Как использовать Docker Compose: структура файла docker-compose.yml
Docker Compose — это инструмент в составе Docker для запуска нескольких связанных контейнеров одной командой. Вместо того чтобы собирать каждый сервис по отдельности через docker build, а потом запускать через docker run, вы описываете всю конфигурацию в одном файле docker-compose.yml и управляете всеми контейнерами одновременно.
В этом руководстве мы разберём только базовую структуру файла и ключевые секции docker-compose.yml. Сети, расширенные тома и секреты будут рассмотрены в следующих материалах сайта. Для сборки образов мы будем использовать Dockerfile из прошлого урока.
Создание файла docker-compose.yml и описание структуры
docker-compose.yml — это обычный текстовый файл с расширением .yml (или .yaml), в котором описывается конфигурация контейнеров.
Хорошей практикой считается создавать его в корневой директории проекта. Для этого перейдите в папку с проектом и создайте пустой файл:
touch docker-compose.ymlБазовая структура файла состоит из трёх верхнеуровневых секций:
services:
service1:
# настройки сервиса 1
service2:
# настройки сервиса 2
networks:
# (опционально) кастомные сети
volumes:
# (опционально) именованные тома^O Записать ^X ВыходСтруктура секции services в docker-compose.yml
Обязательный блок services описывает все контейнеры (сервисы), из которого будет состоять будущее приложение. В нем задаются параметры запуска: какой образ использовать, какие порты открыть, какие переменные окружения передать и даже как сервисы должны взаимодействовать друг с другом.
Пример базовой структуры:
services:
python:
image: ... # образ или сборка
ports: ... # сетевые настройки
environment: ... # переменные окружения
depends_on: ... # порядок запуска
healthcheck: ... # здоровье и отладка
user: ... # дополнительные параметры
db:
image: ...
volumes: ... # хранение данных
restart: ... # поведение контейнера
tty: ... # здоровье и отладка
group_add: ... # дополнительные параметры^O Записать ^X ВыходИмена python и db — произвольные. Вы можете назвать сервисы как угодно, но хорошей практикой считается использование понятных имен, отражающих их роль (например, web, database, cache).
Детализация секции services в docker-compose.yml
К основным параметрам относятся:
services:
python:
build: ./app
container_name: my-python-app
db:
image: postgres:16-alpine^O Записать ^X ВыходВ сетевые настройки входят:
services:
python:
build: ./app
ports:
- "8000:8000"
networks:
- frontend
db:
image: postgres:16-alpine
networks:
- backend
networks:
backend:
frontend:^O Записать ^X ВыходВ примере: сервис python подключен к сети frontend, а сервис db — к сети backend. Поскольку это разные изолированные сети, контейнеры не видят друг друга и не смогут взаимодействовать.
Настройки томов (или volumes) нужны для сохранения данных контейнера между перезапусками. Например, чтобы база данных не теряла информацию при остановке или обновлении. Именованные тома должны быть объявлены в корневой секции volumes файла docker-compose.yml.
services:
db:
image: postgres:16-alpine
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:^O Записать ^X ВыходВ этом примере том db-data монтируется в директорию /var/lib/postgresql/data, где PostgreSQL хранит свои файлы. При удалении и повторном создании контейнера данные сохранятся.
Секция volumes в корне файла нужна, чтобы объявить именованные тома. Без этого объявления Docker Compose не создаст том и выдаст ошибку при запуске.
Позволяют менять поведение приложения без изменения файлов проекта и пересборки образа. Например, задать пароль от базы данных или часовой пояс.
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: mysecretpassword
TZ: Europe/Moscow^O Записать ^X Выходservices:
db:
image: postgres:16-alpine
env_file:
- .env^O Записать ^X ВыходСодержимое файла .env:
POSTGRES_PASSWORD=mysecretpassword
TZ=Europe/Moscow^O Записать ^X ВыходОба способа дают одинаковый результат. Разница только в том, где хранятся значения: внутри docker-compose.yml или в отдельном файле.
Порядок запуска сервисов (depends_on) — определяет, должен ли сервис запускаться только после старта других контейнеров. Это нужно, когда одно приложение зависит от другого (например, веб-сервер не может работать без базы данных).
services:
python:
build: ./app
depends_on:
- db
db:
image: postgres:16-alpine^O Записать ^X ВыходВ этом примере Docker Compose сначала запустит сервис db, и только после создания его контейнера начнёт запуск сервиса python.
Настройка depends_on гарантирует только порядок запуска контейнеров, но не проверяет, готов ли сервис к работе.
Эти параметры управляют жизненным циклом контейнера и тем, что в нем будет запущено.
services:
db:
image: postgres:16-alpine
restart: unless-stopped^O Записать ^X ВыходЗначение unless-stopped означает: «перезапускай контейнер всегда, кроме случая, когда я остановил его вручную через docker compose stop». Это самый универсальный вариант: сервис переживёт и сбой, и перезагрузку хоста, но останется выключенным, если вы намеренно его остановили.
services:
hello-python:
build: ./app
command: ["python", "hello_v2.py"]^O Записать ^X ВыходВ примере, мы переопределяем запуск команды CMD с прошлого урока по Dockerfile, в котором была инструкция:
CMD ["python", "hello.py"]^O Записать ^X ВыходПри запуске контейнера выполнится именно hello_v2.py. Файл hello.py останется в образе, но запущен не будет. Если убрать строку command из docker-compose.yml, снова сработает оригинальная команда из Dockerfile.
В этом блоке описываются настройки для проверки работоспособности контейнера и включения интерактивного режима отладки. К ним относятся:
services:
hello-python:
build: ./app
healthcheck:
test: ["CMD-SHELL", "python -c 'print(\"ok\")'"]
interval: 10s
timeout: 5s
retries: 5^O Записать ^X Выходservices:
python:
build: ./app
tty: true
stdin_open: true^O Записать ^X ВыходЭти настройки используются для решения специфичных задач при конфигурации сервиса.
services:
python:
build: ./app
user: "1000:1000"^O Записать ^X Выходservices:
zigbee2mqtt:
image: koenkk/zigbee2mqtt
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
group_add:
- dialout^O Записать ^X Выходservices:
python:
build: ./app
working_dir: /app/src^O Записать ^X ВыходЗапуск docker-compose.yml с использованием build для Python-скрипта
Перейдём к практике и заполним docker-compose.yml реальными настройками. Возьмём Dockerfile и Python-скрипт из прошлого урока и поместим их в отдельную директорию app:
mkdir app && mv hello.py Dockerfile ./app/Проверим, что файлы Dockerfile и Python-скрипт появились в правильной директории.

