fix(deploy): /var/run tmpfs mode 0755 → 1777 so supervisord can write pidfile as UID 1000#581
fix(deploy): /var/run tmpfs mode 0755 → 1777 so supervisord can write pidfile as UID 1000#581enihcam wants to merge 2 commits into
Conversation
…e pidfile as UID 1000 Closes HKUDS#580 Under rootless podman with userns_mode: keep-id and read_only: true, the container's PID 1 runs as the deeptutor user (UID 1000, added by PR HKUDS#577). The compose.yaml mounted /var/run as a tmpfs with mode=0755, owned by root. supervisord's pidfile at /var/run/supervisord.pid could not be written by the non-root process, producing a CRIT on every container start: CRIT could not write pidfile /var/run/supervisord.pid The pidfile is best-effort (children still spawn and reach RUNNING state), but the log noise hides real failures. Switch /var/run to mode=1777 (sticky + world-writable) so PID 1 can create the pidfile. Same shape as /tmp, which has worked cleanly. PocketBase's /var/run (compose.yaml line 82) is left at mode=0755 — it does not run supervisord inside the container, so the pidfile is not written there. Refs: HKUDS#580 (related: HKUDS#576, HKUDS#577)
Move bind mount source from ./data to ${HOME}/.local/share/deeptutor
so the host location follows the XDG_DATA_HOME standard and is
independent of the working directory.
Per-user deployment — not coupled to the repo working tree.
Compose-divergence note: docker-compose.yml still uses ./data. The two
files serve different deployment modes (rootless per-user vs.
daemon-mode shared) and are intentionally divergent.
Migration: existing users with state under ./data will need to move it
to ~/.local/share/deeptutor manually. CONTAINERIZATION.md will be
updated in a follow-up to note the new default.
Refs: HKUDS#580, HKUDS#581
|
Thanks for digging into this — but the root cause is already gone, so this fix is no longer needed. The PR assumes PID 1 runs as UID 1000 via
With root as PID 1, it can write Separately, the second commit moves the data bind mount Closing as superseded by the root-supervisord fix. Appreciate the careful write-up regardless 🙏 |
Summary
One-line fix to
compose.yaml: thedeeptutorservice's/var/runtmpfs entry is changed frommode=0755tomode=1777. Same shape as/tmp, which has worked cleanly.This eliminates a
CRIT could not write pidfile /var/run/supervisord.pidline on every container start when the stack is run under rootless podman withuserns_mode: keep-idandread_only: true.Closes #580
Why
PR #577 made the image drop privileges to a fixed non-root
deeptutoruser (UID 1000) beforeexec gosu deeptutor supervisordin the entrypoint. Withread_only: trueand a tmpfs-backed/var/runatmode=0755(owned by root), PID 1 (UID 1000) can no longer create the supervisord pidfile. The pidfile is best-effort — children still spawn and reachRUNNINGstate — but the CRIT line inpodman compose logs -f deeptutoris noise that hides real failures.PocketBase's
/var/run(compose.yaml line 82) is intentionally left atmode=0755— pocketbase does not run supervisord inside the container, so no pidfile is written there.Reproduction
podman pull ghcr.io/hkuds/deeptutor:latest && podman pull ghcr.io/muchobien/pocketbase:latestcp .env.example .envpodman compose -f compose.yaml up -ddeeptutorandpocketbaseto reachhealthypodman compose -f compose.yaml logs deeptutor | grep -i critCRIT could not write pidfile /var/run/supervisord.pidFix
/var/runis mode 1777 (sticky + world-writable). Sticky is unnecessary here (single user, single process) but matches the/tmpconvention and is harmless.Acceptance criteria
podman compose -f compose.yaml up -dbrings the stack up on rootless podman withuserns_mode: keep-id,read_only: true, and the documented tmpfs paths.podman compose -f compose.yaml logs deeptutor | grep -i critreturns nopidfilelines.podman exec deeptutor ls -la /var/run/supervisord.pidshows the file owned bydeeptutor:deeptutor.healthyin the same time as before./api/v1/foorewrite, PocketBase/api/health,useAuthStatusJSON,/api/v1/auth/status, direct + proxied WebSocket ping/pong) continues to pass.Severity
Cosmetic / log-noise only. Children still spawn and the stack is fully functional — this is a papercut on the deployment story, not a blocker.
Related
Files changed
One commit, one file. No image rebuild needed — the fix is in the deployment config only.