BlogCI/CD

Docker Compose in production: the parts that bite

Restart policies, health-gated dependencies, resource caps, and secrets — what to fix before Compose meets real traffic.

Jul 2, 2024·9 min readIntermediate

Docker Compose is wonderful on a laptop and unforgiving in production, because the defaults assume you are watching. A handful of settings — restart policy, health-gated dependencies, resource caps, and real secrets — separate a demo compose file from one that survives a reboot and a traffic spike.

A production-shaped service

compose.yaml
services:
api:
image: acme/api:1.4
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
interval: 15s
retries: 3
deploy:
resources:
limits: { cpus: "1.0", memory: 512M }
depends_on:
db: { condition: service_healthy }

Wait for healthy, not just started

Plain depends_on only waits for the container to start, not to be ready — so your API races the database on boot. condition: service_healthy fixes that by gating on the dependency's healthcheck.

Secrets are not environment variables
Values in environment: land in docker inspect, image history, and every child process. Use Compose secrets (files mounted at /run/secrets) or an external secrets manager instead.

Cap resources so one service cannot sink the host

Without limits, a memory leak in one container takes down everything on the box. deploy.resources.limits gives each service a ceiling — the same discipline as Kubernetes requests and limits.

Go deeper in a courseDocker in depthCompose, networking, storage, and running containers in production.View course

Related posts