Вернемся в корневую директорую проекта и отредактируем файл docker-compose.yml:
nano docker-compose.ymlОпишем новый сервис hello-python. Имя выбираем произвольно, а сборку укажем из Dockerfile в подпапке app:
services:
hello-python:
build: ./app^O Записать ^X ВыходВ этом примере мы используем только инструкцию build, потому что наша цель — это посмотреть как работает механизм сборки и запуска Python-скрипта через Docker Compose. Остальные параметры (порты, переменные окружения, тома) здесь не нужны: скрипт просто выводит текст в консоль и завершает работу.
Повторно убедимся, что docker-compose.yml находится в корне проекта, а Dockerfile и скрипт — в подпапке app:

Теперь запустим проект. Флаг —build указывает Docker Compose пересобрать образ перед запуском, даже если он уже существует. Без этого флага Docker может использовать старую версию образа из кэша, и изменения в коде или Dockerfile не применятся.
docker compose up --buildПосле выполнения команды начнётся сборка образа. В выводе вы увидите статусы Built (образ собран) и Created (контейнер создан).

Эта команда запустит контейнер в активном режиме (foreground) и терминал «зависнет», выводя логи в реальном времени. Поскольку наш Python-скрипт просто печатает «Hello world» и завершается, контейнер остановится с кодом 0 (exited with code 0). Это нормально: нет бесконечного цикла — нет работающего процесса.
У docker compose up есть два режима работы:
Пример фонового запуска:
docker compose up -d --buildДля управления фоновыми контейнерами используются отдельные команды:
docker compose logs -fdocker compose stopdocker compose startdocker compose downВ этой статье мы запускали только одноразовый скрипт, поэтому фоновый режим не требовался. Если требуется поднимать веб-серверы и базы данных, флаг -d станет основным способом запуска.
Итоги: структура docker-compose.yml и базовый запуск
В этом статье было разобрано, как устроен файл docker-compose.yml. Мы увидели, что базовая конфигурация строится вокруг обязательного блока services, где каждый сервис описывается через набор параметров: build или image для указания образа, ports для доступа извне, volumes для сохранения данных и environment для настроек приложения. Такая декларативная структура позволяет управлять всеми контейнерами приложения из одного места.
Научились заполнять эту структуру минимальными настройками и запускать сборку через docker compose up —build. В следующем материале мы углубимся в работу с сетями, переменными окружения и зависимостями между сервисами. А чуть позже — научимся сохранять данные с помощью томов (volumes), чтобы они не терялись при перезапуске контейнеров.
