Docker compose for the Whole Stack
docker compose describes your entire system in one file. Postgres, Redis, the order service, the inventory service, the networking between them. One command spins it all up. One command tears it all down. This is how small teams ship to development and staging without spending a week on infra.
services:
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: bookstore
POSTGRES_PASSWORD: bookstore
POSTGRES_DB: bookstore
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U bookstore"]
interval: 5s
retries: 5
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
retries: 5
order-service:
build: ./order-service
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://bookstore:bookstore@db:5432/bookstore
REDIS_URL: redis://redis:6379
JWT_SECRET: replace_me
ports:
- "3000:3000"
inventory-service:
build: ./inventory-service
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://bookstore:bookstore@db:5432/bookstore
REDIS_URL: redis://redis:6379
ports:
- "4000:4000"
volumes:
db_data:Postgres, Redis, and the two services wired together with health checks.
Look at the depends_on blocks. The services do not just wait for the database container to start. They wait for its health check to pass. Postgres takes a couple of seconds to accept connections after the container starts, and without the health check your Node service crashes on startup with connection refused. condition: service_healthy fixes it in one line.
Inside the Compose network, services find each other by name. The order service talks to db and redis, not to an IP address. Docker handles the DNS for you. This is why DATABASE_URL uses @db:5432, not @localhost or an IP. One more moving part that Docker makes boring.
Quiz: Quiz
Loading practiceโฆ