Docker Compose Essentials
Learn how to manage multi-container applications using Docker Compose.
Docker Compose Essentials
As applications grow, managing containers individually becomes difficult.
Consider a typical web application:
- Frontend
- Backend API
- Database
Running each service manually with docker run quickly becomes repetitive and error-prone.
Docker Compose solves this problem by allowing you to define and manage multi-container applications using a single configuration file.
What is Docker Compose?
Docker Compose is a tool that allows you to define an entire application stack inside a YAML file.
Instead of running multiple commands:
docker run ...
docker run ...
docker run ...
You can start everything with:
docker compose up
Compose automatically handles:
- Networks
- Service discovery
- Volumes
- Environment variables
- Container lifecycle
Creating Your First Compose File
Docker Compose uses a file named:
compose.yaml
A minimal example:
services:
app:
image: nginx
ports:
- "8080:80"
Start the application:
docker compose up
Docker downloads the image and starts the container.
Visit:
http://localhost:8080
Understanding the Structure
A Compose file typically contains:
services:
app:
image: nginx
volumes:
networks:
Services
Services define the containers that make up your application.
Example:
services:
frontend:
image: nginx
backend:
image: node:20
Each service becomes its own container.
Building Images with Compose
Instead of pulling an image, Compose can build one directly.
services:
api:
build: .
Compose automatically executes:
docker build .
before starting the container.
You can also specify a directory:
services:
api:
build: ./backend
Port Mapping
Expose container ports to the host machine.
services:
api:
build: .
ports:
- "3000:3000"
Format:
HOST_PORT:CONTAINER_PORT
Example:
localhost:3000
│
▼
Container Port 3000
Environment Variables
Applications often require configuration.
services:
api:
environment:
NODE_ENV: production
PORT: 3000
You can access these values inside the container.
Example:
process.env.NODE_ENV
Using Environment Files
Instead of hardcoding values:
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
Create a .env file:
DATABASE_URL=postgres://user:pass@db:5432/app
Then reference it:
services:
api:
env_file:
- .env
This keeps sensitive values out of source code.
Working with Volumes
Volumes allow data to persist after containers are removed.
Example:
services:
postgres:
image: postgres:16
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Without the volume:
Container Removed
│
▼
Database Lost
With the volume:
Container Removed
│
▼
Data Persists
Service Communication
One of Compose's biggest advantages is automatic networking.
Example:
services:
api:
build: .
database:
image: postgres
Docker automatically creates a network.
The API can connect to PostgreSQL using:
database:5432
No manual network configuration is required.
Multi-Container Example
A simple application stack:
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
api:
build: .
ports:
- "3000:3000"
depends_on:
- postgres
Architecture:
Browser
│
▼
API Container
│
▼
PostgreSQL Container
Starting Services
Start all services:
docker compose up
Start in the background:
docker compose up -d
The -d flag runs containers in detached mode.
Viewing Running Services
Check status:
docker compose ps
Example output:
NAME STATUS
api running
postgres running
Viewing Logs
Display logs from all services:
docker compose logs
Follow logs in real time:
docker compose logs -f
View logs for a specific service:
docker compose logs api
Stopping Services
Stop the stack:
docker compose down
This removes:
- Containers
- Networks
Volumes remain unless explicitly removed.
Remove everything:
docker compose down -v
Use caution when deleting volumes.
Rebuilding Services
If application code changes:
docker compose build
Or rebuild and restart:
docker compose up --build
Common Commands
Start services:
docker compose up
Run in background:
docker compose up -d
View status:
docker compose ps
View logs:
docker compose logs
Stop services:
docker compose down
Rebuild images:
docker compose build
Best Practices
Use Compose for Local Development
Compose makes development environments reproducible.
Every developer can start the entire stack with:
docker compose up
Keep Secrets Out of Source Control
Prefer:
DATABASE_URL=...
over hardcoded credentials.
Use Named Volumes
For databases and persistent storage:
volumes:
postgres-data:
Separate Services
Avoid combining multiple applications into a single container.
One service should perform one primary responsibility.
Summary
Docker Compose simplifies multi-container application management.
Key benefits include:
- Single-file application configuration
- Automatic networking
- Volume management
- Environment variable support
- Simplified container lifecycle management
For most development workflows, Docker Compose becomes the primary way to run containerized applications.