Docker Compose: Orchestrating Containers from Scratch with YAML
Docker Compose is the official tool for defining and running multi-container applications. Instead of running 3 long docker run commands with hard-to-remember options, you describe your entire stack in a YAML file and spin everything up with docker compose up.
Installation
# Docker Compose v2 já vem integrado ao Docker Engine (como plugin)
docker compose version # deve retornar v2.x
# Se não estiver disponível, instalar o plugin
sudo apt install docker-compose-plugin -y
# Versão standalone (legado, ainda funciona)
sudo apt install docker-compose -y # docker-compose (com hífen)
Structure of docker-compose.yml
version: "3.9"
services:
app:
build: . # usa o Dockerfile na raiz
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:senha@db:5432/meudb
depends_on:
db:
condition: service_healthy # espera o banco estar pronto
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: senha
POSTGRES_DB: meudb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
pgdata: # volume nomeado, persiste entre restarts
Essential Commands
# Subir todos os serviços em background
docker compose up -d
# Ver logs de todos (ou de um serviço específico)
docker compose logs -f
docker compose logs -f app
# Listar containers do projeto
docker compose ps
# Parar e remover containers (mantém volumes)
docker compose down
# Parar, remover containers E volumes
docker compose down -v
# Rebuildar imagem e recriar container
docker compose up -d --build app
# Rodar comando em container em execução
docker compose exec app bash
docker compose exec db psql -U user meudb
Environment Variables with .env
Never put passwords directly in docker-compose.yml. Use a .env file in the same folder (and add it to .gitignore):
# .env
POSTGRES_USER=user
POSTGRES_PASSWORD=senha_super_segura
POSTGRES_DB=meudb
# docker-compose.yml — referencia com ${VAR}
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
Volumes: Data Persistence
services:
app:
volumes:
# Volume nomeado (gerenciado pelo Docker)
- dados_app:/app/uploads
# Bind mount (pasta do host mapeada no container)
# Útil em desenvolvimento para hot-reload
- ./src:/app/src
# Arquivo único montado no container
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
volumes:
dados_app:
Bind mounts are great for development — you edit the file on the host and the container sees the change immediately. In production, prefer named volumes as they are managed by Docker and easier to back up.
Networks: Communication between Services
By default, all services in the same docker-compose.yml are on the same network and can communicate using the service name as hostname. The app service accesses the database at db:5432, not at localhost:5432.
# Redes customizadas (para isolamento)
networks:
frontend:
backend:
services:
nginx:
networks: [frontend, backend]
app:
networks: [backend]
db:
networks: [backend]
Real Example: WordPress + MySQL + Nginx
version: "3.9"
services:
nginx:
image: nginx:alpine
ports: ["80:80"]
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- wordpress:/var/www/html
depends_on: [wordpress]
wordpress:
image: wordpress:php8.2-fpm
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: ${DB_USER}
WORDPRESS_DB_PASSWORD: ${DB_PASS}
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress:/var/www/html
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASS}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
volumes:
- dbdata:/var/lib/mysql
volumes:
wordpress:
dbdata:
Docker Compose vs Kubernetes
Compose is for one machine; Kubernetes is for a cluster. For projects with 1–5 services on a single server, Compose is the right choice — simple, no K8s learning curve, easy to back up and migrate. Use Kubernetes when you need horizontal auto-scaling or high availability with multiple nodes.
That was just one piece. The course teaches the whole path — from your first command to exam day.