Run multiple services in a container
A container’s main running process is the ENTRYPOINT and/or CMD at the end of the Dockerfile . It is generally recommended that you separate areas of concern by using one service per container. That service may fork into multiple processes (for example, Apache web server starts multiple worker processes). It’s ok to have multiple processes, but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application. You can connect multiple containers using user-defined networks and shared volumes.
The container’s main process is responsible for managing all processes that it starts. In some cases, the main process isn’t well-designed, and doesn’t handle “reaping” (stopping) child processes gracefully when the container exits. If your process falls into this category, you can use the —init option when you run the container. The —init flag inserts a tiny init-process into the container as the main process, and handles reaping of all processes when the container exits. Handling such processes this way is superior to using a full-fledged init process such as sysvinit , upstart , or systemd to handle process lifecycle within your container.
If you need to run more than one service within a container, you can accomplish this in a few different ways.
Put all of your commands in a wrapper script, complete with testing and debugging information. Run the wrapper script as your CMD . This is a very naive example. First, the wrapper script:
Next, the Dockerfile:
If you have one main process that needs to start first and stay running but you temporarily need to run some other processes (perhaps to interact with the main process) then you can use bash’s job control to facilitate that. First, the wrapper script:
Sorry, you have been blocked
This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.
What can I do to resolve this?
You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.
Cloudflare Ray ID: 7a2676436fa22de8 • Your IP: Click to reveal 88.135.219.175 • Performance & security by Cloudflare
Использование Docker для чайников
В одной из прошлых статей мы рассматривали как запустить контейнер Docker из образа. Основная идея Docker в том, что для каждого отдельного процесса должен быть создан отдельный контейнер Docker с окружением, нужным этому процессу. Но для сложных приложений здесь кроется проблема.
Например, для веб-приложения уже нужна база данных, веб-сервер, и возможно ещё интерпретатор PHP. Это уже три контейнера, настраивать и запускать их вручную не удобно, поэтому была придумана утилита docker-compose, которая позволяет управлять группами контейнеров, создавать их, настраивать, а также удалять одной командой. В этой статье мы разберемся как пользоваться docker для чайников. Подробно рассмотрим docker-compose, а также реальное применение утилиты.
Использование Docker для чайников
Поскольку эта инструкция про Docker для начинающих, я рекомендую сразу прочитать статью про запуск контейнера, вы поймете некоторые основы Docker, которые могут здесь вам пригодится. Там рассказано как всё делать вручную, а здесь мы уже поговорим как автоматизировать этот процесс.
1. Установка docker-compose
Если программа ещё не установлена, её необходимо установить. Для этого надо просто скачать исполняемый файл из официального сайта разработчиков:
sudo curl -L «https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)» -o /usr/local/bin/docker-compose
И дать ему права на выполнение:
sudo chmod +x /usr/local/bin/docker-compose
После этого вы сможете посмотреть её версию:
2. Создание проекта
Если вы уже видели проекты, использующие docker, то, наверное, замечали, что в папке с проектом лежит файл под названием docker-compose.yaml. Именно в этом файле настраиваются контейнеры, которые надо создать для вашего проекта, потом они будут созданы автоматически с помощью docker-compose. Файл использует синтаксис YAML и должен содержать такие данные:
Версия указывает на версию синтаксиса файла, в разных версиях доступны разные ключевые слова, это сделано для обратной совместимости. Мы будем использовать версию 3.5. Далее нужно перечислить хранилища (volumes), сети (networks) и сами контейнеры.
Синтаксис YAML похож на JSON, здесь тоже есть пары ключ: значение, разделенные двоеточием, только тут значение может быть вообще нулевым, может содержать другие ключи, а также оно может быть массивом значений, тогда каждый элемент массива начинается с чёрточки «-«. Но в отличие от JSON, здесь очень важны отступы, чтобы показать вложенность значений, поэтому не теряйте их.
Давайте создадим папку losst-docker и создадим в ней файл docker-compose.yaml:
version: ‘3.5’ services:

3. Добавление контейнеров
Рассмотрим содержимое самого простого пункта настройки контейнера:
Здесь нам обязательно надо указать имя будущего контейнера, а также образ, на основании которого он будет создан. Через двоеточие можно указывать версию контейнера. Версии можно посмотреть на Dockerhub они там отмечены как tags. Если версия не указана используется latest, последняя.
Например, добавим контейнер для веб-сервера Nginx:

Уже имея эти данные в конфигурационном файле можно запускать контейнер.
4. Запуск контейнеров
Когда настройка docker завершена, надо запускать полученные контейнеры. Чтобы запустить группу контейнеров, настроенную в docker-compose.yaml необходимо перейти в папку, где находится этот файл конфигурации и выполнить там команду docker-compose up. Например:

