Кратко
Скопировано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:
На собеседовании
Скопировано отвечает
СкопированоОбычно жизненный цикл контейнера состоит из следующей последовательности состояний:
- Создание контейнера
- Работа контейнера
- Приостановка контейнера
- Возобновление работы контейнера
- Запуск контейнера
- Остановка контейнера
- Перезапуск контейнера
- Принудительная остановка контейнера
- Удаление контейнера
На практике встречаются и более сложные случаи, поэтому жизненный цикл контейнера лучше представить с помощью диаграммы:
На этой диаграмме показаны не только состояния и пути перехода из одного состояния в другое, но и команды, которые позволяют пользователю их менять.