YAML with Docker and Docker Compose
Docker is the most widely used tool for containerizing applications. Docker Compose is the tool that manages multi-container applications using a single YAML file. Learning YAML for Docker means learning how to describe an entire application — its services, networks, volumes, and environment variables — in one readable file.
What Is a Docker Compose File?
A Docker Compose file is a YAML file named docker-compose.yml. It defines all the services that make up an application and how they connect to each other. One command — docker compose up — reads this file and starts all defined services.
Top-Level Keys in Docker Compose
| Key | Purpose |
|---|---|
version | Specifies the Compose file format version |
services | Defines the individual containers (applications) |
networks | Defines custom networks for services to communicate |
volumes | Defines named storage volumes for persistent data |
configs | Defines configuration files to inject into services |
secrets | Defines sensitive data like passwords and certificates |
Docker Compose File Structure Diagram
docker-compose.yml
│
├── version: "3.9"
│
├── services:
│ ├── web:
│ │ ├── image / build
│ │ ├── ports
│ │ ├── environment
│ │ ├── volumes
│ │ └── depends_on
│ │
│ └── db:
│ ├── image
│ ├── environment
│ └── volumes
│
├── networks:
│ └── app_network
│
└── volumes:
└── db_data
Basic Single-Service Example
version: "3.9"
services:
web:
image: nginx:latest
ports:
- "80:80"
This starts one Nginx web server container and exposes port 80 on the host machine.
Understanding the ports Key
ports: - "8080:80" # HOST_PORT:CONTAINER_PORT - "443:443"
The format is HOST_PORT:CONTAINER_PORT. Traffic on the host machine's port 8080 forwards into the container's port 80.
Building from a Dockerfile
Instead of using an existing image, a service can build its container from a local Dockerfile.
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
The context: . means Docker looks for the Dockerfile in the current directory.
Environment Variables
Configuration values like database credentials or API keys are passed to containers as environment variables.
services:
app:
image: myapp:latest
environment:
NODE_ENV: production
DB_HOST: db
DB_PORT: 5432
DB_NAME: appdb
Alternatively, environment variables can be loaded from an external file using env_file.
services:
app:
image: myapp:latest
env_file:
- .env
Volumes for Persistent Data
Volumes keep data alive even when a container stops or is replaced.
services:
db:
image: postgres:15
volumes:
- db_data:/var/lib/postgresql/data # Named volume
- ./init.sql:/docker-entrypoint-initdb.d/init.sql # Bind mount
volumes:
db_data: # Named volume declaration
A named volume (db_data) is managed by Docker. A bind mount (./init.sql:...) maps a file from the host machine directly into the container.
Service Dependencies (depends_on)
services:
web:
image: myapp:latest
depends_on:
- db
- redis
db:
image: postgres:15
redis:
image: redis:7
The depends_on key tells Docker to start the db and redis containers before starting web. Note that this waits for the container to start, not for the service inside to be ready.
Custom Networks
services:
frontend:
image: nginx:latest
networks:
- frontend_net
backend:
image: myapi:latest
networks:
- frontend_net
- backend_net
db:
image: postgres:15
networks:
- backend_net
networks:
frontend_net:
backend_net:
Custom networks isolate services. The database is only on backend_net and cannot be reached directly from the frontend container.
Complete Full-Stack Example
version: "3.9"
services:
# Frontend
frontend:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./frontend/dist:/usr/share/nginx/html
depends_on:
- api
networks:
- app_net
# Backend API
api:
build:
context: ./api
ports:
- "3000:3000"
environment:
NODE_ENV: production
DB_HOST: db
DB_PORT: 5432
DB_USER: admin
DB_PASS: secret
depends_on:
- db
networks:
- app_net
# Database
db:
image: postgres:15
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
volumes:
- db_data:/var/lib/postgresql/data
networks:
- app_net
networks:
app_net:
volumes:
db_data:
Common Docker Compose YAML Properties
| Property | Description | Example |
|---|---|---|
image | Docker image to use | nginx:latest |
build | Build from Dockerfile | context: . |
ports | Port mapping | "8080:80" |
environment | Environment variables | NODE_ENV: production |
volumes | Mount files or directories | ./data:/app/data |
depends_on | Service startup order | - db |
networks | Connect to networks | - app_net |
restart | Restart policy | always, on-failure |
command | Override container command | npm start |
healthcheck | Container health monitoring | test: ["CMD", "curl", "-f", "http://localhost"] |
Summary
- Docker Compose uses a YAML file to define multi-container applications
- Top-level keys include
services,networks, andvolumes - Each service can use an existing image or build from a Dockerfile
- Ports follow the format
HOST:CONTAINER - Environment variables configure containers without hardcoding values
- Named volumes persist data across container restarts
- Custom networks isolate services and control communication
