Skip to content

Docker Compose Notes

Docker Compose simplifies running multi-container applications on a single host. This guide covers service organization, daily operations, and maintenance tasks.

Organize your services in a clear directory layout:

/srv/apps/
├── dashboard/
│ ├── compose.yaml
│ ├── .env
│ └── data/
├── database/
│ ├── compose.yaml
│ ├── .env
│ └── data/
└── monitoring/
├── compose.yaml
├── .env
└── data/

Each service gets its own directory with:

  • compose.yaml — Service definition
  • .env — Environment variables (never commit to git)
  • data/ — Persistent volumes

Here’s a minimal compose.yaml for a web application:

compose.yaml
version: '3.8'
services:
app:
image: ghcr.io/example/myapp:latest
restart: unless-stopped
ports:
- "8080:8080"
environment:
- LOG_LEVEL=info
- DATABASE_URL=postgres://db:5432/myapp
volumes:
- ./data:/app/data
depends_on:
- db
networks:
- app-network
db:
image: postgres:15-alpine
restart: unless-stopped
environment:
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=myapp
volumes:
- ./data/postgres:/var/lib/postgresql/data
networks:
- app-network
networks:
app-network:
driver: bridge
Terminal window
cd /srv/apps/dashboard
docker compose up -d
Terminal window
docker compose ps

Output shows running containers, ports, and status.

Terminal window
# All services
docker compose logs --tail=50
# Specific service
docker compose logs app --tail=50
# Follow logs in real-time
docker compose logs -f app
Terminal window
# Graceful stop (waits for containers to shut down)
docker compose stop
# Force stop (immediate termination)
docker compose kill
Terminal window
# Restart all services
docker compose restart
# Restart specific service
docker compose restart app
Terminal window
# Pull latest images
docker compose pull
# Recreate containers with new images
docker compose up -d
Terminal window
# Remove stopped containers
docker compose rm -f
# Remove unused images
docker image prune -a
# Remove unused volumes (⚠️ data loss)
docker volume prune

Create a backup of PostgreSQL data:

Terminal window
docker compose exec db pg_dump -U postgres myapp > backup-$(date +%Y%m%d).sql

Restore from backup:

Terminal window
docker compose exec -T db psql -U postgres myapp < backup-20260601.sql
TaskCommandExpected Output
Services runningdocker compose psAll services show “Up”
Network connectivitydocker compose exec app ping dbReceives ICMP replies
Database readydocker compose exec db psql -U postgres -c "SELECT 1"Returns “1”
Port accessiblecurl http://localhost:8080Service responds

Check logs for errors:

Terminal window
docker compose logs app

Common causes:

  • Missing environment variables
  • Port already in use
  • Volume mount permission issues

Verify containers can reach each other:

Terminal window
docker compose exec app ping db

Check network configuration:

Terminal window
docker network ls
docker network inspect app-network

Check Docker disk usage:

Terminal window
docker system df

Clean up unused resources:

Terminal window
docker system prune -a

If you get permission errors on volumes, fix ownership:

Terminal window
sudo chown -R 1000:1000 /srv/apps/dashboard/data

Replace 1000:1000 with the UID:GID of the container user.

Prevent runaway containers from consuming all resources:

services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M

Add health checks to monitor service status:

services:
app:
image: myapp:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

Limit log file size to prevent disk filling:

services:
app:
image: myapp:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
  • Set up monitoring with Prometheus and Grafana
  • Configure automated backups to external storage
  • Implement log aggregation with ELK or Loki
  • Plan disaster recovery procedures

See Troubleshooting for common issues and solutions.