Docker Compose & Networking
docker-compose.yml Structure
services:
app:
build:
context: .
dockerfile: Dockerfile
target: runner # multi-stage target
args:
BUILD_VERSION: "1.0"
image: myapp:latest
container_name: myapp
restart: unless-stopped # no | always | on-failure | unless-stopped
ports:
- "3000:3000" # host:container
environment:
NODE_ENV: production
DATABASE_URL: postgres://user:pass@db:5432/mydb
env_file:
- .env.production
volumes:
- ./uploads:/app/uploads # bind mount
- app_data:/app/data # named volume
networks:
- app_net
depends_on:
db:
condition: service_healthy # wait for healthcheck
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- pg_data:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app_net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass secretpassword --appendonly yes
volumes:
- redis_data:/data
networks:
- app_net
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certbot/conf:/etc/letsencrypt:ro
depends_on:
- app
networks:
- app_net
volumes:
pg_data:
redis_data:
app_data:
networks:
app_net:
driver: bridgeCompose Commands
# Start / stop
docker compose up -d # start all services detached
docker compose up -d app db # start specific services
docker compose down # stop and remove containers
docker compose down -v # also remove volumes
docker compose stop # stop without removing
docker compose start # start stopped containers
docker compose restart app # restart specific service
# Build
docker compose build # build all images
docker compose build app # build specific service
docker compose build --no-cache app # ignore cache
# Logs
docker compose logs # all logs
docker compose logs -f app # follow app logs
docker compose logs --tail 50 db # last 50 lines
# Scale
docker compose up -d --scale app=3 # run 3 app containers
# Exec
docker compose exec app bash # shell into service
docker compose exec db psql -U user mydb
# Run one-off command
docker compose run --rm app node migrate.js
# Status
docker compose ps # service status
docker compose top # processes in services
# Config
docker compose config # validate + show merged configNetworking
Bridge (default) — isolated network, containers communicate by service name as DNS
Host — container shares host network stack (Linux only, fastest)
None — completely isolated, no networking
Overlay — multi-host (Docker Swarm / Kubernetes)
# Service discovery in Compose — use service name as hostname
# From 'app' container, connect to db: postgres://user:pass@db:5432/mydb
# From 'app' container, connect to redis: redis://redis:6379
# Network commands
docker network ls
docker network inspect app_app_net
docker network create mynet
docker network connect mynet container1
docker network disconnect mynet container1Override Files
# docker-compose.override.yml is merged automatically in dev
# Use for dev-specific settings (volume mounts, debug ports)
# Explicitly specify files:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Common pattern:
# docker-compose.yml — base config
# docker-compose.override.yml — dev overrides (auto-loaded)
# docker-compose.prod.yml — prod overrides (explicit)Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free