В статье расскажем, что такое Docker Compose, какие задачи он решает и как используется на практике. Рассмотрим структуру конфигурационного файла, основные команды и пример развёртывания.
Что такое Docker Compose
Docker Compose — это инструмент для управления набором взаимосвязанных контейнеров. Их конфигурация задаётся декларативно в конфигурационных файлах. Docker Compose позволяет описывать сервисы приложения, их зависимости и параметры, обеспечивая согласованную работу всех компонентов.
Зачем нужен Docker Compose
Современные приложения часто включают множество компонентов: веб-сервер, базу данных, системы кэширования, мониторинга и др. Каждый компонент может быть запущен в отдельном Docker-контейнере.
Docker Engine предоставляет средства для управления контейнерами, но при работе с несколькими сервисами необходимо отдельно настраивать сети, тома и параметры запуска контейнеров, что усложняет управление приложением. Если контейнеров много, это превращается в неудобную и сложную задачу.
Docker Compose решает эту проблему. Он позволяет описать конфигурацию всего приложения в одном файле, после чего приложение можно развернуть, запустить и остановить одной командой. Также инструмент удобен тем, что для многих популярных сервисов уже существуют готовые файлы конфигурации. Их можно найти в официальной документации проектов, на GitHub или в различных репозиториях примеров.
Однако следует учитывать, что Docker Compose используется для управления контейнерами на одном сервере. Для управления контейнерами в распределённых кластерах применяются системы оркестрации.
Когда использовать Docker Compose
Приведем наиболее распространённые сценарии использования инструмента:
- Разработка и развёртывание многоконтейнерных приложений. Docker Compose позволяет описать все компоненты приложения в одном compose-файле и управлять ими как единым целым. После описания конфигурации всю инфраструктуру можно запустить, остановить или пересоздать одной командой.
- Развёртывание локальной среды разработки. Разработчику не нужно самостоятельно устанавливать и настраивать базы данных, брокеры сообщений, системы кэширования и другие сервисы. Их конфигурация описана в compose-файле, который хранится в репозитории проекта и используется всеми участниками команды. Окружение разворачивается автоматически с помощью Docker Compose. Использование такого подхода позволяет:
- обеспечить одинаковую конфигурацию среды у всех разработчиков;
- быстро развернуть рабочее окружение проекта;
- избежать конфликтов версий программного обеспечения и зависимостей.
- Тестирование приложений. В процессе тестов можно запускать полный стек приложения. После завершения тестирования всю среду легко удалить и получить чистое окружение.
- Развёртывание демонстрационной среды. Docker Compose удобно применять для демонстраций, учебных проектов и лабораторных работ, так как он помогает быстро развернуть заранее подготовленное окружение одной командой.
- Запуск сервисов для экспериментов. Инструмент позволяет разворачивать и удалять различные сервисы, не засоряя основную систему.
Установка
Для работы с Docker Compose необходимо установить Docker Engine и плагин Docker Compose CLI. Начиная с версии Docker 20.10 Compose поставляется как плагин к Docker Engine.
Установить Docker Engine и Docker Compose вам поможет статья.
Проверка установки:
docker --version
docker compose versionСтруктура compose.yaml — основные разделы
Инфраструктура проекта описывается в файле compose.yaml, который размещается в рабочей директории проекта. В более ранних версиях также использовались имена docker-compose.yaml или docker-compose.yml. Файл использует формат YAML и содержит декларативное описание сервисов, сетей и томов. Важно соблюдать синтаксис YAML: структура файла определяется отступами, и ошибка в форматировании может привести к невозможности запуска проекта.
Для проверки корректности compose-файла используется команда:
docker compose config --quietЕсли файл некорректный, команда выведет ошибку с точной строкой. Если ошибок нет — вывод будет пустой.
Ключевые разделы:
- services — описание контейнеров;
- volumes — именованные тома;
- networks — пользовательские сети.
Формально, раздел services является единственным обязательным разделом верхнего уровня.
Docker Compose можно использовать как для простых, так и для более сложных конфигураций. В одном случае это может быть запуск одного сервиса, например, Nginx, в другом — полноценное приложение из нескольких компонентов, таких как веб-сервер, база данных и система управления контентом.
Сначала рассмотрим минимальный пример использования Compose, а затем перейдём к более сложной конфигурации. Опишем сервис Nginx в compose-файле и запустим его:
- В директории проекта создадим файл compose.yml:
services:
nginx:
image: nginx
ports:
- "8080:80"- Введём команду:
docker compose up -dCompose выполнит следующие действия:
скачает образ nginx;
создаст контейнер;
пробросит порт 8080 на 80;
запустит контейнер.

