Looking to improve your development workflow with Docker Compose? This guide covers everything developers should know - from basic setup to common troubleshooting patterns.
Table of Contents ๐
- What is Docker Compose?
- Basic Setup
- Essential Commands
- Development Workflow
- Troubleshooting
- Advanced Features
- Conclusion
What is Docker Compose? ๐
Docker Compose makes it easy to run multiple containers together. This is a great tool for local development and testing without messing your machine.
Instead of starting each service (like the database, backend, and frontend) separately, Compose lets you define everything in a single file compose.yml
(or docker-compose.yml
for older versions) and start them with a single command.
Basic Setup ๐
Docker Compose Template
Hereโs a minimal yet practical template for a backend app and database:
services:
backend:
build: ./backend
ports:
- "8000:8000"
environment:
- DB_HOST=database
- DB_USER=postgres
- DB_PASSWORD=secretpassword
depends_on:
# Waits for 'database' service to start
- database
volumes:
# Mounts local directory to container for live code updates
- ./backend:/app
database:
image: postgres:17
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secretpassword
volumes:
# Persists data using named volume 'db_data'
- db_data:/var/lib/postgresql/data
volumes:
# Declares the named volume
db_data:
Key Features:
-
depends_on
: Ensures services start in order. -
volumes
: Supports persistent data and live code updates. - Environment variables: Simple configuration for connections.
Configuration Priority
Docker Compose uses this file priority:
1. compose.yml
2. compose.yaml
3. compose.override.yml
4. compose.override.yaml
Note: docker-compose.yml
was the standard name for many years. While still valid, Docker now defaults to compose.yml
in modern projects. If you are using an older environment or tools, docker-compose.yml
will still work seamlessly.
You can use override files for development-specific settings:
# compose.yml (base configuration)
services:
backend:
build: ./backend
environment:
- NODE_ENV=production
# compose.override.yml (development overrides)
services:
backend:
environment:
- NODE_ENV=development
volumes:
- ./backend:/app
Ignore overrides with:
docker compose -f compose.yml up -d
Essential Commands ๐ก
Basic Operations
# Start services
docker compose up -d # Detached mode
docker compose up --build # Rebuild images
# Stop services
docker compose stop # Stops running containers without removing them.
docker compose down # Stops and removes containers and networks.
Common Tasks
Frequently used commands during development:
# Check running services
docker compose ps
# View service logs for all services
docker compose logs -f
# Restart a single service (for quick iterations)
docker compose restart backend
Cleaning Up Services
Keeping your environment clean is essential. Here are the key commands for managing unused resources and containers:
Command | Description |
---|---|
docker compose down -v |
Stops and removes all containers, networks, and volumes. |
docker compose down --remove-orphans |
Removes unused containers not defined in the compose.yml . |
docker compose rm -f [service_name] |
Forcibly removes specific containers without stopping the project. |
Usage:
-
down -v
: Use for a complete cleanup, including persistent data and volumes. -
down --remove-orphans
: Ideal for clearing out leftover or unrelated containers. -
rm -f [service_name]
: Quickly remove specific containers.
Building and Starting Services
Hereโs a quick reference for commonly used commands to build images and start containers:
Command | Description |
---|---|
docker compose up |
Starts services defined in compose.yml . |
docker compose build |
Rebuilds service images without starting containers. |
docker compose up --build |
Rebuilds service images and starts services together. |
Usage:
-
up
: Start containers when images are already built. -
build
: Rebuild images when changes are made to theDockerfile
or dependencies. -
up --build
: Rebuild and start services in one step. Ideal for quick iterations.
Working with Containers
You can interact with containers using Service Names (recommended for docker compose
) or Container Names (standalone docker
commands):
Using Docker Compose (Service Name)
Service names, defined in compose.yml
, make interaction easier:
docker compose exec database bash # Access the container shell
docker compose exec database psql -U postgres -d myapp # Connect to the PostgreSQL
Note: Service names are defined in the services
section of compose.yml
.
Using Docker Commands (Container Name)
Use container names, shown in docker ps
, for manual interactions:
docker exec -it myapp-db bash # Access the container shell
docker exec -it myapp-db psql -U postgres -d myapp # Connect to PostgreSQL
Note: Docker automatically generates names (e.g., database_1
) unless you manually set container_name
. Avoid this for scaling.
Development Workflow ๐
Use the following commands based on the type of changes:
- Code Changes: Restart the service.
docker compose restart backend
- Dockerfile or Dependency Changes: Rebuild and restart.
docker compose up --build backend
- Full Cleanup and Reset:
docker compose down -v # Stop and clean up everything
docker compose up --build # Rebuild and restart all services
Troubleshooting ๐ ๏ธ
Port Allocation Errors
When you see an error like this:
Error: Bind for 0.0.0.0:8000 failed: port is already allocated
It means the local port 8000 is already in use.
Solutions:
- Check Port Usage: Find the process using the port:
lsof -i :8000
- Kill the Process: Terminate the process occupying the port:
kill -9 <PID>
- Change the Port: Update
compose.yml
to use a different local port:
ports:
- "8080:8000" # Map local port 8080 to container port 8000
Advanced Features โก
Network Configuration
Define custom networks to enable secure communication between services:
services:
backend:
networks:
- app-network
database:
networks:
- app-network
networks:
app-network:
driver: bridge
Tip: Use docker network ls
and docker network inspect
to troubleshoot network issues.
Health Checks
Ensure services are ready before other services depend on them:
services:
database:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
- Purpose: Prevents dependent services from starting too early.
Resource Management
Control resource usage to ensure stable performance:
services:
backend:
deploy:
resources:
limits:
cpus: '0.50'
memory: 512M
- Purpose: Avoids a single service consuming too many resources.
Conclusion ๐ฏ
Docker Compose might look complex at first, but understanding these basics will help you manage most situations.
- Start simple.
- Use the right command for the task.
- Keep your environment clean.
I hope this guide is helpful. Let me know if you have suggestions or spot anything I missed! ๐ฌ
Happy containerizing! ๐ณ
Top comments (0)