Как использовать 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), в котором описывается конфигурация контейнеров.

Хорошей практикой считается создавать его в корневой директории проекта. Для этого перейдите в папку с проектом и создайте пустой файл:

Terminal
Copy

Базовая структура файла состоит из трёх верхнеуровневых секций:

docker-compose.yml
Copy

  • services:
    Обязательная первая секция. Содержит описание всех контейнеров приложения.
  • networks:
    Секция с настройками изоляции и взаимодействия между сервисами.
  • volumes: 
    Так называемые тома. Это механизм хранения данных вне контейнера. Без томов все данные внутри контейнера удаляются при удалении самого контейнера (например, после команды docker-compose down). Тома позволяют сохранять базы данных, конфигурации и другие важные файлы между перезапусками и обновлениями.

Структура секции services в docker-compose.yml

Обязательный блок services описывает все контейнеры (сервисы), из которого будет состоять будущее приложение. В нем задаются параметры запуска: какой образ использовать, какие порты открыть, какие переменные окружения передать и даже как сервисы должны взаимодействовать друг с другом.

Пример базовой структуры:

docker-compose.yml
Copy

Имена python и db — произвольные. Вы можете назвать сервисы как угодно, но хорошей практикой считается использование понятных имен, отражающих их роль (например, web, database, cache).

Детализация секции services в docker-compose.yml

К основным параметрам относятся:

  • image — указывает готовый образ из реестра (например, Docker Hub), из которого будет создан контейнер.
  • build — путь к директории с Dockerfile для сборки собственного образа.
  • container_name — задаёт ваше произвольное фиксированное имя контейнера вместо автоматически генерируемого. Используется редко, так как ограничивает возможность запуска нескольких копий сервиса.
docker-compose.yml
Copy

В сетевые настройки входят:

  • ports — публикует порт контейнера на хосте. Приложение становится доступным по IP-адресу сервера или доменному имени (например, для открытия сайта в браузере или подключения к базе данных). Без настройки порта сервис будет работать только внутри Docker без доступа извне.
  • networks — создает изолированную сеть для общения между контейнерами. По умолчанию все сервисы в одном docker-compose.yml уже видят друг друга. Настройка нужна чтобы выделить сервисы, которые не должны взаимодействовать с остальными. Чтобы сеть работала — нужно обязательно объявить в корневой секции networks.
docker-compose.yml
Copy

В примере: сервис python подключен к сети frontend, а сервис db — к сети backend. Поскольку это разные изолированные сети, контейнеры не видят друг друга и не смогут взаимодействовать.

Настройки томов (или volumes) нужны для сохранения данных контейнера между перезапусками. Например, чтобы база данных не теряла информацию при остановке или обновлении. Именованные тома должны быть объявлены в корневой секции volumes файла docker-compose.yml.

docker-compose.yml
Copy

В этом примере том db-data монтируется в директорию /var/lib/postgresql/data, где PostgreSQL хранит свои файлы. При удалении и повторном создании контейнера данные сохранятся.

Секция volumes в корне файла нужна, чтобы объявить именованные тома. Без этого объявления Docker Compose не создаст том и выдаст ошибку при запуске.

Позволяют менять поведение приложения без изменения файлов проекта и пересборки образа. Например, задать пароль от базы данных или часовой пояс.

  • environment — задаёт переменные напрямую в файле docker-compose.yml. Применимо для небольшого количества настроек.
docker-compose.yml
Copy

  • env_file — это тот же environment, который вынесен во внешний файл с расширением .env. Используется, когда переменных много или они содержат чувствительные данные (пароли, ключи), которые нельзя оставлять в основном конфигурационном файле.
docker-compose.yml
Copy

Содержимое файла .env:

.env
Copy

Оба способа дают одинаковый результат. Разница только в том, где хранятся значения: внутри docker-compose.yml или в отдельном файле.

Порядок запуска сервисов (depends_on) — определяет, должен ли сервис запускаться только после старта других контейнеров. Это нужно, когда одно приложение зависит от другого (например, веб-сервер не может работать без базы данных).

docker-compose.yml
Copy

