Docker Compose in Depth
๐งญ Docker Compose in Depth
docker1's Compose chapter (docker_10) covered running a multi-container app. This chapter covers the features that turn a working Compose setup into a production-ready one: environment-specific config, optional services, real readiness checks, and predictable networking.
Override Files for Environment-Specific Config
Rather than duplicating an entire docker-compose.yml per environment, Compose merges a base file with an override file โ docker-compose.override.yml is picked up automatically, or explicit files can be layered with -f.
Profiles
The profiles key marks a service as optional โ it only starts when its profile is explicitly activated, keeping services like a debug tool or a one-off seed job out of the way during normal up runs.
Healthchecks
A container can be running while the application inside it hasn't actually finished starting up โ a healthcheck block tells Docker how to verify genuine readiness, not just process liveness.
depends_on With Conditions
Plain depends_on: [db] only waits for the db container to start โ not for MySQL inside it to actually be accepting connections. This is one of Compose's most common real bugs: an app container starts, tries to connect to a database that's technically running but not yet ready, and crashes.
depends_on Without vs. With a Condition
Plain depends_on
Waits only for the db container process to start โ the app can still connect before MySQL is ready, and crash.
depends_on with service_healthy
Waits for the healthcheck (this chapter's mysqladmin ping) to actually pass first โ the app only starts once the database is genuinely ready.
Explicitly Named Networks & Volumes
By default, Compose auto-generates network/volume names prefixed with the project directory name. Giving them explicit names makes them predictable to reference from outside Compose, or to share deliberately across multiple Compose files/projects.
| Feature | Purpose |
|---|---|
| Override files | Layer environment-specific config on a shared base, without duplicating the whole file |
profiles | Keep optional services out of normal up runs |
healthcheck | Distinguish "running" from actually ready |
depends_on: condition: service_healthy | Wait for real readiness, not just container start |
| Named networks/volumes | Predictable references outside Compose or across projects |
๐ป Coding Challenges
Challenge 1: Add a Healthcheck
Write a healthcheck block for a Redis service (image redis:7) that runs redis-cli ping every 5 seconds, allowing up to 5 retries.
Goal: Practice writing a healthcheck's test/interval/retries fields for a real service.
Challenge 2: Fix a depends_on Race Condition
A team's api service has depends_on: [db] and intermittently crashes on startup with a "connection refused" error against the database. Diagnose the cause and fix the Compose file.
Goal: Practice recognizing and fixing the classic depends_on-without-a-condition race condition.
Challenge 3: Design an Optional Debug Service
Add a service called adminer (a database admin UI) to a Compose file such that it never starts during a normal docker compose up, but can be started deliberately when needed.
Goal: Practice using profiles to keep an optional tool out of the default startup path.
It's easy to assume an override file always merges additively with the base file โ but that's not uniformly true. Keys like environment genuinely merge (the override's variables are added to/override individual keys from the base). Keys like command or entrypoint, however, typically replace the base's value entirely rather than merging with it โ an override file that only intended to tweak one argument can silently discard the base's entire command if it redefines that key at all. Always check Compose's documented merge behavior for the specific key being overridden, rather than assuming every override is purely additive.
๐ฏ What's Next
The next chapter is Container Networking Beyond Basics โ bridge vs. host vs. overlay networks, custom networks for service isolation, and DNS-based service discovery between containers.