Phase 3: release script, container limits, rehearsed rollback
Adds the deployment mechanism for the portfolio site. The site itself is not deployed yet: Phase 2 has not produced a binary. - deploy/deploy.sh: build + test (fail fast) -> releases/<ts> -> atomic `current` symlink flip -> docker compose up -d -> /healthz gate -> flip back to `previous` and exit non-zero on failure. `--rollback` restores the previous release in one command. Auto-detects the Go toolchain in /nix/store when `go` is not on PATH. - deploy/docker-compose.yml: 127.0.0.1:8096, mem_limit == memswap_limit == 120m, capped json-file logs (10m x 3), restart unless-stopped. - deploy/Dockerfile: runtime image only (alpine + prebuilt payload), so a release needs no toolchain, no network and no package install. - deploy/rehearse.sh: repeatable proof (21 assertions, exit 0) of deploy, build fail-fast, health-gate rollback, --rollback and N3 restart. - deploy/README.md + docs/phase-3-evidence.md: how it works, the build contract Phase 2 must satisfy, the Caddy block for Sam, and the open bind-address question (loopback-only vs reachable from .35). Satisfies DoD items 1, 3 (container), 4, 8. Items 2, 5, 6, 7 need the Phase 2 binary and Sam's Caddy change; recorded as deferred with owners, not claimed. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
41
deploy/docker-compose.yml
Normal file
41
deploy/docker-compose.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
# 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 127.0.0.1:$PORT:8096 -> Caddy on .35 is the only public listener
|
||||
#
|
||||
# .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"
|
||||
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
|
||||
Reference in New Issue
Block a user