Перевод транскрипции подкаста подготовлен в преддверии старта курса Администратор Linux
Docker Compose это удивительный инструмент для создания
рабочего
окружения для стека, используемого в вашем приложении. Он позволяет
вам определять
каждый компонент вашего приложения, следуя четкому и простому
синтаксису в YAML-
файлах.
С появлением
docker compose v3 эти YAML-файлы могут использоваться
непосредственно в рабочей среде, при работе с
кластером Docker
Swarm.
Но значит ли это, что вы можете использовать один и тот же
docker-compose файл в
процессе разработки и в продакшен среде? Или использовать этот же
файл для
стейджинга? Ну, в целом да, но для такого функционала нам
необходимо следующее:
- Интерполяция переменных: использование переменных среды для
некоторых
значений, которые изменяются в каждой среде. - Переопределение конфигурации: возможность определить второй
(или любой
другой последующий) docker-compose файл, который что-то изменит относительно
первого, и docker compose позаботится о слиянии обоих файлов.
Различия между файлами для разработки и продакшена
Во время разработки вы, скорее всего, захотите проверять
изменения кода в
режиме реального времени. Для этого, обычно, том с исходным кодом
монтируется в
контейнер, в котором находится рантайм для вашего приложения. Но
для продакшн-среды
такой способ не подходит.
В продакшене у вас есть кластер с множеством узлов, а том
является локальным по
отношению к узлу, на котором работает ваш контейнер (или сервис),
поэтому вы не
можете монтировать исходный код без сложных операций, которые
включают в себя
синхронизацию кода, сигналы и т. д.
Вместо этого мы, обычно, хотим создать образ с конкретной
версией вашего кода.
Его принято помечать соответствующим тегом (можно использовать
семантическое
версионирование или другую систему на ваше усмотрение).
Переопределение конфигурации
Учитывая различия и то, что ваши зависимости могут отличаться в
сценариях
разработки и продакшена, ясно, что нам потребуются разные
конфигурационные файлы.
Docker compose поддерживает объединение различных compose-файлов
для
получения окончательной конфигурации. Как это работает можно
увидеть на примере:
$ cat docker-compose.ymlversion: "3.2"services: whale: image: docker/whalesay command: ["cowsay", "hello!"]$ docker-compose upCreating network "composeconfigs_default" with the default driverStarting composeconfigs_whale_1Attaching to composeconfigs_whale_1whale_1 | ________whale_1 | < hello! >whale_1 | --------whale_1 | \whale_1 | \whale_1 | \whale_1 | ## .whale_1 | ## ## ## ==whale_1 | ## ## ## ## ===whale_1 | /""""""""""""""""___/ ===whale_1 | ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~whale_1 | \______ o __/whale_1 | \ \ __/whale_1 | \____\______/composeconfigs_whale_1 exited with code 0
Как было сказано, docker compose поддерживает объединение
нескольких compose-
файлов, это позволяет переопределять различные параметры во втором
файле. Например:
$ cat docker-compose.second.ymlversion: "3.2"services: whale: command: ["cowsay", "bye!"]$ docker-compose -f docker-compose.yml -f docker-compose.second.yml upCreating composeconfigs_whale_1Attaching to composeconfigs_whale_1whale_1 | ______whale_1 | < bye! >whale_1 | ------whale_1 | \whale_1 | \whale_1 | \whale_1 | ## .whale_1 | ## ## ## ==whale_1 | ## ## ## ## ===whale_1 | /""""""""""""""""___/ ===whale_1 | ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~whale_1 | \______ o __/whale_1 | \ \ __/whale_1 | \____\______/composeconfigs_whale_1 exited with code 0
Такой синтаксис не очень удобен в процессе разработки, когда
команду
понадобится выполнять множество раз.
К счастью, docker compose автоматически ищет специальный файл с
именем
docker-compose.override.yml для переопределения
значений docker-compose.yml. Если
переименовать второй файл, то получится тот же результат, только с
помощью изначальной команды:
$ mv docker-compose.second.yml docker-compose.override.yml$ docker-compose upStarting composeconfigs_whale_1Attaching to composeconfigs_whale_1whale_1 | ______whale_1 | < bye! >whale_1 | ------whale_1 | \whale_1 | \whale_1 | \whale_1 | ## .whale_1 | ## ## ## ==whale_1 | ## ## ## ## ===whale_1 | /""""""""""""""""___/ ===whale_1 | ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~whale_1 | \______ o __/whale_1 | \ \ __/whale_1 | \____\______/composeconfigs_whale_1 exited with code 0
Хорошо, так запомнить проще.
Интерполяция переменных
Файлы конфигурации поддерживают
интерполяцию
переменных и значения по умолчанию. То есть вы можете сделать
следующее:
services: my-service: build: context: . image: private.registry.mine/my-stack/my-service:${MY_SERVICE_VERSION:-latest}...
И если вы выполняете docker-compose build (или
push) без переменной окружения
$MY_SERVICE_VERSION, будет использовано значение
latest, но если вы установите
значение переменной окружения до сборки, оно будет использовано при
сборке или пуше
в регистр private.registry.mine.
Мои принципы
Подходы, которые удобны для меня, могут пригодиться и вам. Я
следую этим
простым правилам:
- Все мои стеки для продакшена, разработки (или других сред)
определяются через
файлы docker-compose. - Файлы конфигурации, необходимые для охвата всех моих сред,
максимально
избегают дублирования. - Мне нужна одна простая команда для работы в каждой среде.
- Основная конфигурация определяется в файле docker-compose.yml.
- Переменные среды используются для определения тегов образов или
других
переменных, которые могут меняться от среды к среде (стейджинг, интеграция,
продакшен). - Значения переменных для продакшена используются в качестве
значений по
умолчанию, это минимизирует риски в случае запуска стека в продакшене без
установленной переменной окружения. - Для запуска сервиса в продакшен-среде используется команда docker stack deploy compose-file docker-compose.yml --with-registry-auth my-stack-name.
- Рабочее окружение запускается с помощью команды docker-compose up -d.
Давайте посмотрим на простой пример.
# docker-compose.yml...services: my-service: build: context: . image: private.registry.mine/my-stack/my-service:${MY_SERVICE_VERSION:-latest} environment: API_ENDPOINT: ${API_ENDPOINT:-https://production.my-api.com}...
И
# docker-compose.override.yml...services: my-service: ports: # This is needed for development! - 80:80 environment: API_ENDPOINT: https://devel.my-api.com volumes: - ./:/project/src...
Я могу использовать docker-compose (docker-compose
up), чтобы запустить стек в
режиме разработки с исходным кодом, смонтированным в
/project/src.
Я могу использовать эти же файлы на продакшене! И я мог бы
использовать точно
такой же файл docker-compose.yml для стейджинга.
Чтобы развернуть это на
продакшен, мне просто нужно собрать и отправить образ с
предопределенным тегом
на этапе CI:
export MY_SERVICE_VERSION=1.2.3docker-compose -f docker-compose.yml builddocker-compose -f docker-compose.yml push
На продакшене это можно запустить с помощью следующих команд:
export MY_SERVICE_VERSION=1.2.3docker stack deploy my-stack --compose-file docker-compose.yml --with-registry-auth
И если вы хотите сделать то же самое на стейдже, необходимо
просто определить
необходимые переменные окружения для работы в среде стейджинга:
export MY_SERVICE_VERSION=1.2.3export API_ENDPOINT=http://staging.my-api.comdocker stack deploy my-stack --compose-file docker-compose.yml --with-registry-auth
В итоге мы использовали два разных docker-compose файла, которые
без
дублирования конфигураций могут использоваться для любой вашей
среды!
Узнать подробнее о курсе Администратор Linux