Docker Compose Is Documentation That Actually Runs
Jenkins
Source: Dev.to | Jan 28, 2026 (UTC)
Two projects. Both have Dockerfiles. One takes me 20 minutes to figure out how to run. The other – 30 seconds.
The difference? The second one has a docker-compose.yml.
That file told me everything: what ports to expose, what services it depends on, what environment variables it needs, what volumes to mount. The Dockerfile only told me how to build.
Compose isn’t just a convenience tool. It’s executable documentation.
The “I’ll Just Remember It” Trap
A year ago I was debugging a service that hadn’t been touched in months. The Dockerfile was there. Clean, multi-stage, optimized. Professional.
No Compose file. Just a Dockerfile and a README that said “see Dockerfile.”
How do I run it?
docker build -t myservice . docker run myservice
Enter fullscreen mode
Exit fullscreen mode
Container crashes. Missing environment variables. Okay, which ones?
I open config/config.go. There’s a struct with 15 fields loaded via envconfig. Three have defaults. The rest? Required, apparently. The README mentions DATABASE_URL and that’s it – the rest are “obvious.”
I check git history. Find a Slack message from six months ago:
“run it with -e DATABASE_URL=... -e REDIS_URL=... -e SECRET_KEY=... -v $(pwd)/config:/app/config -p 8080:8080 --network=backend“
No Slack archeology. No guessing. The documentation is the code.
The “But I Only Have One Container” Argument
People say: “I don’t need Compose, I only have one service.”
I disagree. Here’s why.
Reason 1: You’ll forget.
docker run commands grow. First it’s just -p 3000:3000. Then you add a volume. Then environment variables. Then a network. Six months later you have a 200-character command and zero memory of why each flag is there.
When someone changes the configuration, I see it in the PR. Clear diff. Clear history. With shell commands? Good luck tracking what changed.
The Things That Bit Me
depends_on Lies to You
I wrote this and expected it to work:
services: db: image: postgres:15 app: build: . depends_on: - db
Enter fullscreen mode
Exit fullscreen mode
App crashed on startup. “Connection refused.”
depends_on doesn’t wait for the service to be ready. It waits for the container to start. Postgres takes a few seconds to initialize. My app tried to connect immediately. Boom.
Now Compose actually waits until Postgres responds to connections.
I’ve seen production deployments break because of this. People blame Docker. It’s not Docker’s fault – depends_on just doesn’t do what you think it does. (docs)
Now it’s called projectname_node_modules. Searchable. Deletable. Manageable.
The Override File Nobody Reads About
Compose automatically merges docker-compose.override.yml if it exists (docs). No flags needed. Same with .env – it loads automatically, no env_file directive required (docs).
docker compose up # just app docker compose --profile dev up # app + db + redis docker compose --profile monitoring up # app + prometheus + grafana docker compose --profile dev --profile monitoring up # combine profiles
Залишити відповідь