Кратко
СкопированоDocker Compose — это инструмент для запуска мультиконтейнерного приложения, которое не зависит от платформы и содержит все необходимые для работы технологии и библиотеки. Конфигурация такого приложения записывается в одном текстовом файле в формате YAML. Запускается приложение одной командой в терминале.
Как начать
СкопированоЕсли вы работаете на операционных системах Mac или Windows и установили Docker Desktop, то Docker Compose уже установлен автоматически. Если вы работаете на операционной системе семейства Linux, вам необходимо его установить, предварительно скачав последний релиз из репозитория. До установки убедитесь, что Docker Engine на Linux уже установлен и готов к работе (подробнее в статье «Что такое Docker?»). Процесс установки описан в официальной документации Docker.
Как понять
СкопированоРассмотрим мультиконтейнерное приложение на примере WordPress.
Можно создать один образ с установленной базой данных, веб-сервером, интерпретатором PHP и движком WordPress на борту. А можно сделать иначе.

Веб-приложение — это, как правило, сложная система взаимодействующих частей, которые называют сервисами. Команда разработчиков Docker рекомендует подход: один сервис — один контейнер. Этот подход позволяет легче отлавливать ошибки, проще модернизировать сервисы, избегать работы над всем приложением сразу. При большой нагрузке на отдельные сервисы такой подход упрощает масштабирование с помощью перераспределения сетевых запросов (маршрутизатор можно поместить в отдельный контейнер). Реализовать мониторинг и сформировать поток ошибок также можно с помощью отдельного сервиса, запущенного в контейнере. Совокупность описанных сервисов называется мультиконтейнерным приложением.
Вернёмся к примеру. Что нужно для запуска сайта на WordPress? В самом простом случае такое веб-приложение состоит из двух сервисов:
— веб-сервер с WordPress;
— база данных.
Оба контейнера должны работать совместно. Мы можем написать Dockerfile для каждого из них и настроить взаимодействие друг с другом через виртуальную сеть Docker Network. Но такой ручной подход не очень удобен. Docker Compose — это инструмент, который помогает конфигурировать запуск сразу нескольких контейнеров и указывать им, как работать совместно.
Docker Compose поддерживает файлы конфигурации в формате YAML. Имя файла конфигурации по умолчанию — compose.yaml. Для нашего примера такой файл мог бы выглядеть следующим образом (в качестве базы данных будем использовать MySQL):

compose.yaml
version: "3.9"
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: goodpassword
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
В первой строчке этого файла конфигурации содержится информация о версии формата описания. С каждой новой версией функциональность Docker Compose расширяется. Если раньше этот параметр был обязательным, то сейчас его можно не указывать, если не нужно поддерживать старую версию Docker Engine, смотрите таблицу соответствия версий формата описания и движка Docker.
В разделе services содержится описание всех контейнеров, запуск которых нужно настроить. Отдельно работающие приложения или службы в терминах Docker Compose называются сервисами.
В подразделе image необходимо указать имя образа, который должен присутствовать локально на компьютере или в реестре. Можно установить и переменные окружения в подразделе environment, порты для подключения к сервису (например, со стороны браузера) в подразделе ports, пути для монтирования томов в подразделе volumes и прочие параметры.
В различных базах данных, не только в MySQL, как у нас, существует возможность хранить данные в отдельном файле или папке. Логично было бы положить в отдельные файлы и данные нашего сайта на WordPress. Для таких задач используются тома (Docker Volumes). На самом деле — это отдельные образы дисков. Для приложения в контейнере они видны как примонтированные папки. Следовательно, когда используется том db_data, при остановке или перезапуске контейнера с MySQL все данные сохранятся. Ну а с контейнером с самим движком данные вообще никак не связаны.
Файл конфигурации готов, и можно «поднять» все контейнеры всего одной командой:
docker-compose up
docker-compose up
Когда все образы будут загружены, тома включены, переменные окружения установлены, сайт на WordPress окажется доступным по адресу http. В настройках compose указано, что если один из контейнеров упадёт, то Docker Compose должен перезапустить его автоматически (restart). Вы сможете начать с того же места. Появляется ещё одна возможность — можно обновить базу данных, и при следующем перезапуске запустится уже новая версия. То же самое можно делать и с веб-сервером, и движком.
Выключить оба контейнера так же просто, как и включить:
docker-compose down
docker-compose down
Вы можете подробнее посмотреть все команды Docker Compose CLI в официальной документации.
Как пишется
СкопированоПоскольку Docker Compose работает с несколькими типами объектов Docker (образами, контейнерами, томами), то логично представить их настройки в виде дерева в формате YAML, который очень часто используется в файлах конфигурации.
Если вы когда-нибудь писали на языке Python, YAML покажется вам очень понятным. Каждый новый блок отделяется отступами. Блоки могут быть вложенными, что очень удобно, и зрительно воспринимается намного легче, чем, скажем, JSON. Несомненным плюсом является популярность YAML среди специалистов по инфраструктуре.
Предпочтительное расположение файла compose.yaml — корневая папка проекта, которая может содержать подпапки с сервисами мультиконтейнерного приложения. Для обеспечения обратной совместимости поддерживаются файлы с именами docker-compose.yaml и docker-compose.yml.
В файле compose.yaml могут быть следующие элементы верхнего уровня:
— version (скоро исключат): информация о версии формата файла конфигурации;
— services (обязательный): список всех контейнеров, которые нужно будет запустить;
— networks: список подсетей Docker Network, которые объединяют группы контейнеров в виртуальную локальную сеть (она может быть доступна из внешнего мира);
— volumes: список томов, которые будут доступны контейнерам, описанным в файле конфигурации;
— configs: список параметров, которые позволяют запускать контейнеры в различных режимах, не собирая их заново;
— secrets: список чувствительных с точки зрения безопасности параметров (то же, что и configs, но специального назначения).
Services
СкопированоМультиконтейнерное приложение — система взаимодействующих сервисов. Как правило, один сервис обеспечивает какую-то одну функцию системы. Например, веб-сервер только отдаёт статический сайт (HTML, CSS и JS) браузеру, API служит для обмена данными. Сервисы — это самостоятельные (атомарные) микроприложения или службы, работающие независимо в отдельных контейнерах.
Docker Compose — это инструмент, который не только автоматически запускает или останавливает контейнеры, но и поддерживает их жизненный цикл, обеспечивает совместное использование ресурсов.
Разрабатывая мультиконтейнерное приложение, в голове нужно держать мысль о перспективах его масштабирования и поддержки. Например, один веб-сервер со статическим сайтом может обеспечить тысячу пользователей одновременно. А что, если пользователей больше? Docker Compose в этом случае будет автоматически использовать дополнительные экземпляры сервиса, перенаправляя запросы к ним.
Например, мы запускаем два сервиса, frontend и backend:
services: frontend: image: awesome/webapp build: ./webapp deploy: mode: replicated replicas: 6 backend: image: awesome/database build: context: backend dockerfile: ../backend.Dockerfile deploy: resources: limits: cpus: '0.50' memory: 50M reservations: cpus: '0.25' memory: 20M
services:
frontend:
image: awesome/webapp
build: ./webapp
deploy:
mode: replicated
replicas: 6
backend:
image: awesome/database
build:
context: backend
dockerfile: ../backend.Dockerfile
deploy:
resources:
limits:
cpus: '0.50'
memory: 50M
reservations:
cpus: '0.25'
memory: 20M
Скажем, нам нужно обеспечить до шести экземпляров сервиса frontend, ресурсы для которого будут расходоваться, пока они будут доступны. Тогда мы указываем это явно, как сделано в примере выше, с помощью настроек mode и replicas для элемента deploy. Настроек для развёртывания сервиса (запуска, использования ресурсов процессора, памяти и прочее) очень много.
Сборка сервиса frontend описывается отдельно от параметров развёртывания. В нашем случае она будет производиться из папки ./webapp с помощью файла с именем по умолчанию Dockerfile.
Для backend — другие настройки. Нам нужно собрать образ перед тем, как мы будем использовать приложение. Настройка context будет содержать относительный путь к папке сервиса. Вариантов сборки образа несколько, но наш будет описываться в файле backend.Dockerfile. А ещё будут требования к ресурсам, которые использует приложение. Docker Compose:
- будет использовать процессор не более чем на 50% в штатном режиме, и не более 75% в пиковых нагрузках;
- сервис будет использовать не более чем 50 МБ оперативной памяти и 70 МБ в пике.
Подробнее про настройки сборки вы можете почитать в спецификации здесь, а про настройки развёртывания контейнеров здесь.
Networks
СкопированоПараметры, описанные в элементе networks, позволяют настроить виртуальную сеть Docker Network для совместной работы нескольких контейнеров. Например, можно указать две подсети, одна из которых, back-tier, будет обеспечивать прямую связь между frontend и backend, в то время как другая, front-tier, будет связывать frontend с внешним миром. В файле конфигурации это можно записать так:
services: frontend: image: awesome/webapp networks: - front-tier - back-tier backend: image: awesome/database networks: - back-tiernetworks: front-tier: external: true name: host back-tier:
services:
frontend:
image: awesome/webapp
networks:
- front-tier
- back-tier
backend:
image: awesome/database
networks:
- back-tier
networks:
front-tier:
external: true
name: host
back-tier:
Volumes
СкопированоС помощью Docker Compose вы можете использовать тома Docker Volume для хранения данных. Например, нужно обеспечить работу базы данных, расположенную в отдельной папке в томе. Проще всего это сделать следующим образом:
services: backend: image: awesome/database volumes: - db-data:/etc/datavolumes: db-data:
services:
backend:
image: awesome/database
volumes:
- db-data:/etc/data
volumes:
db-data:
Подробная спецификация элементов описана в отдельном репозитории.
На практике
Скопированосоветует
Скопировано🛠 Вы можете поискать подходящие образы на GitHub. Есть, например, целый каталог наиболее удачных: Awesome Compose.
Использование терминальных команд
СкопированоНа этапе сборки образа можно передать аргументы командной строки, а также выполнить произвольные команды по окончании сборки. Иногда это бывает крайне полезно. Например, вы хотите после сборки образа сделать паузу, в течение которой можно будет подождать какой-то процесс или посмотреть вывод в терминал результатов работы программы. В этом случае можно использовать элемент command:
version: "3.9"services: phys-website: env_file: ./.env command: /bin/sh -c "while sleep 1000; do :; done" build: context: ./ args: USER_NAME: ${NAME} USER_EMAIL: ${EMAIL}
version: "3.9"
services:
phys-website:
env_file: ./.env
command: /bin/sh -c "while sleep 1000; do :; done"
build:
context: ./
args:
USER_NAME: ${NAME}
USER_EMAIL: ${EMAIL}
В примере также описываются аргументы командной строки, которые будут использоваться в Dockerfile и могут передаваться на этапе сборки образа командой:
docker-compose build --build-arg NAME="John Doe" --build-arg EMAIL=john@light.org
docker-compose build --build-arg NAME="John Doe" --build-arg EMAIL=john@light.org
Приложение на стеке MERN
СкопированоMERN — это аббревиатура от MongoDB, Express, React, Node.js. С помощью Docker Compose можно легко реализовать фулстек-приложение. MERN является одним из популярных решений. Оно объединяет веб-сервер, базу данных и фреймворки для бэкенда и фронтенда.
Обычно структура папок MERN-проекта выглядит следующим образом:
. ├── backend │ ├── Dockerfile │ ... ├── compose.yaml ├── frontend │ ├── ... │ └── Dockerfile └── README.md
Файл конфигурации compose.yaml можно сделать так:
services: frontend: build: frontend ports: - 3000:3000 stdin_open: true volumes: - ./frontend:/usr/src/app - /usr/src/app/node_modules container_name: frontend restart: always networks: - react-express depends_on: - backend backend: container_name: backend restart: always build: backend volumes: - ./backend:/usr/src/app - /usr/src/app/node_modules depends_on: - mongo networks: - express-mongo - react-express mongo: container_name: mongo restart: always image: mongo:4.2.0 volumes: - ./data:/data/db networks: - express-mongonetworks: react-express: express-mongo:
services:
frontend:
build: frontend
ports:
- 3000:3000
stdin_open: true
volumes:
- ./frontend:/usr/src/app
- /usr/src/app/node_modules
container_name: frontend
restart: always
networks:
- react-express
depends_on:
- backend
backend:
container_name: backend
restart: always
build: backend
volumes:
- ./backend:/usr/src/app
- /usr/src/app/node_modules
depends_on:
- mongo
networks:
- express-mongo
- react-express
mongo:
container_name: mongo
restart: always
image: mongo:4.2.0
volumes:
- ./data:/data/db
networks:
- express-mongo
networks:
react-express:
express-mongo:
На собеседовании
Скопировано отвечает
СкопированоОбычно жизненный цикл контейнера состоит из следующей последовательности состояний:
- Создание контейнера
- Работа контейнера
- Приостановка контейнера
- Возобновление работы контейнера
- Запуск контейнера
- Остановка контейнера
- Перезапуск контейнера
- Принудительная остановка контейнера
- Удаление контейнера
На практике встречаются и более сложные случаи, поэтому жизненный цикл контейнера лучше представить с помощью диаграммы:

На этой диаграмме показаны не только состояния и пути перехода из одного состояния в другое, но и команды, которые позволяют пользователю их менять.