В этом примере Docker Compose сначала запустит сервис db, и только после создания его контейнера начнёт запуск сервиса python.

Настройка depends_on гарантирует только порядок запуска контейнеров, но не проверяет, готов ли сервис к работе.

Эти параметры управляют жизненным циклом контейнера и тем, что в нем будет запущено.

  • restart — определяет, что делать с контейнером после остановки или сбоя. Без этой настройки контейнер не запустится автоматически ни при ошибке приложения, ни после перезагрузки сервера.
docker-compose.yml
Copy

Значение unless-stopped означает: «перезапускай контейнер всегда, кроме случая, когда я остановил его вручную через docker compose stop». Это самый универсальный вариант: сервис переживёт и сбой, и перезагрузку хоста, но останется выключенным, если вы намеренно его остановили.

  • command — заменяет команду CMD, заданную в Dockerfile. Нужно, когда вы используете один и тот же образ для разных задач или хотите запустить другой скрипт без пересборки.
docker-compose.yml
Copy

В примере, мы переопределяем запуск команды CMD с прошлого урока по Dockerfile, в котором была инструкция:

Dockerfile
Copy

При запуске контейнера выполнится именно hello_v2.py. Файл hello.py останется в образе, но запущен не будет. Если убрать строку command из docker-compose.yml, снова сработает оригинальная команда из Dockerfile.

В этом блоке описываются настройки для проверки работоспособности контейнера и включения интерактивного режима отладки. К ним относятся: 

  • healthcheck — команда Docker, которая время от времени выполняется внутри контейнера, чтобы отслеживать, что приложение работает. Если проверка не проходит, контейнер помечается как «неживой» (unhealthy). Хорошо работает в связке с порядком запуска depends_on.
docker-compose.yml
Copy

  • tty и stdin_open — включают интерактивный режим для контейнера. Аналог флага -it в команде docker run. После запуска контейнера можно ввести в терминале команду docker compose exec и работать в нём как в обычном терминале (писать код и сразу его выполнять).
docker-compose.yml
Copy

Эти настройки используются для решения специфичных задач при конфигурации сервиса.

  • user — задаёт пользователя, от имени которого запускается процесс внутри контейнера. По умолчанию это root, что может быть небезопасно для продакшена.
docker-compose.yml
Copy

  • group_add — даёт контейнеру права на доступ к устройствам хоста (например, USB-координатору Zigbee). Настройка нужна из-за особенности работы подключаемых устройств в Linux: взаимодействовать с ними может только пользователь, который входит в группу dialout. Поэтому, чтобы контейнер мог работать с устройством, его нужно добавить в соответствующую группу.
docker-compose.yml
Copy

  • working_dir — устанавливает рабочую директорию внутри контейнера. Аналог инструкции WORKDIR в Dockerfile. Используется, когда нужно переопределить путь по умолчанию без пересборки образа.
docker-compose.yml
Copy

Запуск docker-compose.yml с использованием build для Python-скрипта

Перейдём к практике и заполним docker-compose.yml реальными настройками. Возьмём Dockerfile и Python-скрипт из прошлого урока и поместим их в отдельную директорию app:

Terminal
Copy

Проверим, что файлы Dockerfile и Python-скрипт появились в правильной директории.

Структура проекта docker_projects с подпапкой app и файлами Dockerfile hello.py
В директории проекта docker_projects создана подпапка app, куда были перемещены Dockerfile и hello.py

Вернемся в корневую директорую проекта и отредактируем файл docker-compose.yml:

Terminal
Copy

Опишем новый сервис hello-python. Имя выбираем произвольно, а сборку укажем из Dockerfile в подпапке app:

docker-compose.yml
Copy

В этом примере мы используем только инструкцию build, потому что наша цель — это посмотреть как работает механизм сборки и запуска Python-скрипта через Docker Compose. Остальные параметры (порты, переменные окружения, тома) здесь не нужны: скрипт просто выводит текст в консоль и завершает работу.

Повторно убедимся, что docker-compose.yml находится в корне проекта, а Dockerfile и скрипт — в подпапке app:

Структура проекта с docker-compose.yml в корне и папкой app
В директории проекта лежит файл сборки и подпапка с Dockerfile и python-скриптом

Теперь запустим проект. Флаг —build указывает Docker Compose пересобрать образ перед запуском, даже если он уже существует. Без этого флага Docker может использовать старую версию образа из кэша, и изменения в коде или Dockerfile не применятся.

Terminal
Copy

После выполнения команды начнётся сборка образа. В выводе вы увидите статусы Built (образ собран) и Created (контейнер создан).

Запуск контейнера через Docker Compose с выводом Hello World и кодом выхода 0
Запуск docker-compose.yml и вывод python-команды из файла .py

Эта команда запустит контейнер в активном режиме (foreground) и терминал «зависнет», выводя логи в реальном времени. Поскольку наш Python-скрипт просто печатает «Hello world» и завершается, контейнер остановится с кодом 0 (exited with code 0). Это нормально: нет бесконечного цикла — нет работающего процесса.

У docker compose up есть два режима работы:

  • Активный режим (по умолчанию) — терминал «зависает», а контейнеры работают в активном режиме и вы сможете видеть логи прямо в консоли. Для остановки этого режима — нажмите Ctrl + C. Это остановит контейнеры, но не удалит их: при следующем docker compose up они запустятся снова без пересборки.
  • Фоновый режим (-d / --detach) — единственный практичный способ оставить сервисы работать и «уйти». Без -d вы рано или поздно нажмёте Ctrl + C, чтобы вернуть управление терминалом, и контейнеры остановятся. Фоновый режим — это единственный способ запустить веб-сервер или базу данных и продолжить работу в терминале.

Пример фонового запуска:

Terminal
Copy

Для управления фоновыми контейнерами используются отдельные команды:

  • Посмотреть логи в реальном времени:
Terminal
Copy

  • Остановить контейнеры без удаления (аналог Ctrl + C для фонового режима).
Terminal
Copy

  • Запустить ранее остановленные контейнеры без пересборки:
Terminal
Copy

  • Остановить и удалить контейнеры, сети и тома. Используйте аккуратно: если в docker-compose.yml указана политика unless-stopped, после down она перестанет работать.
Terminal
Copy

В этой статье мы запускали только одноразовый скрипт, поэтому фоновый режим не требовался. Если требуется поднимать веб-серверы и базы данных, флаг -d станет основным способом запуска.

Итоги: структура docker-compose.yml и базовый запуск

В этом статье было разобрано, как устроен файл docker-compose.yml. Мы увидели, что базовая конфигурация строится вокруг обязательного блока services, где каждый сервис описывается через набор параметров: build или image для указания образа, ports для доступа извне, volumes для сохранения данных и environment для настроек приложения. Такая декларативная структура позволяет управлять всеми контейнерами приложения из одного места.

Научились заполнять эту структуру минимальными настройками и запускать сборку через docker compose up —build. В следующем материале мы углубимся в работу с сетями, переменными окружения и зависимостями между сервисами. А чуть позже — научимся сохранять данные с помощью томов (volumes), чтобы они не терялись при перезапуске контейнеров.

FAQ. Вопросы и ответы

Только если вы используете именованные тома или кастомные сети внутри секции services. Если вы указываете анонимные тома (только путь) и используете сеть по умолчанию, объявление в корне не требуется.

Docker Compose кэширует собранный ранее образ. Если вы изменили код или Dockerfile и запустили docker compose up без флага --build, будет использована старая закэшированная версия. Чтобы применить изменения, используйте docker compose up --build или предварительно выполните docker compose build.

Нет, один файл docker-compose.yml описывает только один проект. Docker Compose использует имя директории, где лежит этот файл, как префикс для всех контейнеров, сетей и томов. Если вы попытаетесь запустить два разных приложения из одной папки, они начнут конфликтовать: контейнеры перезапишут друг друга, а данные могут смешаться. Для каждого отдельного приложения создавайте свою директорию со своим файлом docker-compose.yml.

depends_on гарантирует только порядок запуска контейнеров, но не проверяет, готов ли сервис к работе (база данных может ещё инициализироваться). healthcheck периодически выполняет команду внутри контейнера и помечает его как «здоровый» только когда приложение реально отвечает.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *