From 09c21d5e55f20797b294df0599e96f4da857e2c5 Mon Sep 17 00:00:00 2001 From: OdooSky v3 Date: Wed, 6 May 2026 13:29:17 +0200 Subject: [PATCH] =?UTF-8?q?feat(chart):=20filestore-chown=20initContainer?= =?UTF-8?q?=20=E2=80=94=20self-heal=20for=20UID=20drift=20on=20every=20pod?= =?UTF-8?q?=20boot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/odoo-deployment.yaml | 70 ++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/templates/odoo-deployment.yaml b/templates/odoo-deployment.yaml index 97447e5..d21786f 100644 --- a/templates/odoo-deployment.yaml +++ b/templates/odoo-deployment.yaml @@ -36,31 +36,61 @@ spec: imagePullSecrets: - name: {{ . }} {{- end }} - # fsGroup=101 makes the kubelet recursively chown the filestore - # PVC's root inode to gid=101 on attach. Odoo runs as uid 101 - # and writes /var/lib/odoo/sessions on first request; without - # this it crashes "Permission denied: '/var/lib/odoo/sessions'" - # on the first hit because Longhorn-formatted PVCs come up - # owned by root:root. (k3s local-path masked this — its hostPath - # provisioner left the dir world-writable. Real CSI drivers - # don't.) supplementalGroups + runAsUser kept default so the - # rest of the pod (db-init, addon init containers) keeps the - # behavior they already had. + # fsGroup=101 makes the kubelet recursively chgrp the filestore + # PVC's root inode to gid=101 on attach. The Odoo user is in + # group 101 (`odoo`) so it inherits group access to the volume. + # + # NOTE: fsGroup ONLY changes group, never owner UID. If a helper + # job (Tower's checkpoint, spawn-seed, import) ever wrote files + # as a different UID, fsGroup wouldn't fix that. The + # filestore-chown initContainer below is what closes the gap — + # it's the single source of truth for "files in /var/lib/odoo + # are owned by 100:101 with mode g+rwX before Odoo runs." securityContext: fsGroup: 101 - # OnRootMismatch: only recursive-chown when the volume root - # ISN'T already gid=101. Saves O(filestore-size) chmod cost - # on every pod restart for instances with millions of files. - # Defaults work for fresh PVCs (root != 101 → chown once). fsGroupChangePolicy: OnRootMismatch # 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. + # run when there are addons. We always need filestore-chown + + # db-init to ensure the filestore is writable + the tenant DB + # exists + base module is initialized before Odoo's main process + # starts serving — without these the operator would either hit + # Permission denied on first attachment write (filestore-chown + # fixes that) or have to click through Odoo's setup wizard + # manually for every new instance (db-init fixes that). initContainers: + # filestore-chown: load-bearing self-heal. Runs as root, chowns + # /var/lib/odoo to 100:101 (the Odoo runtime user inside the + # official Odoo image: uid 100, gid 101) and chmods g+rwX. + # Idempotent — runs on every pod boot. + # + # Why this exists: Tower's clone helpers (checkpoint Job, + # spawn-seed Job, import Job) used to chown to 101:101 (uid + # 101 doesn't even exist as a user — that's the gid). Files + # ended up owned by a non-existent UID, group=odoo. mode 0755 + # gave the running Odoo (uid 100) only group r-x — install + # operations failed with "Permission denied: mkdir + # /var/lib/odoo/filestore//" inside Odoo's + # mail.data load. This initContainer fixes ownership-drift + # regardless of what wrote the files. Defence in depth. + - name: filestore-chown + image: {{ include "instance.odooImage" . | quote }} + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "-c"] + args: + - | + set -eu + # uid 100 = odoo, gid 101 = odoo group (per the Odoo + # base image's /etc/passwd + /etc/group). Hardcoded + # because the chart targets that specific image. + chown -R 100:101 /var/lib/odoo + chmod -R u+rwX,g+rwX /var/lib/odoo + echo "filestore ownership: $(stat -c '%u:%g %a' /var/lib/odoo)" + securityContext: + runAsUser: 0 + runAsGroup: 0 + volumeMounts: + - name: filestore + mountPath: /var/lib/odoo # db-init: idempotent on every pod boot. # 1. createdb if missing (PG-level) # 2. odoo -i base --stop-after-init to install base module