В результате nginx будет запущен на 8080 порту хоста.
Если порт 8080 на хосте занят другим приложением, то контейнер не запустится (несмотря на то, что предыдущие этапы прошли корректно) и compose выведет ошибку:

С помощью параметра include можно использовать дополнительные compose-файлы:
compose.yaml:
services:
web:
image: nginx
ports:
- "80:80"
include:
- database.yaml
database.yaml:
services:
db:
image: postgres:15
Рассмотрим реальный пример конфигурации и запуска многоконтейнерного приложения — Nginx — сайт на WordPress — MySQL:
version: "3.9"
services:
nginx:
image: nginx:stable
container_name: nginx_proxy
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- wp_data:/var/www/html
depends_on:
- wordpress
networks:
- frontend
- backend
wordpress:
image: wordpress:php8.2-fpm
container_name: wordpress_app
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: strong_password
WORDPRESS_DB_NAME: wordpress
volumes:
- wp_data:/var/www/html
depends_on:
- db
networks:
- backend
db:
image: mysql:8.0
container_name: mysql_db
restart: unless-stopped
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wp_user
MYSQL_PASSWORD: strong_password
MYSQL_ROOT_PASSWORD: root_password
volumes:
- db_data:/var/lib/mysql
networks:
- backend
volumes:
wp_data:
db_data:
networks:
frontend:
backend:
internal: trueВ начале compose-файла часто можно увидеть поле version. В современных версиях Docker Compose поле version больше не используется и игнорируется. Оно сохраняется только для совместимости со старыми версиями Compose.
Имя проекта может быть задано параметром name. Если параметр не задан, то в качестве имени проекта используется имя директории, в которой находится compose-файл.

