host-mount: replace named-volume driver_opts with direct service binds
The previous version of docker-compose.host-mount.yml modified the
'data' named volume's driver_opts to point at /data with 'o:
bind,rbind'. Docker named volumes have an immutability footgun:
once a volume is created, its driver options are fixed for the life
of the volume. Editing this file and re-running 'docker compose up
-d' does NOT propagate the new options to existing volumes — they
keep whatever options were in effect at create time.
This bit a deployer (Groupon FoundryAI) on 2026-05-05: the volume
was created before this overlay had bind,rbind, kept the old bind
(non-recursive) propagation, and containers wrote to a shadowed
subdirectory of the parent disk instead of the nested child mount.
DuckDB went FATAL on a root-owned WAL during a routine container
recreate; sign-in broke. Recovery required docker volume rm +
manual data migration on every affected VM.
Direct service-level bind mounts ('/host/path:/container/path')
don't go through Docker's volume layer at all. They re-evaluate
mount options every container start, and modern Docker Engine
(20.10+) defaults to recursive bind for these. No options to
forget, no immutable state to migrate, no shadow-mount class.
Validated via 'docker compose config' merge — overlay correctly
replaces 'data:/data' with bind type:none on app, extract,
scheduler, telegram-bot, ws-gateway.
Compose-spec version note: !override merge tag is part of the
Compose Specification supported by Docker Compose v2.20+. Tested
against Compose v5.1.3 used by Groupon's deployment.
This commit is contained in:
parent
1315f9f93c
commit
655822b953
1 changed files with 67 additions and 17 deletions
|
|
@ -1,14 +1,41 @@
|
||||||
# Bind-mount overlay — replaces the `data` named volume with a bind mount
|
# Bind-mount overlay — replaces the `data` named volume with a direct
|
||||||
# to /data on the host.
|
# host bind mount per service.
|
||||||
#
|
#
|
||||||
# Use this when /data is a persistent disk mounted by the VM startup script,
|
# Why direct service-level bind, not driver_opts on the named volume
|
||||||
# so Agnes data lives on the PD (not on the boot disk's Docker volume).
|
# ------------------------------------------------------------------
|
||||||
|
# The previous version of this file modified the `data` named volume's
|
||||||
|
# `driver_opts` to point at /data with `o: bind,rbind`. Docker named
|
||||||
|
# volumes have an immutability footgun: once a volume is created, its
|
||||||
|
# driver options are fixed for the life of the volume. Editing this
|
||||||
|
# file and re-running `docker compose up -d` does NOT propagate the
|
||||||
|
# new options to existing volumes — they keep whatever options were
|
||||||
|
# in effect at create time.
|
||||||
#
|
#
|
||||||
# `bind,rbind` (recursive bind) is required when the host nests a second
|
# This bit a deployer (Groupon FoundryAI) on 2026-05-05: the volume
|
||||||
# disk under /data — e.g. the dual-disk layout where sdb is mounted on /data
|
# was created before this overlay had `bind,rbind`, kept the old
|
||||||
# and sdc on /data/state. A plain `bind` captures only the top-level mount
|
# `bind` (non-recursive) propagation, and containers wrote to a
|
||||||
# and silently shadows the sub-mount with an empty subdirectory inside the
|
# shadowed subdirectory of the parent disk instead of the nested
|
||||||
# container, causing the app to write to the wrong disk.
|
# child mount. DuckDB went FATAL on a root-owned WAL during a
|
||||||
|
# routine container recreate; sign-in broke.
|
||||||
|
#
|
||||||
|
# Direct service-level bind mounts (`/host/path:/container/path`)
|
||||||
|
# don't go through Docker's volume layer at all. They re-evaluate
|
||||||
|
# the mount options every container start, and modern Docker Engine
|
||||||
|
# (20.10+) defaults to recursive bind for these. No options to
|
||||||
|
# forget, no immutable state to migrate, no shadow-mount class.
|
||||||
|
#
|
||||||
|
# What this overlay does
|
||||||
|
# ----------------------
|
||||||
|
# `volumes: !override` on each service replaces the base
|
||||||
|
# `data:/data` named-volume mount with a direct `/data:/data` host
|
||||||
|
# bind. The named volume `data:` declared at the bottom of
|
||||||
|
# docker-compose.yml is left intact (still useful for local-dev
|
||||||
|
# `compose up` without this overlay) but is no longer referenced
|
||||||
|
# by any service when the overlay is active.
|
||||||
|
#
|
||||||
|
# When the operator's host has a nested mount under /data (e.g. a
|
||||||
|
# separate state disk mounted at /data/state), the recursive bind
|
||||||
|
# carries that nested mount into every container automatically.
|
||||||
#
|
#
|
||||||
# Usage (combined with docker-compose.prod.yml):
|
# Usage (combined with docker-compose.prod.yml):
|
||||||
# docker compose \
|
# docker compose \
|
||||||
|
|
@ -17,11 +44,34 @@
|
||||||
# -f docker-compose.host-mount.yml \
|
# -f docker-compose.host-mount.yml \
|
||||||
# up -d
|
# up -d
|
||||||
#
|
#
|
||||||
# Do NOT use this overlay in CI — /data does not exist on GitHub runners.
|
# Do NOT use this overlay in CI — /data does not exist on GitHub
|
||||||
volumes:
|
# runners.
|
||||||
data:
|
#
|
||||||
driver: local
|
# Compose-spec version requirement: !override merge tag is part of
|
||||||
driver_opts:
|
# the Compose Specification supported by Docker Compose v2.20+ and
|
||||||
type: none
|
# the compose-go library used by Compose v5+. If you need to support
|
||||||
o: bind,rbind
|
# older clients, fork this overlay into per-service files.
|
||||||
device: /data
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
volumes: !override
|
||||||
|
- /data:/data
|
||||||
|
- ./config:/app/config:ro
|
||||||
|
|
||||||
|
extract:
|
||||||
|
volumes: !override
|
||||||
|
- /data:/data
|
||||||
|
- ./config:/app/config:ro
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
volumes: !override
|
||||||
|
- /data:/data
|
||||||
|
- ./config:/app/config:ro
|
||||||
|
|
||||||
|
telegram-bot:
|
||||||
|
volumes: !override
|
||||||
|
- /data:/data
|
||||||
|
|
||||||
|
ws-gateway:
|
||||||
|
volumes: !override
|
||||||
|
- /data:/data
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue