# Flat-mount overlay — parallel host binds for /data and /data-state. # # Why this overlay # ---------------- # The default deployment topology nests state under data: sdb at /data, # sdc at /data/state (i.e. /data/state is a separate disk mounted INSIDE # the data disk). That layout works but has known fragility: # # - Bind-mount propagation matters. A non-recursive bind hides the # nested mount, leading to silent shadow writes (the failure mode # that caused 2026-05-05 in the Groupon FoundryAI deployment). # # - Two writers, one tree. Host-side timers (tls-rotate.timer) # write to /data/state/certs as root, while the container app # writes to /data/state/system.duckdb as uid 999. Same prefix, # different mount-namespace views = ownership conflicts. # # - sdb resize requires umounting sdc first. Mount-order coupling. # # This overlay removes the nesting by mounting the state disk in # PARALLEL to the data disk: # # sdb at /data (analytics, regenerable) # sdc at /data-state (DuckDB, secrets, certs — irreplaceable) # # Both are direct service-level binds, recursive by default in modern # Docker Engine. No volume options to forget. No nested propagation. # No two-writer collision (app uses /data-state, host scripts also use # /data-state — same path, single namespace). # # Usage # ----- # 1. On the operator's host: mount the config disk at /data-state # (instead of /data/state). Update fstab. Move existing state # contents from /data/state to /data-state. # # 2. In /opt/agnes/.env, set STATE_DIR=/data-state. The app's secrets # module + DuckDB code, plus the host-side rotate.sh and # auto-upgrade.sh scripts, all read this var. # # 3. Compose invocation: # # docker compose \ # -f docker-compose.yml \ # -f docker-compose.prod.yml \ # -f docker-compose.flat-mount.yml \ # up -d # # Note: this overlay is mutually exclusive with docker-compose.host-mount.yml. # Pick one based on your disk topology. # # Do NOT use this overlay in CI — /data and /data-state do not exist # on GitHub runners. services: app: volumes: !override - /data:/data - /data-state:/data-state - ./config:/app/config:ro extract: volumes: !override - /data:/data - /data-state:/data-state - ./config:/app/config:ro scheduler: volumes: !override - /data:/data - /data-state:/data-state - ./config:/app/config:ro telegram-bot: volumes: !override - /data:/data - /data-state:/data-state ws-gateway: volumes: !override - /data:/data - /data-state:/data-state caddy: volumes: !override - ./Caddyfile:/etc/caddy/Caddyfile:ro - /data-state/certs:/certs:ro - caddy_data:/data