Services (сервисы)
В данном разделе описываем сервисы приложения и их параметры. При запуске Docker Compose для каждого сервиса создаётся отдельный контейнер. Полный список атрибутов данного раздела приведен в официальной документации.
Основные атрибуты:
- image — определяет образ из которого запускается контейнер. В нашем примере образы nginx, wordpress, mysql будут загружены из репозитория docker.
- build — задаёт параметры сборки образа, включая контекст сборки (директорию с файлами, используемыми при сборке) и путь к Dockerfile.
При наличии обоих атрибутов image и build образ будет собран из dockerfile, указанного в build.собранный образ получит тег, прописанный в image.
Например,
services:
app:
build: ./app
image: myapp:1.0Образ будет собран из dockerfile, который расположен в поддиректории проекта app и ему будет присвоен тег myapp:1.0
Фактически, выполняется:
docker build -t myapp:1.0 ./app- command — задаёт команду, которая будет выполнена при запуске контейнера. Если указан данный атрибут, он переопределяет команду по умолчанию (CMD) из Dockerfile:
services:
app:
image: nginx
command: ["-g", "daemon off;"]- entrypoint — задаёт основной исполняемый процесс контейнера. Если указан, переопределяет
ENTRYPOINTиз Dockerfile:
services:
app:
image: nginx
entrypoint: ["nginx"]- container_name
— задаёт имя контейнера. В нашем примере поле используется для наглядности, но в большинстве случаев container_name не рекомендуется использовать, так как Docker Compose автоматически генерирует уникальные имена контейнеров. - restart — определяет политику перезагрузки контейнера:
- no — контейнер не перезапускается ни при каких обстоятельствах.
- always — контейнер перезапускается всегда: при падении, при ручной остановке Docker daemon, после перезагрузки сервера.
- on-failure — контейнер перезапускается только при завершении с ошибкой (exit code ≠ 0).
- unless-stopped — контейнер перезапускается при падении, после перезагрузки сервера, но не будет перезапущен при ручной остановке.
- ports — проброс портов контейнера на хост. Левая часть относится к хосту, правая — к контейнеру.
Например:
ports:
- "80:8080"Порт 80 на хосте будет соответствовать 8080 порту в контейнере.
В нашем примере 80 порт контейнера nginx соответствует 80 порту на хосте.
- environment — определяет переменные окружения, которые используются в контейнере.
- env_file — указывает путь к файлу с переменными окружения. Можно задать несколько файлов.
env_file:
- .env
- db.envВ .env файле переменные записываются в формате ключ=значение:
APP_NAME=web_service
APP_PORT=80Если указано несколько файлов, они обрабатываются сверху вниз, и значения из последующих файлов могут переопределять переменные из предыдущих.
Если заданы оба атрибута environment и env_file, переменные из environment имеют более высокий приоритет.
- volumes — подключает хранилище данных к контейнеру. В качестве источника могут использоваться:
- bind mount (директория или файл на хосте);
- именованный том (Docker volume);
- временная файловая система (tmpfs).
- networks — определяет сети, к которым подключен контейнер.
- depends_on — устанавливает порядок запуска контейнеров. В нашем примере сервис nginx зависит от wordpress, а wordpress — от db. Сначала будет запущен сервис db, потом wordpress, потом nginx.
Volumes (тома)
Контейнер — это временная сущность, он может быть удален или пересоздан.
Чтобы хранить важные данные, например, базы данных или файлы сайта, используются тома — это постоянное хранилище данных, которое подключается к контейнеру как директория. Тома хранятся вне контейнера и не зависят от его состояния.
Использование томов решает несколько задач:
- сохраняет данные между перезапусками контейнера;
- позволяет разным контейнерам совместно использовать данные;
- позволяет хранить данные вне контейнера;
- упрощает резервное копирование и миграцию данных.
Важно не путать! В разделе services используется атрибут volumes.
Следует различать:
- раздел верхнего уровня volumes — объявляет тома.
- атрибут volumes внутри services — подключает их к контейнерам.
В нашем примере в разделе верхнего уровня volumes мы объявляем два именованных тома wp_data и db_data
volumes:
wp_data:
db_data:Docker сам создаёт именованные тома и управляет ими, а доступ к ним осуществляется по имени, а не через путь в файловой системе.
Именованные тома хранятся на хосте в директории /var/lib/docker/volumes/ (для Linux):
Имена директорий томов имеют вид <project>_<volume>. В нашем случае compose_db_data и compose_wp_data
Том wp_data подключен к контейнеру wordpress. Внутри контейнера данный том расположен по пути /var/www/html
volumes:
- wp_data:/var/www/htmlТом wp_data подключен также к контейнеру nginx:
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- wp_data:/var/www/htmlЗдесь:
- wp_data — именованный том.
./nginx.conf:/etc/nginx/nginx.conf:ro— bind mount.
Bind mount — это способ подключения файлов или директорий с хоста напрямую в контейнер.
В примере файл nginx.conf из директории проекта монтируется в контейнер по пути /etc/nginx/nginx.conf. Параметр ro означает, что файл доступен только для чтения.
Можно также подключать контейнеры к уже существующему тому, созданному ранее в другом compose-проекте или с помощью docker volume create. Для этого используется атрибут external: true
volumes:
data:
external: trueПодробнее об использовании томов в Docker Compose вы можете прочитать в статье документации. Об общих принципах работы томов рассказали в нашей статье.
Networks (сети)
Сети в Docker обеспечивают взаимодействие между контейнерами, позволяют изолировать сервисы и запускать несколько идентичных compose-проектов без конфликтов.
Тип сети можно указать через необязательный атрибут driver. Основные типы сетей:
- bridge — самый распространенный тип. Каждый контейнер получает собственный внутренний IP-адрес, уникальный в рамках одной сети. Работает встроенный DNS — если сервисы находятся в одной сети, они могут обращаться друг к другу по имени сервиса. Контейнеры имеют доступ к внешней сети через механизм NAT.
- host — контейнер работает напрямую через сеть хоста. В этом режиме проброс портов (ports) не используется, так как контейнер и хост фактически используют одну и ту же сеть.
- none
— контейнер запускается без сетевого подключения и не может взаимодействовать с другими контейнерами.
Если в compose-файле не указан раздел networks, Compose автоматически создаёт сеть <project>_default. Она является пользовательской сетью типа bridge. Все сервисы проекта, для которых явно не заданы другие сети, автоматически подключаются к данной сети.
Можно подключать контейнеры к уже существующей сети Docker с помощью атрибута external: true
networks:
mynetwork:
external: trueЭто нужно, когда:
- несколько compose-проектов должны общаться;
- контейнер должен видеть сервисы вне compose.
Также можно создать сеть, изолированную от внешней сети с помощью атрибута internal:true
В нашем примере создаются две сети: frontend и backend.
Сервис nginx подключён к обеим сетям. Порт 80 проброшен на хост, поэтому nginx принимает запросы из внешней сети.
Сервисы nginx, wordpress и db подключены к сети backend, через которую они взаимодействуют друг с другом. Сеть изолирована от внешней сети (internal: true)
Разделение на сети frontend и backend позволяет отделить точку входа приложения (nginx) от внутренней инфраструктуры (wordpress и db).
В сервисе wordpress мы задаем переменную окружения WORDPRESS_DB_HOST, в значении которой ссылаемся на сервис db по имени сервиса:
WORDPRESS_DB_HOST: db:3306Подробнее об использовании сетей в Docker Compose вы можете прочитать в документации.
Запуск проекта
- Создайте директорию проекта, если она еще не создана, и перейдите в нее:
mkdir compose
cd compose- Создайте файл
compose.yamlи вставьте код. - Создайте файл конфигурации
nginx.conf
events {}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name _;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
}
}- Запустите проект
docker compose up -d
Предупреждение WARN означает, что параметр version в файле compose.yml больше не используется в новых версиях Docker Compose.
Можем убедиться, что контейнеры запущены:

