Docker Compose — инструмент для запуска многоконтейнерных приложений через один файл конфигурации. Вместо того чтобы поднимать каждый контейнер руками через docker run, вы описываете весь стек в docker compose файл формата YAML — и запускаете одной командой. Docker compose установка занимает пять минут, а экономит часы работы.
В этой статье — всё что нужно: установка, структура файла, основные команды, сети, volumes и разбор реального примера со стеком Nginx + Node.js + PostgreSQL.
Что такое Docker Compose
Обычный Docker запускает один контейнер одной командой. Реальные приложения состоят из нескольких частей: веб-сервер, бэкенд, база данных, кэш. Запускать их по одному, следить за зависимостями, настраивать сети вручную — боль.
Docker Compose решает это через концепцию services. Каждый сервис — это контейнер (или группа контейнеров). Все сервисы описываются в одном docker-compose.yml файле и управляются как единое целое.
Docker vs Docker Compose — в чём разница
| Docker | Docker Compose |
|---|---|
| Один контейнер за раз | Несколько контейнеров одновременно |
| Команды в терминале | Конфигурация в YAML-файле |
| Сети и volumes — вручную | Автоматически создаёт сети и volumes |
| Нет понятия зависимостей | depends_on — порядок запуска |
| Для одиночных задач | Для dev-окружения и простых прод-стеков |
Когда использовать Compose: локальная разработка, тестовые окружения, небольшие продакшен-стеки на одном сервере.
Когда переходить на Kubernetes: нужна высокая доступность, масштабирование на несколько серверов, сложный оркестратор.
Установка Docker Compose
Есть два варианта Docker Compose — важно не путать:
- docker-compose (со знаком дефис) — старая standalone-утилита, написана на Python, устарела
- docker compose (без дефиса) — современный плагин для Docker CLI, написан на Go, рекомендуется
Используйте плагин. Если где-то встречаете docker-compose в инструкциях — это значит статья старая.
Docker Compose установка на Ubuntu
Способ 1 — через официальный репозиторий Docker (рекомендуется)
Устанавливаем Docker Engine вместе с плагином Compose:
# Удалить старые версии
sudo apt remove docker docker-engine docker.io containerd runc
# Установить зависимости
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
# Добавить GPG-ключ Docker
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Добавить репозиторий
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Установить <a title="Установка и настройка SOCKS5 proxy Dante в Docker Compose" href="https://it-apteka.com/ustanovka-i-nastrojka-socks5-proxy-dante-v-docker-compose/" target="_blank" rel="noopener" data-wpil-monitor-id="521">Docker + плагин Compose</a>
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Способ 2 — через apt (быстро, но не всегда последняя версия)
sudo apt update
sudo apt install -y docker.io docker-compose-plugin
Способ 3 — бинарник (legacy, для старых систем)
# Скачать последний релиз
sudo curl -L \
"https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose
# Дать права на выполнение
sudo chmod +x /usr/local/bin/docker-compose
⚠️ Этот способ даёт старый docker-compose (с дефисом). Используйте только если нет другого выхода.
Проверка установки:
# Версия плагина (современный способ)
docker compose version
# Версия standalone (если стоит старый)
docker-compose --version
Вывод должен быть примерно таким:
Docker Compose version v2.24.0
Если видите v2.x — всё хорошо. Если v1.x — пора обновляться.
Docker Compose file — структура и синтаксис
Весь стек описывается в файле docker-compose.yml (или docker-compose.yaml — оба варианта работают). Это и есть docker compose yaml конфигурация.
Основные секции файла
[yaml] services: # Контейнеры приложенияvolumes: # Постоянное хранилище данных
networks: # Сетевая изоляция
[/yaml]
Директива version в современных версиях Compose не нужна — она устарела начиная с Compose v2. Если встречаете version: "3.8" в старых инструкциях — это нормально, просто наследие.
Полный пример docker-compose.yml
Разворачиваем стек: Nginx → Node.js backend → PostgreSQL:
[yaml] services: nginx:
image: nginx:alpine
container_name: nginx_proxy
ports:
— "80:80"
— "443:443"
volumes:
— ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
— static_files:/var/www/static
depends_on:
— backend
networks:
— frontend
restart: unless-stopped
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: node_backend
environment:
— NODE_ENV=production
— DB_HOST=postgres
— DB_PORT=5432
— DB_NAME=myapp
— DB_USER=appuser
— DB_PASS=secretpassword
volumes:
— ./backend:/app
— /app/node_modules
depends_on:
postgres:
condition: service_healthy
networks:
— frontend
— backend
restart: unless-stopped
postgres:
image: postgres:16-alpine
container_name: postgres_db
environment:
POSTGRES_DB: myapp
POSTGRES_USER: appuser
POSTGRES_PASSWORD: secretpassword
volumes:
— postgres_data:/var/lib/postgresql/data
— ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
— backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
postgres_data:
static_files:
networks:
frontend:
driver: bridge
backend:
driver: bridge
[/yaml]
Разбор секций
services — основная секция. Каждый ключ внутри — отдельный сервис (контейнер). Имя сервиса становится именем хоста внутри сети Compose.
image / build — либо готовый образ из Docker Hub, либо сборка из локального Dockerfile.
ports — проброс портов: "хост:контейнер". Без этого сервис доступен только внутри сети Compose.
environment — переменные окружения. Лучше выносить секреты в .env файл и использовать ${VARIABLE}.
depends_on — порядок запуска. С condition: service_healthy ждёт пока healthcheck не пройдёт.
restart — политика перезапуска: no, always, unless-stopped, on-failure.
volumes — монтирование данных (подробнее ниже).
networks — к каким сетям подключён сервис.
Основные команды Docker Compose
Все docker compose command выполняются из папки, где лежит docker-compose.yml.
docker compose up
Запустить весь стек:
# Запустить в foreground (с выводом логов)
docker compose up
# Запустить в фоне (detached mode)
docker compose up -d
# Пересобрать образы и запустить
docker compose up -d --build
# Запустить только один сервис
docker compose up -d postgres
docker compose down
Остановить и удалить контейнеры:
# Остановить контейнеры
docker compose down
# Остановить и удалить volumes (осторожно - данные удалятся!)
docker compose down -v
# Остановить и удалить образы
docker compose down --rmi all
docker compose ps
Статус контейнеров в стеке:
docker compose ps
# Расширенный вывод
docker compose ps -a
docker compose logs
# Логи всех сервисов
docker compose logs
# Логи конкретного сервиса
docker compose logs backend
# Следить за логами в реальном времени
docker compose logs -f
# Последние 100 строк
docker compose logs --tail=100 postgres
docker compose build
# Собрать все образы
docker compose build
# Собрать без кэша
docker compose build --no-cache
# Собрать конкретный сервис
docker compose build backend
Остальные полезные команды
# Перезапустить сервис
docker compose restart backend
# Выполнить команду внутри контейнера
docker compose exec backend sh
docker compose exec postgres psql -U appuser -d myapp
# Запустить одноразовую команду в новом контейнере
docker compose run --rm backend npm run migrate
# Остановить без удаления
docker compose stop
# Посмотреть конфигурацию после подстановки переменных
docker compose config
# Версия
docker compose version
Docker Compose контейнеры и сервисы
Каждый docker compose service — это шаблон для создания контейнера. По умолчанию из одного сервиса создаётся один docker compose container.
Имя контейнера формируется автоматически: имя_проекта-имя_сервиса-номер. Например: myapp-backend-1. Проект — это имя папки, где лежит docker-compose.yml. Можно задать явно:
docker compose -p myproject up -d
Масштабирование сервисов
# Запустить 3 экземпляра backend
docker compose up -d --scale backend=3
Через файл (современный способ):
[yaml] services:backend:
image: myapp/backend
deploy:
replicas: 3
[/yaml]
⚠️ При масштабировании нельзя использовать фиксированный container_name и проброс конкретного порта хоста — будет конфликт.
Docker Compose network
По умолчанию Compose создаёт одну сеть для всего стека — все сервисы в ней видят друг друга по имени сервиса. Это и есть DNS-resolution внутри Compose.
# Из контейнера backend обращаемся к postgres вот так:
# host: postgres (имя сервиса, не IP)
# port: 5432 (внутренний порт, не пробрасываемый)
Кастомные сети
Разделение на сети — best practice для изоляции. В нашем примере выше:
frontend— nginx и backend: фронт видит бэкbackend— backend и postgres: бэк видит базу- nginx не видит postgres напрямую — изоляция
frontend:
driver: bridge
backend:
driver: bridge
internal: true # Нет доступа в интернет из этой сети
[/yaml]
Подключение к внешней сети
[yaml] networks:shared_network:
external: true # Сеть создана вне Compose, подключаемся к ней
[/yaml]
# Создать сеть заранее
docker network create shared_network
Docker Compose volumes
Без volumes данные живут только пока живёт контейнер. Удалили контейнер — данные исчезли. Docker compose volumes решают эту проблему.
Типы монтирования
Named volume — для данных БД и постоянного хранилища:
[yaml] services:postgres:
volumes:
— postgres_data:/var/lib/postgresql/data
volumes:
postgres_data: # Объявляем именованный volume
[/yaml]
Данные хранятся в /var/lib/docker/volumes/имя_проекта_postgres_data/. Docker управляет этим сам.
Bind mount — для разработки, когда нужно монтировать локальную папку:
[yaml] services:backend:
volumes:
— ./backend:/app # Локальная папка → внутрь контейнера
— /app/node_modules # Анонимный volume для node_modules
[/yaml]
Bind mount позволяет видеть изменения кода в реальном времени без пересборки образа.
Read-only mount — для конфигов:
[yaml] volumes:— ./nginx.conf:/etc/nginx/nginx.conf:ro
[/yaml]
Как не потерять данные БД
Три правила:
- Всегда используйте named volume для данных PostgreSQL, MySQL, MongoDB
- Никогда не делайте
docker compose down -vв продакшене без бэкапа - Регулярно бэкапьте volume отдельно от бэкапа контейнера
# Бэкап PostgreSQL из Compose
docker compose exec postgres pg_dump -U appuser myapp > backup.sql
# Восстановление
docker compose exec -T postgres psql -U appuser myapp < backup.sql
Практический пример — разворачиваем стек Nginx + Node.js + PostgreSQL
Поднимаем продакшен-стек с нуля. Структура проекта:
myapp/
├── docker-compose.yml
├── docker-compose.dev.yml
├── .env
├── nginx/
│ └── nginx.conf
└── backend/
└── Dockerfile
Шаг 1 — Создаём .env файл с секретами:
# .env
POSTGRES_DB=myapp
POSTGRES_USER=appuser
POSTGRES_PASSWORD=supersecret
NODE_ENV=production
Шаг 2 — Production docker-compose.yml:
[yaml] services:nginx:
image: nginx:alpine
ports:
— "80:80"
volumes:
— ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
— backend
networks:
— frontend
restart: unless-stopped
backend:
build: ./backend
environment:
— NODE_ENV=${NODE_ENV}
— DB_HOST=postgres
— DB_NAME=${POSTGRES_DB}
— DB_USER=${POSTGRES_USER}
— DB_PASS=${POSTGRES_PASSWORD}
depends_on:
postgres:
condition: service_healthy
networks:
— frontend
— backend
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
— postgres_data:/var/lib/postgresql/data
networks:
— backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
retries: 5
restart: unless-stopped
volumes:
postgres_data:
networks:
frontend:
backend:
[/yaml]
Шаг 3 — Dev-конфигурация docker-compose.dev.yml (override):
[yaml] services:backend:
build:
context: ./backend
target: development
environment:
— NODE_ENV=development
volumes:
— ./backend:/app
— /app/node_modules
command: npm run dev
postgres:
ports:
— "5432:5432" # В dev пробрасываем порт наружу для подключения из IDE
[/yaml]
Шаг 4 — Запуск:
# Продакшен
docker compose up -d
# Разработка (объединяет оба файла)
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
Шаг 5 — Проверка:
# Статус контейнеров
docker compose ps
# Логи
docker compose logs -f
# Проверить что база поднялась
docker compose exec postgres pg_isready -U appuser
Шаг 6 — Перезапуск после обновления кода:
# Пересобрать и перезапустить только backend
docker compose up -d --build backend
Шаг 7 — Полная остановка:
# Остановить без потери данных
docker compose down
# Остановить и удалить всё включая volumes (осторожно!)
docker compose down -v
Частые ошибки Docker Compose
Порт уже занят
Error: Bind for 0.0.0.0:80 failed: port is already allocated
# Найти что занимает порт
sudo ss -tlnp | grep :80
# Или
sudo lsof -i :80
# Остановить процесс или изменить порт в docker-compose.yml
network not found
Error: network myapp_frontend declared as external, but could not be found
# Создать сеть вручную
docker network create myapp_frontend
# Или убрать external: true из конфига
Неправильный YAML — самая частая причина «ничего не работает»
# Проверить синтаксис файла
docker compose config
# Типичные ошибки:
# - Табы вместо пробелов
# - Неправильные отступы
# - Кавычки не закрыты
permission denied при bind mount
# Проблема: контейнер запускается под другим пользователем
# Решение 1: задать uid/gid
services:
backend:
user: "1000:1000"
# Решение 2: изменить права на хосте
sudo chown -R 1000:1000 ./backend
Контейнер перезапускается в цикле
# Посмотреть почему падает
docker compose logs backend
# Проверить exit code
docker compose ps -a
depends_on не помогает — сервис стартовал, но не готов
depends_on по умолчанию ждёт только запуска контейнера, не его готовности. Используйте healthcheck + condition: service_healthy — пример в файле выше.
Конфликт версий образа
# Всегда указывайте тег образа явно
image: postgres:16-alpine # Хорошо
image: postgres # Плохо - может обновиться и сломать всё
# Обновить образы принудительно
docker compose pull
docker compose up -d
Чек-лист Docker Compose
- ☐ Установлен Docker Compose v2 (
docker compose version) - ☐ Секреты вынесены в
.envфайл, не захардкожены в yml - ☐
.envдобавлен в.gitignore - ☐ Для БД используется named volume, не bind mount
- ☐ Настроен
healthcheckдля БД - ☐
depends_onсcondition: service_healthyдля зависимых сервисов - ☐ Образы указаны с явным тегом (
postgres:16, неpostgres:latest) - ☐ Настроен
restart: unless-stoppedдля продакшена - ☐ Проверен конфиг командой
docker compose config - ☐ Сети разделены для изоляции сервисов
- ☐ Настроен бэкап данных из volumes
Заключение
Docker Compose — стандарт для локальной разработки и простых продакшен-стеков. Один файл описывает весь стек, одна команда его поднимает. Это удобно, воспроизводимо и легко переносится между окружениями.
Используйте Docker Compose когда: одна машина, несколько сервисов, нужна простота и скорость.
Переходите на Kubernetes когда: нужна высокая доступность, несколько серверов, сложный auto-scaling или вы уже чувствуете потолок Compose.
Сохраните статью в закладки — команды и примеры пригодятся.
Оставайтесь на связи
Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.
Подписаться на IT-Аптеку →



