Docker Compose обладает целым рядом нетривиальных способов применения, которые мы рассмотрим в этой заметке. Это очередной перевод статьи, которую мы разбирали при подготовке материалов нашего курса Python для Web-разработки.
Docker Compose запускает контейнеры в порядке зависимостей, используя опцию depends_on, чтобы указывать, когда запускается сервис. Для определения порядка запуска Compose применяет depends_on, links, volumes_from и network_mode: «service: ...».
Если контейнер должен дождаться состояния “ready” другого контейнера, можно использовать инструменты wait-for-it или dockerize. Они будут проверять хосты и порты до тех пор, пока TCP соединение не будет подтверждено. Для включения принудительного ожидания в композицию необходимо добавить entrypoint:
Вы всегда можете самостоятельно написать скрипт-обёртку, если возникнет необходимость в усилении контроля.
Если вам понадобится несколько копий окружений с одинаковой композицией (или docker-compose.yml файлом), просто запустите docker-compose up -p new_project_name.
Переменные среды оболочки могут быть использованы для установки значений в композициях:
Установить переменные среды:
Использовать переменную среды в Docker Compose файле:
Docker Compose принимает и ${DB}, и $TAG. Также можно задать переменные среды в контейнерах:
Можно даже передать переменные среды внутрь контейнеров:
Для гарантии передачи переменной среды, необходимо хранить её в файле среды. Назовите файл .env и сохраните в рабочей директории. Docker Compose игнорирует пустые строки (используйте их для лучшей читаемости) и код, начинающийся с # (то есть комментарии). Вы можете присвоить переменные для дальнейшей подстановки, а также задать переменные Compose CLI:
Пример файла среды:
Используйте несколько файлов Docker Compose, если необходимо изменять приложение под разные среды (разработка, промежуточная среда и продакшн) или запускать задачи администрирования через Compose приложение. Это предоставляет способ совместного использования общих конфигов.
Docker Compose по умолчанию читает два файла: docker-compose.yml и docker-compose.override.yml. В файле docker-compose-override.yml можно хранить переопределения для существующих сервисов или определять новые. Чтобы использовать несколько файлов (или файл переопределения с другим именем), необходимо передать -f в docker-compose up (порядок имеет значение):
Когда две опции конфигурации совпадают, новое значение заменяет или расширяет первоначальное.
В этом примере новое значение переписывает старое и command запускает my_new_app.py:
Если используются environment, labels, volumes, или devices, Docker Compose объединяет результаты. В следующем примере три переменные среды становятся FOO=Hello и BAR=«Python Dev!»:
На сервере разработки мы хотим открыть порты, смонтировать код как том и создать веб-изображение (docker-compose.override.yml):
docker-compose up автоматически читает файл переопределения и применяет его. Также понадобится продакшн версия Docker Compose приложения, которую назовём docker-compose.production.yml:
Когда понадобится развернуть продакшн файл, просто запустим следующее:
Примечание: Docker Compose читает docker-compose.production.yml, но не docker-compose.override.yml.
Необходимо запустить административную копию приложения, чтобы иметь возможность выполнять определённые задачи, например, бэкапить базу данных. Используя уже упомянутый файл docker-compose.yml, создадим файл docker-compose.admin.yml:
А затем, выполним следующую команду:
Расширение сервисов
Совместно использовать конфигурации можно с помощью поля extends. Также оно позволяет делиться опциями между разными проектами.
Создать common-services.yml (можно назвать его как угодно):
Создать базовый docker-compose.yml. Например:
Кроме этого, определить (или переопределить) конфигурацию и добавить другие сервисы можно локально:
Docker Compose ждёт только запуска контейнера перед тем, как перейти к следующему. В случае, если одна часть приложения становится недоступна, Docker Compose рассчитывает на гибкость оставшейся части приложения.
Если вы определяете переменные среды в оболочке или через командную строку во время работы docker-compose, эти переменные будут иметь приоритет над .env файлом.
Не стоит хранить переменные среды в системе контроля версии. Если вы используете файл среды, добавьте его в локальный файл игнорирования и создайте образец env.sample, похожий на следующий пример (если предполагается, что используется файл .env, описанный выше):
Обратите внимание, Docker Compose объединяет файлы в заданном вами порядке.
Сервисы никогда не делят links, volumes_from или depends_on, используя extends; links и volumes_from всегда должны быть определены локально.
С вопросами, предложениями и замечаниями — welcome в комментарии. А если хочется похоливарить в режиме реального времени — присоединяйтесь к нам на Дне открытых дверей курса.
Контроль порядка запуска
Docker Compose запускает контейнеры в порядке зависимостей, используя опцию depends_on, чтобы указывать, когда запускается сервис. Для определения порядка запуска Compose применяет depends_on, links, volumes_from и network_mode: «service: ...».
Если контейнер должен дождаться состояния “ready” другого контейнера, можно использовать инструменты wait-for-it или dockerize. Они будут проверять хосты и порты до тех пор, пока TCP соединение не будет подтверждено. Для включения принудительного ожидания в композицию необходимо добавить entrypoint:
version: '2'
services:
web:
build: .
ports:
- "80:8000"
depends_on:
- db
entrypoint: "./wait-for-it.sh db:5432"
db:
image: postgres
Вы всегда можете самостоятельно написать скрипт-обёртку, если возникнет необходимость в усилении контроля.
Запуск нескольких копий Compose проекта
Если вам понадобится несколько копий окружений с одинаковой композицией (или docker-compose.yml файлом), просто запустите docker-compose up -p new_project_name.
Переменные среды
Переменные среды оболочки могут быть использованы для установки значений в композициях:
Установить переменные среды:
$ TAG="latest"
$ echo $TAG
latest
$ DB="postgres"
$ echo $DB
postgres
Использовать переменную среды в Docker Compose файле:
db:
image: "${DB}:$TAG"
Docker Compose принимает и ${DB}, и $TAG. Также можно задать переменные среды в контейнерах:
web:
environment:
- PRODUCTION=1
Можно даже передать переменные среды внутрь контейнеров:
$ PRODUCTION=1
$ echo $PRODUCTION
1
Файл окружения
Для гарантии передачи переменной среды, необходимо хранить её в файле среды. Назовите файл .env и сохраните в рабочей директории. Docker Compose игнорирует пустые строки (используйте их для лучшей читаемости) и код, начинающийся с # (то есть комментарии). Вы можете присвоить переменные для дальнейшей подстановки, а также задать переменные Compose CLI:
COMPOSE_API_VERSION
COMPOSE_FILE
COMPOSE_HTTP_TIMEOUT
COMPOSE_PROJECT_NAME
DOCKER_CERT_PATH
DOCKER_HOST
DOCKER_TLS_VERIFY
Пример файла среды:
# ./.env
# для нашей промежуточной среды
COMPOSE_API_VERSION=2
COMPOSE_HTTP_TIMEOUT=45
DOCKER_CERT_PATH=/mycerts/docker.crt
EXTERNAL_PORT=5000
Использование нескольких файлов Docker Compose
Используйте несколько файлов Docker Compose, если необходимо изменять приложение под разные среды (разработка, промежуточная среда и продакшн) или запускать задачи администрирования через Compose приложение. Это предоставляет способ совместного использования общих конфигов.
Docker Compose по умолчанию читает два файла: docker-compose.yml и docker-compose.override.yml. В файле docker-compose-override.yml можно хранить переопределения для существующих сервисов или определять новые. Чтобы использовать несколько файлов (или файл переопределения с другим именем), необходимо передать -f в docker-compose up (порядок имеет значение):
$ docker-compose up -f my-override-1.yml my-overide-2.yml
Когда две опции конфигурации совпадают, новое значение заменяет или расширяет первоначальное.
В этом примере новое значение переписывает старое и command запускает my_new_app.py:
# оригинальный сервис
command: python my_app.py
# новый сервис
command: python my_new_app.py
При использовании опции с несколькими значениями (ports, expose, external_links, dns, dns_search и tmpfs), Docker Compose объединяет значения (в примере ниже Compose открывает порты 5000 и 8000):
# оригинальный сервис
expose:
- 5000
# новый сервис
expose:
- 8000
Если используются environment, labels, volumes, или devices, Docker Compose объединяет результаты. В следующем примере три переменные среды становятся FOO=Hello и BAR=«Python Dev!»:
# оригинальный сервис
environment:
- FOO=Hello
- BAR=World
# новый сервис
environment:
- BAR="Python Dev!"
Различные среды
Начнём с базового Docker Compose файла для приложения (docker-compose.yml):
web:
image: "my_dockpy/my_django_app:latest"
links:
- db
- cache
db:
image: "postgres:latest"
cache:
image: "redis:latest"
На сервере разработки мы хотим открыть порты, смонтировать код как том и создать веб-изображение (docker-compose.override.yml):
web:
build: .
volumes:
- ".:/code"
ports:
- "8883:80"
environment:
DEBUG: "true"
db:
command: "-d"
ports:
- "5432:5432"
cache:
ports:
- "6379:6379"
docker-compose up автоматически читает файл переопределения и применяет его. Также понадобится продакшн версия Docker Compose приложения, которую назовём docker-compose.production.yml:
web:
ports:
- "80:80"
environment:
PRODUCTION: "true"
cache:
environment:
TTL: "500"
Когда понадобится развернуть продакшн файл, просто запустим следующее:
$ docker-compose -f docker-compose.yml -f docker-compose.production.yml up -d
Примечание: Docker Compose читает docker-compose.production.yml, но не docker-compose.override.yml.
Задачи администрирования
Необходимо запустить административную копию приложения, чтобы иметь возможность выполнять определённые задачи, например, бэкапить базу данных. Используя уже упомянутый файл docker-compose.yml, создадим файл docker-compose.admin.yml:
dbadmin:
build: database_admin/
links:
- db
А затем, выполним следующую команду:
$ docker-compose -f docker-compose.yml -f docker-compose.admin.yml run dbadmin db-backup
Расширение сервисов
Совместно использовать конфигурации можно с помощью поля extends. Также оно позволяет делиться опциями между разными проектами.
Создать common-services.yml (можно назвать его как угодно):
webapp:
build: .
ports:
- "8000:8000"
volumes:
- "/data"
Создать базовый docker-compose.yml. Например:
web:
extends:
file: common-services.yml
service: webapp
Кроме этого, определить (или переопределить) конфигурацию и добавить другие сервисы можно локально:
web:
extends:
file: common-services.yml
service: webapp
environment:
- DEBUG=1
cpu_shares: 5
links:
- db
important_web:
extends: web
cpu_shares: 10
db:
image: postgres
Распространённые проблемы
Контроль порядка запуска
Docker Compose ждёт только запуска контейнера перед тем, как перейти к следующему. В случае, если одна часть приложения становится недоступна, Docker Compose рассчитывает на гибкость оставшейся части приложения.
Файл окружения
Если вы определяете переменные среды в оболочке или через командную строку во время работы docker-compose, эти переменные будут иметь приоритет над .env файлом.
Не стоит хранить переменные среды в системе контроля версии. Если вы используете файл среды, добавьте его в локальный файл игнорирования и создайте образец env.sample, похожий на следующий пример (если предполагается, что используется файл .env, описанный выше):
COMPOSE_API_VERSION= # должно быть 2
COMPOSE_HTTP_TIMEOUT= # мы используем 30 на продакшне и 120 в разработке
DOCKER_CERT_PATH= # храните путь сертификации здесь
EXTERNAL_PORT= # установите внешний порт здесь (запомните, 5000 для Flask и 8000 для Django)
Использование нескольких файлов Docker Compose
Обратите внимание, Docker Compose объединяет файлы в заданном вами порядке.
Расширение сервисов
Сервисы никогда не делят links, volumes_from или depends_on, используя extends; links и volumes_from всегда должны быть определены локально.
The end
С вопросами, предложениями и замечаниями — welcome в комментарии. А если хочется похоливарить в режиме реального времени — присоединяйтесь к нам на Дне открытых дверей курса.
barkalov
Пользуясь случаем, спрошу. Как правильно монтировать persistent разделы в docker-compose?
Сейчас использую такую копипасту, но выглядит оно не очень и не работает под виндой:
MaxRokatansky
Коллега ответил, но похоже, что ответ где-то потерялся, так что я его продублирую:
Если ты хочешь примонтировать заданную директорию на хосте, то самый простой способ это указать путь до этой директории в docker-compose файле в определении сервиса:
Например:
Если хочешь просто иметь персистетное хранилище для твоего контейнера можно также использовать именованный вольюм. Для этого в определении сервиса указываешь имя вольюма вместо директории на хосте. Например:
Плюс этот именнованный вольюм еще нужно определить в секции volumes в том же компоуз файле. Следуя примеру, мы можем определить именнованный вольюм следующим образом (в секции mydata ничего не указываем, а берем опции по умолчанию):
Тогда твой вольюм можно будет найти на хосте по пути /var/lib/docker/volumes/.
barkalov
Спасибо за такой развернутый ответ!
Хотел, было, написать в личку сначала, но потом решил — тут поспамлю. Вроде как в топик.
Инлайново всё выглядит действительно действительно классно!
— /host/path:/container/path
А как быть, если вольюмы именованые, в отдельной секции, как в последнем примере, и хочется примонтировать определенную директорию на хосте?
volumes:
mydata:
- /host/path/
Могу объяснить зачем.
С дефолтным путем
/var/lib/docker/volumes/
есть проблема под виндой: его, без танцев с бубном, не видно. По крайней мере, в virtualbox based версии (docker toolbox). Не знаю, как там в hyper-v based (docker for windows), она не работает вместе с установленным oracle virtualbox на одной системе (смайл).А именованные вольюмы в отдельной секции мне нравятся, хотя бы, из соображений читаемости компоуз-файла.
MaxRokatansky
На Windows и OSX содержимое вольюмов не видно на твоей рабочей машине по понятным причинам, т.к. для работы контейнеров используется дополнительный слой виртуализации.
Именованными вольюмами управляет сам докер, поэтому ты не можешь использовать произвольную папку на твоей рабочей машине в качестве именованного вольюма. Если тебя интересует конкретная папка, то используй bind mount, указывая путь для монтирования нужной директории.
barkalov
/var/lib/docker/
в винду — мне не понятно. Я пробовал сделать это сам, но, кроме добавления шары в vitualbox, нужно что-то ещё шаманить внутри linux-образа. А там, во-первых, весьма, такой, обрезанный линукс — busybox, я вообще ничего там ни понимаю. Во-вторых, я посчитал, что править «официальную» виртуалку было бы просто неправильно.Технически могу. Но выглядит ужасно.