Docker Compose: многоконтейнерные приложения
Зачем Docker Compose
docker run запускает один контейнер. Реальное приложение — это минимум три: бэкенд, база данных, кэш. Запускать их вручную — пытка. Docker Compose решает это одной командой.
bash
docker compose up -d # запустить всё
docker compose down # остановить всё
docker compose logs -f # логи всех сервисовСтруктура docker-compose.yml
yaml
services:
web: # имя сервиса (используется как hostname)
image: nginx:alpine
ports:
- "80:80"
api:
build: ./backend # собрать из Dockerfile
environment:
DATABASE_URL: postgres://user:pass@db:5432/myapp
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:build: vs image:
yaml
services:
# Готовый образ из registry
redis:
image: redis:7-alpine
# Собрать из Dockerfile в текущей папке
api:
build: .
# Собрать из конкретной папки и файла
api:
build:
context: ./backend
dockerfile: Dockerfile.prod
args:
NODE_ENV: productionПеременные окружения
yaml
# Вариант 1: прямо в YAML (не для секретов!)
environment:
PORT: 3000
NODE_ENV: production
# Вариант 2: из .env файла
env_file:
- .env
- .env.local
# Вариант 3: подстановка из shell
environment:
API_KEY: ${MY_API_KEY} # из переменной окружения хостаbash
# .env файл
DATABASE_URL=postgres://user:pass@db:5432/myapp
SECRET_KEY=super-secretdepends_on: порядок запуска
yaml
services:
api:
depends_on:
db:
condition: service_healthy # ждать health check
redis:
condition: service_started # просто запущен
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5depends_on гарантирует порядок запуска, но не готовность к работе. Используй condition: service_healthy для надёжности.
Volumes
yaml
services:
db:
volumes:
- pgdata:/var/lib/postgresql/data # named volume
- ./init.sql:/docker-entrypoint-initdb.d/init.sql # bind mount
app:
volumes:
- .:/app # весь проект (для разработки)
- /app/node_modules # анонимный volume (исключить node_modules хоста)
volumes:
pgdata: # объявить named volumeNetworks
yaml
networks:
frontend:
backend:
internal: true # не доступна снаружи
services:
nginx:
networks: [frontend]
api:
networks: [frontend, backend] # мост между зонами
db:
networks: [backend] # только внутренняя сетьСервисы в одной сети обращаются друг к другу по имени: http://api:8000, postgres://db:5432.
Полный стек для разработки
yaml
# docker-compose.yml
services:
web:
build: ./frontend
ports:
- "3000:3000"
volumes:
- ./frontend:/app
- /app/node_modules
environment:
VITE_API_URL: http://localhost:8000
depends_on: [api]
api:
build: ./backend
ports:
- "8000:8000"
volumes:
- ./backend:/app
environment:
DATABASE_URL: postgres://user:pass@db:5432/dev
REDIS_URL: redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: dev
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
volumes:
pgdata:
redis-data:Команды
bash
# Жизненный цикл
docker compose up -d # запустить в фоне
docker compose up --build # пересобрать перед запуском
docker compose down # остановить и удалить контейнеры
docker compose down -v # + удалить volumes
docker compose restart api # перезапустить конкретный сервис
# Мониторинг
docker compose ps # состояние сервисов
docker compose logs -f api # логи сервиса
docker compose top # процессы внутри контейнеров
# Выполнение команд
docker compose exec api bash # войти в контейнер
docker compose exec db psql -U user # запустить команду
docker compose run --rm api pytest # одноразовый контейнер
# Обновление
docker compose pull # обновить образы
docker compose up -d --force-recreate # пересоздать контейнерыOverride файлы
yaml
# docker-compose.yml — базовый
services:
api:
image: myapp:latest
environment:
NODE_ENV: productionyaml
# docker-compose.override.yml — автоматически накладывается при разработке
services:
api:
build: . # переопределяет image
volumes:
- .:/app
environment:
NODE_ENV: development
ports:
- "8000:8000"bash
# Явно указать файлы
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dProfiles: не все сервисы нужны всегда
yaml
services:
api:
# нет profile — запускается всегда
pgadmin:
image: dpage/pgadmin4
profiles: [tools] # только при явном включении
tests:
build: .
command: pytest
profiles: [ci]bash
docker compose up # только api
docker compose --profile tools up # + pgadmin
docker compose --profile ci run tests # запустить тестыCompose vs Swarm vs Kubernetes
| Compose | Swarm | Kubernetes | |
|---|---|---|---|
| Масштаб | 1 хост | Несколько хостов | Тысячи хостов |
| Сложность | Низкая | Средняя | Высокая |
| Сценарий | Разработка, маленький прод | Средний прод | Крупный прод |
| Rolling updates | Нет | Есть | Есть |
Для большинства проектов Compose (разработка) + Swarm или managed Kubernetes (прод) — оптимальный выбор.
Интерактивные уроки по теме