Thank you for reading this post, don't forget to subscribe!
Базовый шаблон
В первую очередь, предлагаю заготовку для docker-compose файла, на основе которой можно начинать писать свой сценарий для docker.
Создаем файл:
vi docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
version: "3.9" services: <srv_name>: image: <image_name> container_name: <container_name> hostname: <hostname> restart: unless-stopped environment: TZ: "Europe/Moscow" networks: - default networks: default: ipam: driver: default config: - subnet: 172.28.0.0/16 |
* где:
- version — версия спецификации файла. Начиная с docker-compose v1.27.0 является опциональной.
- services — основной раздел, где мы будем создавать и описывать наши сервисы (контейнеры docker). В данном примере сервис один. Для добавления еще одного добавляем еще строчки <srv_name>.
- <srv_name> — название для нашего сервиса, на основе которого будет создан контейнер.
- image — имя образа, который будет использоваться для создания контейнера.
- container_name — имя, которое получен созданный контейнер.
- hostname — имя хоста внутри контейнера.
- restart — поведения контейнера при падении. В нашем примере мы указываем на необходимость автоматической перезагрузки, за исключением случаев, когда мы его сами остановили командой stop.
- environment — задаем переменные окружения. В нашем примере только одна, которая указывает на часовой пояс (московское время).
- networks — привязываем наш контейнер к сети. Опционально, но лучше определять самому подсеть. Это упрощает настройку некоторых сервисов, например, мы можем ограничить доступ для определенных подсетей и не желательно, чтобы подсети задавалась случайным образом.
- networks — описание для сети. В нашем примере используются стандартные настройки, но указывается конкретная подсеть 172.28.0.0/16.
Сервисы
В данном разделе рассмотрим примеры настроек сервисов (контейнеров). Синтаксис:
1 2 3 |
services: <имя сервиса>: <настройки сервиса> |
1. Создание контейнера из готового образа. Образ указывается с помощью директивы image:
image: nginx
* в данном примере будет взят образ nginx для поднятия контейнера.
2. Сборка контейнера из Dockerfile. Для этого используем опцию build:
1 2 3 4 |
build: context: ./web-server/ args: buildno: 22042001 |
* где:
- build — указание на необходимость сборки из Dockerfile.
- context — путь, где нужно искать Dockerfile относительно места, где находится docker-compose файл.
- buildno — номер для сборки.
3. Проброс папок (volumes). Настраивается с помощью опции volumes:
1 2 |
volumes: - /data/mysql:/var/lib/mysql |
* в нашем примере мы смонтируем локальный каталог /data/mysql на хосте внутрь контейнера в качестве каталога /var/lib/mysql.
4. Работа с портами. С помощью опции ports мы можем указывать, на каких портах должен слушать контейнер и на какие порты должны пробрасываться запросы:
1 2 |
ports: - 8080:80 |
* в данном примере наш контейнер будет слушать запросы на порту 8080 и передавать их внутрь контейнера на порт 80.
5. Переменные окружения. В нашей универсальной заготовке мы уже использовали одну системную переменную:
1 2 |
environment: TZ: "Europe/Moscow" |
Чтобы передать несколько переменных, просто их перечисляем:
1 2 3 |
environment: TZ: "Europe/Moscow" MYSQL_ROOT_PASSWORD=password |
Для каждого приложения есть свой набор системных переменных, которые оно понимает и интерпретирует. Например, MYSQL_ROOT_PASSWORD поймет СУБД и установит значение в качестве пароля для пользователя root.
Также системные переменные можно передать не в сценарии docker-compose, а в файле .env — просто создадим этот файл в одной директории с файлом docker-compose.yml:
vi .env
MYSQL_ROOT_PASSWORD=secret
MYSQL_PWD=secret
6. Зависимости для контейнеров. Мы можем указать с помощью опции depends_on, от какого контейнера зависит сервис:
1 2 |
depends_on: - db |
* в конкретном примере, контейнер не запустится, пока не поднимется db.
7. Переопределить команду. С помощью директивы command мы можем переопределить команду для запуска, например:
1 2 3 |
command: [ "redis-server", "/usr/local/etc/redis/redis.conf" ] |
* в данном примере мы запустим redis-server с альтернативным конфигурационным файлом.
8. Метки. С помощью опции labels мы можем указывать дополнительную информацию для ориентирования или фильтров при поиске контейнеров:
1 2 3 |
labels: MAINTAINER: ${MAINTAINER_EMAIL} SITE_URL: ${SITE_URL} |
* данные могут быть произвольные. Обратите внимание, что в качестве значений мы указали переменные, которые можно просто передать из системного окружения.
Healthcheck
Данная директива, хоть и является частью сервиса, мы рассмотрим ее в отдельном разделе. Синтаксис:
1 2 3 4 5 6 7 8 |
services: <имя сервиса>: ... healthcheck: test: <script> interval: <interval> timeout: <timeout> retries: <retries> |
* где:
- test — наш скрипт, который должен вернуть 0, если все хорошо, или 1 — если все плохо.
- interval — как часто запускать проверку.
- timeout — как долго нужно ждать ответа.
- retries — сколько раз тест должен вернуть отрицательный результат, чтобы контейнер перешел в состояние «unhealthy».
1. Проверка работы веб-портала. Рассмотрим пример, когда сайт при правильной работы должен возвращать слово works:
1 2 3 4 5 |
healthcheck: test: curl -s http://127.0.0.1 | grep works interval: 30s timeout: 2s retries: 10 |
* в данном примере мы запросим у нашего сервера страницу по http и выведем строку, в которой есть слово works. Если такой строки не найдется, команда вернет код 1.
2. Проверка СУБД mysql. Проверку можно выполнить с помощью запроса SELECT 1. В композ-файле это выглядит так:
1 2 3 4 5 |
healthcheck: test: ["CMD", "mysql" ,"-h", "mysql", "-P", "3306", "-u", "root", "-e", "SELECT 1", "cache"] interval: 30s timeout: 2s retries: 10 |
Networks
Отдельно рассмотрим варианты сетевых настроек.
1. Указать определенную подсеть. Задается с помощью опции subnet в отдельной секции networks. В последней мы создаем конфигурацию для определенной сети (в данном примере, default). Для конкретного сервиса мы также задаем привязку к созданной сети default в подразделе networks:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
services: <srv_name>: ... networks: - default networks: default: ipam: driver: default config: - subnet: 172.28.0.0/16 |
* где 172.28.0.0/16 — подсеть, в которой будут работать все контейнеры, которые привязаны к созданной сети default.
2. Алиасы. Данная настройка позволит видеть контейнеры по альтернативным именам (по умолчанию, они обнаруживаются по имени контейнера). Настройка указывается в подразделе networks сервиса:
1 2 3 4 5 6 7 8 |
services: <srv_name>: ... networks: default: aliases: - <alternative_name> |
* в данном примере наш контейнер будет также резолвиться по имени <alternative_name>.
3. Внешняя сеть. Если необходимо, чтобы наши контейнеры могли видеть по сети другие контейнеры, создаем сеть external:
1 2 3 4 5 6 7 8 9 10 11 |
services: <srv_name>: ... networks: - dnet networks: dnet: external: name: dnet |
Запуск docker-compose
Рассмотрим различные примеры выполнения команды docker-compose.
1. Посмотреть версию:
docker-compose --version
2. Создание и запуск контейнеров:
docker-compose up -d
3. Перечитать файл docker-compose:
docker-compose up -d
* на самом деле, команда такая же, как для запуска. Система если определит, что есть изменения, пересоздаст контейнер.
4. Остановить контейнеры:
docker-compose down
5. Остановить контейнеры с удаление данных (в volumes):
docker-compose down --volumes