A running process is not necessarily ready to serve traffic. Compose can use container health checks and dependency conditions to prevent an application from starting before its database is ready. Restart policies then handle process exits, not application readiness.
1. Create a health-aware stack
mkdir -p ~/compose-health-demo && cd ~/compose-health-demo
cat > compose.yaml <<'EOF'
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: local-demo-only
POSTGRES_DB: app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d app"]
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
restart: unless-stopped
api:
image: nginx:1.28-alpine
depends_on:
db:
condition: service_healthy
restart: true
ports:
- "127.0.0.1:8080:80"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1/ >/dev/null || exit 1"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s
restart: unless-stopped
EOF
The password is intentionally local-only; use a Compose secret for real deployments.
2. Validate and observe startup order
docker compose config --quiet
docker compose up -d --wait --wait-timeout 90
docker compose ps
curl -I http://127.0.0.1:8080
Inspect the detailed health state and recent probe output:
docker inspect compose-health-demo-db-1
--format '{{json .State.Health}}' | jq
docker inspect compose-health-demo-api-1
--format 'Status={{.State.Status}} Health={{.State.Health.Status}} Restarts={{.RestartCount}}'
3. Watch health events
docker events --filter event=health_status --since 10m
Run that command in a separate terminal and use Ctrl+C when finished.
4. Simulate a database failure
docker compose kill db
docker compose ps
sleep 10
docker compose ps
docker inspect compose-health-demo-db-1 --format 'Restarts={{.RestartCount}} Status={{.State.Status}}'
unless-stopped restarts a container after an unexpected exit. It does not restart a process merely because a health check reports unhealthy; monitoring must alert or an external controller must remediate that state.
5. Diagnose unhealthy services
docker compose ps
docker compose logs --tail 100 db api
docker inspect compose-health-demo-db-1 --format '{{range .State.Health.Log}}{{.End}} exit={{.ExitCode}} {{.Output}}{{println}}{{end}}'
docker compose exec db pg_isready -U postgres -d app
6. Apply a health-check change
docker compose config --quiet
docker compose up -d --force-recreate api
docker compose up -d --wait --wait-timeout 90
7. Clean up
docker compose down --volumes
Design guidance
- A health command should test the actual service, not only that a process exists.
- Keep probes fast and deterministic.
- Use
start_periodfor legitimate initialization time. - Set timeouts and retries according to measured behavior.
- Use dependency conditions for startup order, but make applications resilient to later dependency loss.
References: Docker documentation and the Server World topic index.