mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
fix(docker): normalise data-volume ownership at startup via gosu entrypoint
Two related failure modes have been biting Docker users repeatedly, most recently in #1211: 1. Docker named volumes are created by the daemon as root:root, and the previous `chmod 777 /app/data` Dockerfile workaround only covered the named-volume root — so subdirs Bambuddy creates at runtime (virtual_printer/uploads, virtual_printer/certs, etc.) inherited wrong ownership when the container ran as 1000:1000. 2. The shipped docker-compose.yml ships `./virtual_printer:/app/data/virtual_printer` uncommented, and dockerd creates a missing bind-mount source on the host as root before the container starts — leaving the host directory unwritable by uid 1000 inside the container even though the named volume above it had the chmod-777 workaround. Symptom either way: [Errno 13] Permission denied: '/app/data/virtual_printer/uploads', no virtual printer ever starts, "VP doesn't work" support reports follow. Replace the chmod-777 hack with a proper entrypoint: - deploy/docker-entrypoint.sh runs as root, chowns /app/data and /app/logs (and /app/data/virtual_printer when bind-mounted) to PUID:PGID, then drops to that uid via gosu before exec'ing the app. The chown is gated behind a top-level ownership check so subsequent restarts skip the recursive traversal — no multi- second startup penalty on multi-GB archive directories. - A sentinel .bambuddy file in each data path prevents Docker from re-syncing image directory metadata on every mount (otherwise empty volumes have their ownership reverted from the image on each restart, defeating the idempotency). - When the container is started with an explicit `user:` directive or `--user` flag the entrypoint detects it isn't root and falls through to direct exec — preserving compatibility for users who pin a specific uid. Compose template changes: - Remove `user: "${PUID:-1000}:${PGID:-1000}"` (entrypoint owns privilege drop now). - Add PUID / PGID env vars with the same defaults. - Comment out the ./virtual_printer:/app/data/virtual_printer bind mount by default, with explicit "only needed if you also run a native install of Bambuddy on the same host and want both to share the VP CA cert" guidance. The entrypoint chowns the host-side dir through the bind mount the first time it sees wrong ownership, so existing uncomented installs continue to work and #1211 specifically gets fixed.
This commit is contained in:
+25
-3
@@ -24,6 +24,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ffmpeg \
|
||||
gnupg \
|
||||
gosu \
|
||||
iproute2 \
|
||||
libcap2-bin \
|
||||
openssh-client \
|
||||
@@ -66,9 +67,29 @@ COPY .git/HEAD ./.git/HEAD
|
||||
# Copy built frontend from builder stage
|
||||
COPY --from=frontend-builder /app/static ./static
|
||||
|
||||
# Create data directory for persistent storage
|
||||
# chmod 777 allows running as non-root user (e.g., with docker compose user: directive)
|
||||
RUN mkdir -p /app/data /app/logs && chmod 777 /app/data /app/logs
|
||||
# Create data directories. Ownership is normalised at startup by the
|
||||
# entrypoint (chowns to PUID:PGID and drops privileges via gosu before
|
||||
# exec'ing the app), so we don't need a chmod 777 hack here — that was
|
||||
# the workaround for the previous compose `user: "1000:1000"` model and
|
||||
# only worked when the volume's perms happened to survive (named volume
|
||||
# first-create case; bind-mount-source case bit users in #1211 / #668).
|
||||
#
|
||||
# The sentinel file is needed so a freshly-created Docker named volume
|
||||
# isn't "empty" from Docker's POV. On empty volumes Docker resyncs the
|
||||
# directory metadata (incl. ownership) from the image on every mount,
|
||||
# which would mean our entrypoint chown gets reverted on every restart
|
||||
# and re-fired on every start (slow on multi-GB archive dirs). With a
|
||||
# sentinel inside the volume on first mount, Docker considers the
|
||||
# volume populated and stops resyncing, so the chown is genuinely
|
||||
# one-shot.
|
||||
RUN mkdir -p /app/data /app/logs && \
|
||||
: >/app/data/.bambuddy && \
|
||||
: >/app/logs/.bambuddy
|
||||
|
||||
# Entrypoint script: handles PUID/PGID + ownership normalisation +
|
||||
# privilege drop. See deploy/docker-entrypoint.sh for the full rationale.
|
||||
COPY deploy/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||
|
||||
# Environment variables
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
@@ -103,4 +124,5 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||
# Run the application
|
||||
# Use standard asyncio loop (uvloop has permission issues in some Docker environments)
|
||||
# Port is configurable via PORT environment variable (default: 8000)
|
||||
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||
CMD ["sh", "-c", "uvicorn backend.app.main:app --host 0.0.0.0 --port ${PORT:-8000} --loop asyncio"]
|
||||
|
||||
Reference in New Issue
Block a user