Why
The Docker 4 bootcamp session (9 Jul 2026, slides-devops-bootcamp → outlines/2026/docker4.md) teaches Docker Compose by reusing this arena as the subject: learners collapse the Docker 3 manual docker network create + three flag-heavy docker runs into one compose.yaml → docker compose up. That's the whole payoff of the session.
The slides author the compose block content verbatim from this repo (same rule as the pinned docker run block in CLAUDE.md). So the canonical compose.yaml must live here, be part of the pinned contract, and be e2e-proven before the deck is authored — otherwise the in-class build is unverified.
This repo currently has no compose.yaml — the "Remaining" list in CLAUDE.md even notes compose is Docker 4's job. This issue is that job.
Task
-
Add compose.yaml (Compose v2 spec — file named compose.yaml, no version: key) that reproduces the pinned local arena from CLAUDE.md. Target shape (keep it minimal + beginner-legible — only the keys the slides teach):
services:
profile:
image: redis
volumes:
- me:/data
server:
image: ghcr.io/infratify/arena-server
avatar:
image: ghcr.io/infratify/arena-avatar
ports:
- "8080:8080"
environment:
COLOR: cyan
SERVER: server:3000
depends_on:
- profile
- server
volumes:
me:
- Do NOT declare an explicit
networks: block. Compose auto-creates a project network and services resolve each other by service name (server:3000, redis host profile). That elimination is the teaching payoff — keep it automatic.
- Only the taught keys:
image, ports, environment, volumes, depends_on + top-level volumes:. No build:, restart:, extra networks, etc.
-
CRITICAL — resolve the startup race. depends_on waits for the profile/server containers to start, not to be ready. Verify the avatar does not fail when redis isn't yet accepting connections on docker compose up:
- If the avatar's redis client already retries →
depends_on alone is fine, document that.
- If it races/fails → add the minimal fix (a
healthcheck on profile + depends_on: { profile: { condition: service_healthy } }, or app-side retry). Prefer whatever keeps the slide YAML simplest; a healthcheck is acceptable and the slides mention it as one-line "production pattern" awareness.
-
e2e test. Extend scripts/e2e.sh (or add scripts/e2e-compose.sh) to prove, via compose:
docker compose up -d brings up all three; avatar reaches server + profile by name.
localhost:8080 serves the avatar client; a join shows on the server roster.
- Volume survives
docker compose down → up (character/name persists in volume me — the redis SAVE-on-write path from CLAUDE.md).
-
Pin it to the contract. Add the compose.yaml to the pinned student-facing contract block in CLAUDE.md (the section the slides copy verbatim) and note the breakout override: to join the shared class arena, learners change environment: SERVER: "<instructor-ip>:3000" (external host → IP + port, the reused -p concept) + a team COLOR. Keep the contract stable (renames = breaking changes for the slides).
Acceptance
Context / cross-refs
- Pinned
docker run contract + single-host truth + redis SAVE note: this repo's CLAUDE.md.
- Docker 4 outline (how the slides use this):
slides-devops-bootcamp → outlines/2026/docker4.md (LO1 shows each service/key as a labeled block mapped to its Docker 3 flag; LO2 arranges the blocks in-class; breakout deploys the whole arena to the learner's own EC2).
Why
The Docker 4 bootcamp session (9 Jul 2026,
slides-devops-bootcamp→outlines/2026/docker4.md) teaches Docker Compose by reusing this arena as the subject: learners collapse the Docker 3 manualdocker network create+ three flag-heavydocker runs into onecompose.yaml→docker compose up. That's the whole payoff of the session.The slides author the compose block content verbatim from this repo (same rule as the pinned
docker runblock inCLAUDE.md). So the canonicalcompose.yamlmust live here, be part of the pinned contract, and be e2e-proven before the deck is authored — otherwise the in-class build is unverified.Task
Add
compose.yaml(Compose v2 spec — file namedcompose.yaml, noversion:key) that reproduces the pinned local arena fromCLAUDE.md. Target shape (keep it minimal + beginner-legible — only the keys the slides teach):networks:block. Compose auto-creates a project network and services resolve each other by service name (server:3000, redis hostprofile). That elimination is the teaching payoff — keep it automatic.image,ports,environment,volumes,depends_on+ top-levelvolumes:. Nobuild:,restart:, extra networks, etc.CRITICAL — resolve the startup race.
depends_onwaits for the profile/server containers to start, not to be ready. Verify the avatar does not fail when redis isn't yet accepting connections ondocker compose up:depends_onalone is fine, document that.healthcheckonprofile+depends_on: { profile: { condition: service_healthy } }, or app-side retry). Prefer whatever keeps the slide YAML simplest; ahealthcheckis acceptable and the slides mention it as one-line "production pattern" awareness.e2e test. Extend
scripts/e2e.sh(or addscripts/e2e-compose.sh) to prove, via compose:docker compose up -dbrings up all three; avatar reachesserver+profileby name.localhost:8080serves the avatar client; a join shows on the server roster.docker compose down→up(character/name persists in volumeme— the redisSAVE-on-write path fromCLAUDE.md).Pin it to the contract. Add the
compose.yamlto the pinned student-facing contract block inCLAUDE.md(the section the slides copy verbatim) and note the breakout override: to join the shared class arena, learners changeenvironment: SERVER: "<instructor-ip>:3000"(external host → IP + port, the reused-pconcept) + a teamCOLOR. Keep the contract stable (renames = breaking changes for the slides).Acceptance
compose.yamlpresent, Compose v2, no explicit network, minimal taught keys onlydocker compose up -dreliably brings up the full arena (startup race resolved + documented)compose.yamladded to the pinned contract inCLAUDE.md+ breakoutSERVERoverride documentedContext / cross-refs
docker runcontract + single-host truth + redisSAVEnote: this repo'sCLAUDE.md.slides-devops-bootcamp→outlines/2026/docker4.md(LO1 shows each service/key as a labeled block mapped to its Docker 3 flag; LO2 arranges the blocks in-class; breakout deploys the whole arena to the learner's own EC2).