Введя IP-адрес сервера в строку браузера, видим начальную страницу установки WordPress:

Команды docker compose
Создание и запуск контейнеров проекта:
docker compose upЗапуск контейнеров в фоновом режиме:
docker compose up -dЗапуск конкретного сервиса:
docker compose up -d dbОстановка проекта:
docker compose downЗапуск\остановка\перезапуск контейнеров проекта:
docker compose start
docker compose stop
docker compose restart
docker compose start <имя_сервиса>
docker compose stop <имя_сервиса>
docker compose restart <имя_сервиса>Команда docker compose up используется для первичного запуска проекта. иОна выполняет несколько действий:
- создаёт сеть проекта;
- создаёт тома;
- создаёт контейнеры;
- скачивает образы (если их нет);
- запускает контейнеры.
Если контейнеры уже существуют, Compose проверит конфигурацию и при необходимости пересоздаст контейнеры.
Команда docker compose start используется для запуска уже созданных контейнеров.
Пересоздание контейнеров принудительно, даже если их конфигурация и образ не изменились:
docker compose up --force-recreateВывести список контейнеров проекта:
docker compose ps -aВ отличие от docker ps -a будут выведены только контейнеры текущего проекта.
Вывод логов проекта:
docker compose logsВывод логов отдельного сервиса (db):
docker compose logs dbПросмотр логов сервиса db в режиме реального времени
docker compose logs -f dbВывод списка томов:
docker compose volumesЛучшие практики
Минимализм
Compose-файл должен оставаться простым описанием инфраструктуры. Его не стоит перегружать сложной логикой или пытаться использовать как инструмент управления всей системой.
Не рекомендуется:
- добавлять сложные скрипты запуска внутри command или entrypoint;
- пытаться управлять порядком и состоянием сервисов через shell-скрипты;
- использовать Compose для оркестрации сложных сценариев развертывания.
Например ожидание базы через цикл в command:
services:
app:
image: myapp
command: >
sh -c "
until nc -z db 5432;
do echo waiting for db;
sleep 2;
done;
python app.py
"Если конфигурация содержит подобную логику управления, это признак того, что задача выходит за пределы возможностей Docker Compose и требует других инструментов.
Использование .env
Используйте файл .env для хранения переменных окружения, которые могут отличаться в разных средах (разработка, тестирование, рабочая среда). Тогда при переносе проекта на другой сервер или в другую среду достаточно заменить файл .env — основная конфигурация compose.yaml останется прежней.
Явные версии образов
Для надёжности лучше использовать конкретные версии образов. Использование специальных тегов (latest, stable и т.д.) может привести к несовместимости с компонентами приложения из-за изменения версии образа.
Разделение окружений
Используйте несколько compose-файлов. Это позволит разделить базовую инфраструктуру и настройки для отдельных сред.
Пример:
compose.yaml # базовая конфигурация
compose.dev.yaml # настройки для разработки
compose.prod.yaml # настройки для productionОтносительные пути
При использовании bind mount рекомендуется указывать относительные пути вместо абсолютных. Это позволяет запускать проект на разных серверах без изменения конфигурации.