# Container image strategy ## Images | Image | Built from | Registry path | |---|---|---| | `rootnode/platform-api` | `platform/api/Dockerfile` | `{{ registry }}/rootnode/platform-api` | | `rootnode/gateway` | `platform/gateway/Dockerfile` | `{{ registry }}/rootnode/gateway` | | `rootnode/provisioner` | `platform/provisioner/Dockerfile` | `{{ registry }}/rootnode/provisioner` | | `rootnode/egress-proxy` | `platform/egress-proxy/Dockerfile` | `{{ registry }}/rootnode/egress-proxy` | | `rootnode/lab-router` | `platform/lab-router/Dockerfile` (Phase 4.1) | `{{ registry }}/rootnode/lab-router` | | `rootnode/lab` | root `Dockerfile` (the student Lab image) | `{{ registry }}/rootnode/lab` | ## Tagging **Never `:latest` in staging or production.** Every build is tagged with: - the full git SHA (`sha-<40 hex>`) — always, every build, the ground truth - `staging-` on every push to `main` that passes CI (moving pointer, staging only) - a semantic tag (`vX.Y.Z`) only on an explicit, human-triggered production release `infra/scripts/ci/tag-and-push.sh` implements this — see §18 in `docs/PHASE4_PRODUCTION_INFRASTRUCTURE.md`. Deployment configs (`infra/environments/*/​*.env.template`, Ansible `group_vars`) reference the tag as a variable (`image_tag`), never a hardcoded value baked into a compose file — rolling back is changing one variable and re-running the `platform`/`lab-host` Ansible role, not editing a compose file by hand (see `docs/RUNBOOK_ROLLBACK.md`). ## Registry No paid registry required. Two supported options, chosen at deploy time via `registry` in `infra/ansible/group_vars/production.yml`: 1. **Gitea's own built-in container registry** (`git.synthossystems.com`) — zero new infrastructure, already authenticated the same way the repo itself is. Preferred default. 2. **A self-hosted registry** (e.g. a `registry:2` container on rn-platform-01 itself, or elsewhere in the homelab) — a documented fallback if the Gitea registry isn't enabled on this instance. Either way: private registry, credentials pulled the same way any other production secret is (`docs/PRODUCTION_DEPLOYMENT.md` §10), never a public Docker Hub push of anything beyond what's already public (this project doesn't publish anything to Docker Hub in Phase 4). ## Rollback Every image is content-addressable by SHA tag, so "roll back" is always available as long as the previous tag hasn't been garbage-collected from the registry — see `docs/RUNBOOK_ROLLBACK.md` for the exact procedure (re-point `image_tag`, re-run the Ansible role, verify).