Files
ai-resume/deploy/docker-compose.yml
System agent e6240c1e8e Phase 3: dual bind per Sam's decision (DoD 3 amended, DoD 1/4/8 re-evidenced)
Sam answered the bind question on AUD-133 (2026-10-26):
"A - dual bind: 127.0.0.1:8096 and 192.168.20.13:8096".

- docker-compose: publish 127.0.0.1 and ${APP_LAN_IP:-192.168.20.13}, never 0.0.0.0
- deploy.sh: carry APP_LAN_IP into the release .env, --lan-ip flag, health gate
  now requires /healthz 200 on loopback AND the LAN address
- rehearse.sh: assert both binds, no wildcard, LAN reachability; KEEP_REHEARSAL
  now really keeps the container/image; N3 waits up to 20s instead of 3s
- docs/phase-3-evidence.md: decision recorded, new measured output

DoD: 1, 3 (as amended by Sam), 4, 8 met with recorded output. 2, 5, 6 deferred
on the Phase 2 binary; 7 is Sam's Caddy apply. rehearse.sh 24/24, exit 0.
2026-10-26 17:44:22 +11:00

50 lines
1.8 KiB
YAML

# resume — runtime container (Phase 3 §3.2).
#
# Copied into each release directory by deploy/deploy.sh; the release's .env
# supplies APP_VERSION (the image tag). Never edited on the host — change it
# here, in git, and deploy again.
#
# Limits that are not negotiable (AGENTS.md §4.3):
# mem_limit == memswap_limit == 120m -> the container cannot touch host swap
# ports never 0.0.0.0 -> Caddy on .35 is the only public listener
#
# Published on two explicit addresses and nothing else (Sam, 2026-10-26, on
# AUD-133: "A - dual bind: 127.0.0.1:8096 and 192.168.20.13:8096"):
# 127.0.0.1 -> deploy.sh health gate and local checks on .13
# 192.168.20.13 -> the LAN address Caddy on .35 proxies to (phase doc §3.3)
# A wildcard bind is still forbidden; if APP_LAN_IP is unset the LAN address
# defaults to this host's own 192.168.20.13.
#
# .13 has every default Docker address pool subnetted out (many projects), so a
# single-container service uses the host bridge and publishes its port rather
# than creating a project network. Same pattern as compass-teams-nhs.
name: resume
services:
app:
image: resume/app:${APP_VERSION}
container_name: resume-app
restart: unless-stopped
network_mode: bridge
ports:
- "127.0.0.1:${APP_PORT:-8096}:8096"
- "${APP_LAN_IP:-192.168.20.13}:${APP_PORT:-8096}:8096"
environment:
PORT: "8096"
APP_VERSION: "${APP_VERSION}"
# Mode B values arrive in Phase 5 from ~/.config/environment.d/ — never here.
mem_limit: 120m
memswap_limit: 120m
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8096/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 5s