chart: db-init initContainer (auto-create tenant DB + base init) + pin -d <code>

This commit is contained in:
2026-04-27 11:55:36 +00:00
parent 32869f74e8
commit f46e453ed0

View File

@@ -28,6 +28,65 @@ spec:
# values.yaml would leave the existing pod alone.
odoosky.io/addons-hash: {{ .Values.addons | toJson | sha256sum | trunc 16 }}
spec:
# Bootstrap initContainers always run; addon initContainers only
# run when there are addons. We always need db-init to ensure the
# tenant DB exists + base module is initialized before Odoo's
# main process starts serving — without this the operator would
# have to click through Odoo's setup wizard manually for every
# new instance, which is exactly the SaaS UX v3 sets out to
# eliminate.
initContainers:
# db-init: idempotent on every pod boot.
# 1. createdb if missing (PG-level)
# 2. odoo -i base --stop-after-init to install base module
# and create Odoo's tables. After base is installed,
# `-i base` is a no-op so subsequent boots add ~5s.
- name: db-init
image: "{{ .Values.odoo.image }}:{{ .Values.odoo.tag }}"
imagePullPolicy: IfNotPresent
# Override the official Odoo entrypoint so we can run psql
# before odoo. The image ships with postgresql-client, so
# createdb is on PATH.
command: ["/bin/sh", "-c"]
args:
- |
set -eu
DBNAME="{{ .Values.instance.code }}"
echo "── ensuring database $DBNAME exists ──"
# Wait for PG to accept connections (max 60s)
for i in $(seq 1 30); do
if PGPASSWORD="$PASSWORD" psql -h "$HOST" -p "$PORT" -U "$USER" -d postgres -c '\q' 2>/dev/null; then break; fi
echo "(waiting for postgres, $i/30)"
sleep 2
done
# createdb is idempotent if we wrap with an existence check.
if PGPASSWORD="$PASSWORD" psql -h "$HOST" -p "$PORT" -U "$USER" -d postgres -tAc \
"SELECT 1 FROM pg_database WHERE datname = '$DBNAME'" | grep -q 1; then
echo "(database $DBNAME already exists)"
else
echo "── creating database $DBNAME ──"
PGPASSWORD="$PASSWORD" createdb -h "$HOST" -p "$PORT" -U "$USER" "$DBNAME"
fi
echo "── initializing base module (no-op if already installed) ──"
odoo -i base -d "$DBNAME" --stop-after-init --without-demo=all --no-http \
--db_host="$HOST" --db_port="$PORT" --db_user="$USER" --db_password="$PASSWORD" \
--workers=0
echo "── db-init done ──"
env:
- name: HOST
value: {{ include "instance.fullname" . }}-pg
- name: PORT
value: "5432"
- name: USER
valueFrom:
secretKeyRef:
name: {{ include "instance.fullname" . }}-pg
key: POSTGRES_USER
- name: PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "instance.fullname" . }}-pg
key: POSTGRES_PASSWORD
{{- if .Values.addons }}
# One initContainer per selected addon. Each addon image's
# ENTRYPOINT/CMD copies its bundled content into /target/<code>,
@@ -43,7 +102,6 @@ spec:
# new content. Always forces a manifest fetch on each pod
# start; layers themselves are still cached so the pull is
# cheap (~50 ms when content is unchanged, fresh otherwise).
initContainers:
{{- range $i, $a := .Values.addons }}
- name: addon-{{ $a.code | replace "_" "-" | lower }}
image: {{ $a.image }}:{{ $a.version }}
@@ -57,14 +115,16 @@ spec:
- name: odoo
image: "{{ .Values.odoo.image }}:{{ .Values.odoo.tag }}"
imagePullPolicy: IfNotPresent
{{- if .Values.addons }}
# Pass --addons-path explicitly so the official Odoo image's
# entrypoint appends our extra-addons dir to the default
# addons_path. Args after the entrypoint that start with --
# are passed through to `odoo` directly. We list our path
# AFTER the default so built-in modules still take priority
# on name collisions.
# Pin the active database to our tenant code. Without this
# Odoo runs in multi-DB mode and exposes /web/database/manager;
# for the SaaS UX we want one instance == one DB and never
# show the manager. db-init has already created and bootstrapped
# this DB, so Odoo opens it cleanly.
args:
- "-d"
- "{{ .Values.instance.code }}"
- "--db-filter=^{{ .Values.instance.code }}$"
{{- if .Values.addons }}
- "--addons-path=/usr/lib/python3/dist-packages/odoo/addons,{{ .Values.addonsMountPath }}"
{{- end }}
ports: