fix(docker): pin service UIDs and repair volume ownership on upgrade - #333
Open
chrip wants to merge 1 commit into
Open
fix(docker): pin service UIDs and repair volume ownership on upgrade#333chrip wants to merge 1 commit into
chrip wants to merge 1 commit into
Conversation
Upgrading the standalone image from v9.3.2 to v9.3.3 with an existing Postgres volume puts the container in a restart loop: Error: Config owner (postgres:102) and data owner (rabbitmq:103) do not match, and config owner is not root The service accounts get their UIDs allocated by the package installs, in package-configuration order, so the package set decides them. Adding --no-install-recommends in v9.3.3 dropped dbus (`messagebus`) from that layer and everything after it slid down one: v9.3.2: messagebus 101 redis 102 postgres 103 rabbitmq 104 ds 105 v9.3.3: redis 101 postgres 102 rabbitmq 103 messagebus 104 ds 105 A datadir written by v9.3.2 is therefore owned by a UID that resolves to `rabbitmq` in v9.3.3, postgresql-common refuses to start on the mismatch, and the entrypoint dies under `set -e` before nginx. `ds` kept 105 only because messagebus moved from ahead of postgres to behind it, so the document volume escaped by coincidence, not by design. Three parts: - entrypoint.sh chowns the state directories it owns when, and only when, the current owner differs, before starting anything. This is what rescues volumes that already exist, and it also covers a bind mount arriving owned by something else. $DATA_DIR/.private stays root-owned, since the recursive chown would otherwise hand the persisted secrets to ds. - The Dockerfile pins the UIDs/GIDs ahead of the installs, so a future packaging change cannot renumber them again. The pinned values are the ones v9.3.3 already shipped, which makes this a no-op for volumes written by v9.3.3 or later; adduser/useradd in the package postinsts (and the .deb's own, for `ds`) are no-ops when the account exists. - A new build.yml job boots the last released image against persistent volumes and then boots the image built here on the same volumes, asserting a row seeded before the upgrade is still readable after it. The e2e job only ever sees empty volumes, which is why this shipped green. Skipped on tag pushes, where :latest is already the image under test. Fixes #314 Assisted-by: ClaudeCode:claude-opus-5 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upgrading the standalone image from v9.3.2 to v9.3.3 with an existing Postgres volume puts the container in a restart loop:
Error: Config owner (postgres:102) and data owner (rabbitmq:103) do not
match, and config owner is not root
The service accounts get their UIDs allocated by the package installs, in package-configuration order, so the package set decides them. Adding --no-install-recommends in v9.3.3 dropped dbus (
messagebus) from that layer and everything after it slid down one:v9.3.2: messagebus 101 redis 102 postgres 103 rabbitmq 104 ds 105
v9.3.3: redis 101 postgres 102 rabbitmq 103 messagebus 104 ds 105
A datadir written by v9.3.2 is therefore owned by a UID that resolves to
rabbitmqin v9.3.3, postgresql-common refuses to start on the mismatch, and the entrypoint dies underset -ebefore nginx.dskept 105 only because messagebus moved from ahead of postgres to behind it, so the document volume escaped by coincidence, not by design.Three parts:
entrypoint.sh chowns the state directories it owns when, and only when, the current owner differs, before starting anything. This is what rescues volumes that already exist, and it also covers a bind mount arriving owned by something else. $DATA_DIR/.private stays root-owned, since the recursive chown would otherwise hand the persisted secrets to ds.
The Dockerfile pins the UIDs/GIDs ahead of the installs, so a future packaging change cannot renumber them again. The pinned values are the ones v9.3.3 already shipped, which makes this a no-op for volumes written by v9.3.3 or later; adduser/useradd in the package postinsts (and the .deb's own, for
ds) are no-ops when the account exists.A new build.yml job boots the last released image against persistent volumes and then boots the image built here on the same volumes, asserting a row seeded before the upgrade is still readable after it. The e2e job only ever sees empty volumes, which is why this shipped green. Skipped on tag pushes, where :latest is already the image under test.
Fixes #314
Assisted-by: ClaudeCode:claude-opus-5