Docker Compose обладает целым рядом нетривиальных способов применения, которые мы рассмотрим в этой заметке. Это очередной перевод статьи, которую мы разбирали при подготовке материалов нашего курса Python для Web-разработки.
Контроль порядка запуска
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 в комментарии. А если хочется похоливарить в режиме реального времени — присоединяйтесь к нам на Дне открытых дверей курса.
Автор: Tully