После этого контейнеры будут запущены, все их потоки вывода будут объединены в один и вам будет выводится информация в терминал. Чтобы остановить контейнеры достаточно нажать Ctrl+C. Если вы хотите запустить контейнеры в фоновом режиме используйте опцию -d:
docker-compose up -d

Остановить контейнеры, запущенные в фоновом режиме можно командой stop:
Команда down не просто останавливает все запущенные контейнеры, но и удаляет их:

Остановите пока этот контейнер, мы продолжим его настройку.
5. Порты контейнера
Контейнер работает, но толку пока нам от него мало. С помощью docker мы можем пробросить порт 80 контейнера в основную операционную систему и получить к нему доступ. Для этого используйте директиву ports. Синтаксис такой:
ports: — внешний_порт : внутренний порт
Например, пробросим порт 80 как 8094:

Теперь вы можете перезапустить контейнеры и увидеть в браузере страницу, сообщающую о том, что Nginx работает по адресу http://localhost:8094:

Но это все ещё не интересно, потому что мы не можем размещать там свои файлы. Сейчас это исправим.
6. Монтирование папок
Для монтирования хранилищ или внешних папок хоста используется пункт volumes. Синтаксис очень похож на работу с портами:
volumes: — /путь/к/внешней/папке : /путь/к/внутренней/папке
Например, давайте создадим в текущей папке проекта файл index.html и смонтируем эту папку вместо папки /usr/share/nginx/html/ контейнера:

После перезапуска контейнера вы увидите в браузере уже свою страницу. Это очень мощный инструмент, с помощью которого вы можете пробрасывать в контейнер всё, начиная от исходников и заканчивая конфигурационными файлами. Очень удобно.

7. Настройка хранилищ
Мы можем монтировать к контейнеру не только внешние папки, но и хранилища, создаваемые в docker. Для этого сначала надо добавить хранилище в главную секцию volumes. Например losst-vl:
Большинству веб приложений необходима база данных, например, MySQL. Добавим ещё один контейнер для этой базы данных и добавим в него наше хранилище. Хранилище добавляется также, как и внешняя папка, только вместо папки указывается название хранилища:

Здесь мы ещё добавили пункт environment, в котором задали переменные окружения для контейнера. Они необходимы, для того, чтобы указать имя базы данных и пароль root, которые будут использоваться по умолчанию. Как видите, с переменными окружения нет ничего сложного.

8. Настройка сети
Контейнеры должны взаимодействовать между собой. У нас уже есть Nginx и MySQL, им пока не нужно обращаться друг к другу, но как только у нас появится контейнер для PhpMyAdmin, которому надо обращаться к MariaDB ситуация поменяется. Для взаимодействия между контейнерами используются виртуальные сети, они добавляются похожим образом на хранилища. Сначала добавьте сеть в глобальную секцию networks:
Затем для каждого контейнера, которые будут иметь доступ к этой сети, надо добавить сеть в раздел networks.

Далее контейнеры будут доступны по сети по их имени. Например, добавим PhpMyAdmin и дадим ему доступ к базе данных:

Здесь в переменной PMA_HOST мы ссылаемся на хост docker-mariadb, который благодаря общей сети этих контейнеров доступен. Аналогично в контейнере docker-mariadb, наш контейнер с PhpMyAdmin доступен как docker-phpmyadmin. Вы можете открыть адрес http://localhost:8095 и авторизоваться чтобы проверить, что база данных работает:

9. Модификация контейнера
Это уже более сложные вещи, но зато вы разберетесь с Docker на практике. В большинстве случаев можно обойтись без модификации контейнера, иногда туда надо скопировать специфические конфигурационные файлы либо установить дополнительное программное обеспечение, для таких случаев docker-compose позволяет создавать свои контейнеры на основе уже существующих образов. Для этого надо создать файл Dockerfile на основе которого будет создаваться контейнер. Давайте добавим контейнер php-fpm и установим в него несколько расширений php с помощью Dockerfile.
Сначала создадим папку для файлов контейнера:
FROM php:7.2.26-fpm-stretch RUN docker-php-ext-install pdo pdo_mysql pcntl

Вот основные директивы, которые можно использовать в этом файле:
- FROM — образ, на основе которого будет создаваться наш образ;
- RUN — выполнить команду в окружении образа;
- COPY — скопировать файл в образ;
- WORKDIR — задать рабочую папку для образа;
- ENV — задать переменную окружения образа;
- CMD — задать основной процесс образа;
Теперь надо добавить новую секцию в наш docker-compose.yaml. Здесь вместо image мы используем директиву build, которой надо передать путь к папке с конфигурацией образа:
Дальше, раз мы уже добавили php-fpm надо примонтировать для Nginx верный конфиг, который будет поддерживать php-fpm. Создайте папку nginx и поместите в неё такой конфигурационный файл:
Осталось немного поправить конфигурацию nginx. Примонтировать этот конфигурационный файл и поправить папку для веб-документов по умолчанию:

Осталось создать файл index.php и можно тестировать:
Теперь можно запускать контейнеры:

В отличие от предыдущего раза, теперь перед запуском будет собран новый контейнер на основе файла Dockerfile. Такие контейнеры собираются только первый раз, если они не существуют. Чтобы их пересобрать используйте опцию —build:
docker-compose up —build
Теперь у вас есть полноценное веб-приложение, которое доступно на вашем компьютере, может использовать базу данных, PHP и много чего другого. Вы можете добавить любые недостающие вам контейнеры.
10. Подключение к контейнеру
С помощью docker-compose вы можете подключится к любому контейнеру из группы. Для этого просто используйте команду exec. Например, запустите проект в фоновом режиме:
docker-compose up -d
И используйте docker-compose exec. Подключимся к контейнеру с Nginx:
docker-compose exec docker-nginx /bin/bash

Перед вами откроется оболочка Bash этого контейнера. Устанавливать здесь что-то вручную не рекомендуется, так как всё сотрётся после удаления контейнера, но для тестирования работы чего либо такая возможность будет очень кстати.
Выводы
В этой статье мы разобрали использование docker для чайников. Тема довольно обширная и сложная, но очень интересная. Развернув таким образом проект на одной машине, вы сможете развернуть его там, где вам нужно просто скопировав туда конфигурацию. Поэтому эта технология завоевала такую большую популярность среди разработчиков и DevOps.
Мультиконтейнерное приложение и Docker Compose
Как собирать целые системы на основе докер контейнеров.
Время чтения: 11 мин
- Кратко
- Как начать
- Как понять
- Как пишется
- Services
- Networks
- Volumes
- Игорь Коровченко советует
- Опишите жизненный цикл контейнера Docker
Обновлено 20 декабря 2021
В этой статье мы говорим про инструменты Docker. Если вам не очень понятно, зачем он нужен и как работает, прочитайте статью «Что такое Docker».
Кратко
Скопировать ссылку на секцию «Кратко» Скопировано
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):

В первой строчке этого файла конфигурации содержится информация о версии формата описания. С каждой новой версией функциональность Docker Compose расширяется. Если раньше этот параметр был обязательным, то сейчас его можно не указывать, если не нужно поддерживать старую версию Docker Engine, смотрите таблицу соответствия версий формата описания и движка Docker.
В разделе services содержится описание всех контейнеров, запуск которых нужно настроить. Отдельно работающие приложения или службы в терминах Docker Compose называются сервисами.
В подразделе image необходимо указать имя образа, который должен присутствовать локально на компьютере или в реестре. Можно установить и переменные окружения в подразделе environment , порты для подключения к сервису (например, со стороны браузера) в подразделе ports , пути для монтирования томов в подразделе volumes и прочие параметры.
В различных базах данных, не только в MySQL, как у нас, существует возможность хранить данные в отдельном файле или папке. Логично было бы положить в отдельные файлы и данные нашего сайта на WordPress. Для таких задач используются тома (Docker Volumes). На самом деле — это отдельные образы дисков. Для приложения в контейнере они видны как примонтированные папки. Следовательно, когда используется том db_data, при остановке или перезапуске контейнера с MySQL все данные сохранятся. Ну а с контейнером с самим движком данные вообще никак не связаны.
Файл конфигурации готов, и можно «поднять» все контейнеры всего одной командой:
Когда все образы будут загружены, тома включены, переменные окружения установлены, сайт на WordPress окажется доступным по адресу http : / / localhost : 8000 . В настройках compose . yaml указано, что если один из контейнеров упадёт, то Docker Compose должен перезапустить его автоматически ( restart : always ). Вы сможете начать с того же места. Появляется ещё одна возможность — можно обновить базу данных, и при следующем перезапуске запустится уже новая версия. То же самое можно делать и с веб-сервером, и движком.
Выключить оба контейнера так же просто, как и включить:
Вы можете подробнее посмотреть все команды 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
Скопировать ссылку на секцию «Services» Скопировано
Мультиконтейнерное приложение — система взаимодействующих сервисов. Как правило, один сервис обеспечивает какую-то одну функцию системы. Например, веб-сервер только отдаёт статический сайт (HTML, CSS и JS) браузеру, API служит для обмена данными. Сервисы — это самостоятельные (атомарные) микроприложения или службы, работающие независимо в отдельных контейнерах.
Docker Compose — это инструмент, который не только автоматически запускает или останавливает контейнеры, но и поддерживает их жизненный цикл, обеспечивает совместное использование ресурсов.
Разрабатывая мультиконтейнерное приложение, в голове нужно держать мысль о перспективах его масштабирования и поддержки. Например, один веб-сервер со статическим сайтом может обеспечить тысячу пользователей одновременно. А что, если пользователей больше? Docker Compose в этом случае будет автоматически использовать дополнительные экземпляры сервиса, перенаправляя запросы к ним.
Например, мы запускаем два сервиса, frontend и backend:
Скажем, нам нужно обеспечить до шести экземпляров сервиса frontend, ресурсы для которого будут расходоваться, пока они будут доступны. Тогда мы указываем это явно, как сделано в примере выше, с помощью настроек mode и replicas для элемента deploy . Настроек для развёртывания сервиса (запуска, использования ресурсов процессора, памяти и прочее) очень много.
Сборка сервиса frontend описывается отдельно от параметров развёртывания. В нашем случае она будет производиться из папки ./webapp с помощью файла с именем по умолчанию Dockerfile.
Для backend — другие настройки. Нам нужно собрать образ перед тем, как мы будем использовать приложение. Настройка context будет содержать относительный путь к папке сервиса. Вариантов сборки образа несколько, но наш будет описываться в файле backend.Dockerfile. А ещё будут требования к ресурсам, которые использует приложение. Docker Compose:
- будет использовать процессор не более чем на 50% в штатном режиме, и не более 75% в пиковых нагрузках;
- сервис будет использовать не более чем 50 МБ оперативной памяти и 70 МБ в пике.
Подробнее про настройки сборки вы можете почитать в спецификации здесь, а про настройки развёртывания контейнеров здесь.
Networks
Скопировать ссылку на секцию «Networks» Скопировано
Параметры, описанные в элементе networks , позволяют настроить виртуальную сеть Docker Network для совместной работы нескольких контейнеров. Например, можно указать две подсети, одна из которых, back-tier, будет обеспечивать прямую связь между frontend и backend, в то время как другая, front-tier, будет связывать frontend с внешним миром. В файле конфигурации это можно записать так:
Volumes
Скопировать ссылку на секцию «Volumes» Скопировано
С помощью Docker Compose вы можете использовать тома Docker Volume для хранения данных. Например, нужно обеспечить работу базы данных, расположенную в отдельной папке в томе. Проще всего это сделать следующим образом:
Подробная спецификация элементов описана в отдельном репозитории.
На практике
Скопировать ссылку на секцию «На практике» Скопировано
Игорь Коровченко советует
Скопировать ссылку на секцию «Игорь Коровченко советует» Скопировано
Вы можете поискать подходящие образы на GitHub. Есть, например, целый каталог наиболее удачных: Awesome Compose.
Использование терминальных команд
Скопировать ссылку на секцию «Использование терминальных команд» Скопировано
На этапе сборки образа можно передать аргументы командной строки, а также выполнить произвольные команды по окончании сборки. Иногда это бывает крайне полезно. Например, вы хотите после сборки образа сделать паузу, в течение которой можно будет подождать какой-то процесс или посмотреть вывод в терминал результатов работы программы. В этом случае можно использовать элемент command :
В примере также описываются аргументы командной строки, которые будут использоваться в Dockerfile и могут передаваться на этапе сборки образа командой:
Приложение на стеке MERN
Скопировать ссылку на секцию «Приложение на стеке MERN» Скопировано
MERN — это аббревиатура от MongoDB, Express, React, Node.js. С помощью Docker Compose можно легко реализовать фулстек-приложение. MERN является одним из популярных решений. Оно объединяет веб-сервер, базу данных и фреймворки для бэкенда и фронтенда.
Обычно структура папок MERN-проекта выглядит следующим образом:
Файл конфигурации compose.yaml можно сделать так:
На собеседовании
Скопировать ссылку на секцию «На собеседовании» Скопировано
Это партнёрская рубрика, мы выпускаем её совместно с сервисом онлайн-образования Яндекс Практикум. Приносите вопрос, на который не знаете ответа, в задачи, мы разложим всё по полочкам и опубликуем. Если знаете ответ, присылайте пулреквест на GitHub.
Опишите жизненный цикл контейнера Docker
Скопировать ссылку на секцию «Опишите жизненный цикл контейнера Docker» Скопировано
Редакция
Скопировать ссылку на секцию «Редакция Игорь Коровченко отвечает» Скопировано
Обычно жизненный цикл контейнера состоит из следующей последовательности состояний:
- Создание контейнера
- Работа контейнера
- Приостановка контейнера
- Возобновление работы контейнера
- Запуск контейнера
- Остановка контейнера
- Перезапуск контейнера
- Принудительная остановка контейнера
- Удаление контейнера
На практике встречаются и более сложные случаи, поэтому жизненный цикл контейнера лучше представить с помощью диаграммы:

На этой диаграмме показаны не только состояния и пути перехода из одного состояния в другое, но и команды, которые позволяют пользователю их менять.
Читайте также
Микросервисы
Зачем компании перестают писать одно большое приложение и пишут много маленьких?