Docker Compose
Зачем нужно
Docker Compose — инструмент для запуска нескольких контейнеров одной командой. Вместо десятка docker run команд ты описываешь все сервисы в одном YAML-файле и запускаешь docker compose up. Приложение + база данных + кэш = один файл конфигурации.
Где используется
- Локальная разработка — полный стек одной командой
- Тестирование — поднять окружение для интеграционных тестов
- CI/CD — тестовое окружение в пайплайне
- Демонстрации — быстрый показ проекта
docker-compose.yml
Базовая структура
# docker-compose.yml
version: '3.8' # версия синтаксиса (можно опустить в новых версиях)
services:
# Каждый сервис — отдельный контейнер
app:
build: .
ports:
- "3000:3000"
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
Полный пример: Node.js + PostgreSQL + Redis
version: '3.8'
services:
# === Приложение ===
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379
volumes:
- .:/app # монтируем код для hot-reload
- /app/node_modules # но не перезаписываем node_modules
depends_on:
- db
- cache
restart: unless-stopped
# === База данных ===
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
# === Кэш ===
cache:
image: redis:7-alpine
ports:
- "6379:6379"
# === Именованные тома ===
volumes:
postgres_data:
Ключевые секции
services — сервисы
services:
web:
# Из образа Docker Hub
image: nginx:alpine
app:
# Собрать из Dockerfile
build: .
# или с параметрами
build:
context: ./backend
dockerfile: Dockerfile.dev
args:
NODE_VERSION: 20
ports — проброс портов
services:
app:
ports:
- "3000:3000" # host:container
- "9229:9229" # debug порт
volumes — тома и маунты
services:
app:
volumes:
- .:/app # bind mount (для разработки)
- /app/node_modules # анонимный том
- app_data:/app/data # именованный том
db:
volumes:
- db_data:/var/lib/postgresql/data
volumes:
app_data:
db_data:
environment — переменные окружения
services:
app:
# Способ 1: список
environment:
- NODE_ENV=development
- API_KEY=abc123
# Способ 2: словарь
environment:
NODE_ENV: development
API_KEY: abc123
# Способ 3: из файла
env_file:
- .env
- .env.local
networks — сети
services:
frontend:
networks:
- frontend_net
backend:
networks:
- frontend_net
- backend_net
db:
networks:
- backend_net # недоступна из frontend
networks:
frontend_net:
backend_net:
depends_on — порядок запуска
services:
app:
depends_on:
db:
condition: service_healthy # ждать healthcheck
cache:
condition: service_started # просто запустился
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
timeout: 5s
retries: 5
Команды Docker Compose
# === Запуск ===
docker compose up # запуск (с логами)
docker compose up -d # запуск в фоне (detached)
docker compose up --build # пересобрать образы и запустить
docker compose up app # запустить только сервис app
# === Остановка ===
docker compose down # остановить и удалить контейнеры
docker compose down -v # + удалить volumes
docker compose stop # остановить без удаления
# === Логи ===
docker compose logs # все логи
docker compose logs app # логи конкретного сервиса
docker compose logs -f app # следить за логами (follow)
# === Выполнение команд ===
docker compose exec app sh # зайти в контейнер
docker compose exec app npm test # запустить тесты
docker compose exec db psql -U user # подключиться к БД
# === Информация ===
docker compose ps # список контейнеров
docker compose top # процессы в контейнерах
docker compose config # проверить конфигурацию
# === Масштабирование ===
docker compose up -d --scale app=3 # запустить 3 экземпляра
Пример: фронтенд + бэкенд + БД
version: '3.8'
services:
# React frontend
frontend:
build: ./frontend
ports:
- "5173:5173"
volumes:
- ./frontend:/app
- /app/node_modules
environment:
- VITE_API_URL=http://localhost:4000
# Express backend
backend:
build: ./backend
ports:
- "4000:4000"
volumes:
- ./backend:/app
- /app/node_modules
environment:
- DATABASE_URL=postgres://user:pass@db:5432/app
- JWT_SECRET=dev-secret
depends_on:
db:
condition: service_healthy
# PostgreSQL
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: app
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
- ./backend/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d app"]
interval: 5s
timeout: 5s
retries: 5
# Adminer (GUI для БД)
adminer:
image: adminer
ports:
- "8080:8080"
depends_on:
- db
volumes:
pgdata:
Файл .env для Compose
# .env (рядом с docker-compose.yml)
POSTGRES_USER=user
POSTGRES_PASSWORD=secret
POSTGRES_DB=myapp
NODE_ENV=development
# docker-compose.yml
services:
db:
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
Частые ошибки
| Ошибка | Проблема | Решение |
|---|---|---|
depends_on не ждёт готовности |
Контейнер запущен, но сервис не готов | Используй condition: service_healthy |
Потеря данных БД при down |
Данные в контейнере | Используй именованные volumes |
node_modules пустой |
Volume перезаписывает | Добавь /app/node_modules как анонимный volume |
| Порт уже занят | Конфликт портов | Смени порт хоста: "3001:3000" |
| Изменения кода не видны | Нет bind mount | Добавь volumes: - .:/app |
Практика
- Создай
docker-compose.ymlдля Node.js + MongoDB - Добавь Adminer для просмотра базы данных через браузер
- Настрой hot-reload через bind mount для разработки
- Используй healthcheck для ожидания готовности БД
- Создай
.envфайл и вынеси туда все переменные
Связанные темы
- Что такое Docker — основы Docker
- Dockerfile — создание образов
- Что такое CI-CD — использование Compose в CI
- Vercel — альтернатива для фронтенда
Ресурсы
- Docker Compose Documentation
- Compose file reference
- Awesome Compose — примеры конфигураций