fix: bind-mount config/ as a directory, not a single file
Single-file bind mounts pin the container to that file's inode at mount time. sed -i and most editors write-then-rename (atomic write), which swaps in a new inode at the same path -- the container kept reading the orphaned original and never saw edits, silently breaking the hot-reload from the previous commit. Caught by actually testing the reload live instead of trusting the code. Directory mounts resolve paths dynamically and don't have this problem. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+7
-1
@@ -10,7 +10,13 @@ services:
|
|||||||
- SSH_PRIVATE_KEY_PATH=/app/ssh/monitor_ed25519
|
- SSH_PRIVATE_KEY_PATH=/app/ssh/monitor_ed25519
|
||||||
- DISCOVERY_FILE_PATH=/app/data/devices-raw.json
|
- DISCOVERY_FILE_PATH=/app/data/devices-raw.json
|
||||||
volumes:
|
volumes:
|
||||||
- ./config/hosts.yaml:/app/config/hosts.yaml:ro
|
# Directory mount, not a single-file mount: bind-mounting one file pins
|
||||||
|
# the container to that file's inode at mount time. Editors/`sed -i`
|
||||||
|
# that write-then-rename (the common atomic-write pattern) swap in a new
|
||||||
|
# inode at the same path, which the container would never see again
|
||||||
|
# without a restart — silently breaking the hot-reload in issue #14.
|
||||||
|
# Directory mounts resolve paths dynamically and don't have this problem.
|
||||||
|
- ./config:/app/config:ro
|
||||||
- ./ssh/monitor_ed25519:/app/ssh/monitor_ed25519:ro
|
- ./ssh/monitor_ed25519:/app/ssh/monitor_ed25519:ro
|
||||||
# Bind mount (not a named volume) so scripts/discover-devices.sh, which
|
# Bind mount (not a named volume) so scripts/discover-devices.sh, which
|
||||||
# runs on the host via systemd (see deploy/systemd/), can write
|
# runs on the host via systemd (see deploy/systemd/), can write
|
||||||
|
|||||||
@@ -16,3 +16,16 @@ cycle (checks the file's mtime, reloads if changed) — no container restart nee
|
|||||||
|
|
||||||
If the file fails to parse (bad YAML), the error is logged and the **previous**
|
If the file fails to parse (bad YAML), the error is logged and the **previous**
|
||||||
in-memory config keeps running rather than crashing the poller.
|
in-memory config keeps running rather than crashing the poller.
|
||||||
|
|
||||||
|
## Gotcha that broke this on first deploy
|
||||||
|
|
||||||
|
`docker-compose.yml` originally bind-mounted the single file
|
||||||
|
(`./config/hosts.yaml:/app/config/hosts.yaml:ro`). Single-file bind mounts pin the
|
||||||
|
container to that file's **inode** at mount time. `sed -i`, most text editors, and any
|
||||||
|
tool that does an atomic write (write to a temp file, then `rename()` over the
|
||||||
|
original — the common safe-write pattern) swap in a *new* inode at the same path. The
|
||||||
|
container kept reading the original (now-orphaned) inode and never saw edits made this
|
||||||
|
way, no matter how long you waited for the next poll cycle. Fixed by mounting the
|
||||||
|
**directory** instead (`./config:/app/config:ro`), which resolves paths dynamically
|
||||||
|
rather than pinning to a specific inode. Confirmed via `docker exec ... stat` showing a
|
||||||
|
stale mtime that didn't match the host file before this fix.
|
||||||
|
|||||||
Reference in New Issue
Block a user