В данной инструкции мы приведем различные примеры по работе с docker-compose без подробного описания принципа работы. Данный материал можно использовать в качестве шпаргалки.
Универсальный шаблон
Параметры для контейнеров
Проверки состояния и диагностика
Работа с сетью
Примеры команд
Дополнительные возможности
Решение возможных проблем
Читайте также
В первую очередь, предлагаю заготовку для docker-compose файла, на основе которой можно начинать писать свой сценарий для docker.
Создаем файл для работы с контейнерами:
vi docker-compose.yml
services:
<srv_name>:
image: <image_name>
container_name: <container_name>
hostname: <hostname>
restart: unless-stopped
environment:
TZ: «Europe/Moscow»
* где:
В данном разделе рассмотрим примеры настроек сервисов (контейнеров). Синтаксис:
services:
<имя сервиса>:
<настройки сервиса>
1. Создание контейнера из готового образа. Образ указывается с помощью директивы image:
image: nginx
* в данном примере будет взят образ nginx для поднятия контейнера.
При желании, мы можем, явно, указать версию:
image: nginx:1.18.0
2. Сборка контейнера из Dockerfile. Для этого используем опцию build:
build:
context: ./web-server/
args:
buildno: 22042001
* где:
3. Проброс папок (volumes). Настраивается с помощью опции volumes:
volumes:
— /data/mysql:/var/lib/mysql
* в нашем примере мы смонтируем локальный каталог /data/mysql на хосте внутрь контейнера в качестве каталога /var/lib/mysql .
Также мы можем смонтировать папку только на чтение, например:
volumes:
— /:/rootfs:ro
4. Работа с портами. Рассмотрим несколько вариантов работы с портами.
а) Ports (внешняя публикация). С помощью данной опции мы можем указывать, на каких портах должен слушать контейнер и на какие порты должны пробрасываться запросы:
ports:
— 8080:80
* в данном примере наш контейнер будет слушать запросы на порту 8080 и передавать их внутрь контейнера на порт 80 .
Или можно прописать так:
ports:
— 80
* в этом примере будет настроен проброс на порт 80 . Внешний порт будет выбран docker автоматически.
При необходимости прикрепить проброс с конкретному IP-адресу хостовой машины, используем нотацию:
ports:
— 192.168.15.15:80:80
* хост docker будет слушать на порту 80 на адресе 192.168.15.15 .
По умолчанию пробрасываются порты по протоколу TCP. Чтобы указать UDP, используем формат:
ports:
— 53:53/udp
* в данном примере будет использоваться для прослушивания порт 53/udp .
б) Expose (внутрення публикация). Данная опция задает порт, на котором должно слушать приложение внутри контейнера, но проброса с внешнего адреса не будет — отправить запрос по сети на данный порт можно с другого контейнера:
expose:
— 7000
5. Переменные окружения. В нашей универсальной заготовке мы уже использовали одну системную переменную:
environment:
TZ: «Europe/Moscow»
Чтобы передать несколько переменных, просто их перечисляем:
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
Или мы можем назвать файл с переменными иначе, например env-config. В таком случае, в docker-compose нам нужно указать путь до него:
env_file:
— .env
— env-config
* обратите внимание, что мы указали использовать сразу 2 файла.
6. Зависимости для контейнеров. Мы можем указать с помощью опции depends_on, от какого контейнера зависит сервис:
depends_on:
— db
* в конкретном примере, контейнер не запустится, пока не поднимется db .
7. Переопределить команду. С помощью директивы command мы можем переопределить команду для запуска, например:
command: [ «redis-server», «/usr/local/etc/redis/redis.conf» ]
* в данном примере мы запустим redis-server с альтернативным конфигурационным файлом.
Или можно написать так:
command:
— redis-server
— /usr/local/etc/redis/redis.conf
Но если нам понадобиться запустить несколько последовательных команд, рабочий вариант с использованием bash:
command: bash -c «yarn install && yarn start»
или если в контейнере нет bash:
command: sh -c «yarn install && yarn start»
Если нам нужно не переопределить команду, но дополнить ее дополнительными аргументами запуска, то можем сделать следующую запись:
command: >
—requirepass ${REDIS_PASSWORD}
8. Метки. С помощью опции labels мы можем указывать дополнительную информацию для ориентирования или фильтров при поиске контейнеров:
labels:
MAINTAINER: ${MAINTAINER_EMAIL}
SITE_URL: ${SITE_URL}
* данные могут быть произвольные. Обратите внимание, что в качестве значений мы указали переменные, которые можно просто передать из системного окружения.
9. Пользователь. Директива user позволяет задать конкретного пользователя, от которого будет запускаться и работать контейнер:
user: root
10. Домашняя директория. Определяет положение по умолчанию, откуда будут выполняться команды.
working_dir: /var/www/app
11. Лимиты. Дают возможность определить для контейнера ограничения. Приведем несколько примеров таких лимитов.
а) ulimits. Ограничение на число дескрипторов файлов в контейнере:
ulimits:
memlock:
soft: -1
hard: -1
б) shm_size. Размер устройства /dev/shm, которое является устройством общей памяти и обеспечивает временную файловую систему хранения файлов.
shm_size: ‘512m’
Отдельно рассмотрим директивы, которые помогают проверять состояние контейнера или вести жерналы.
Синтаксис:
services:
<имя сервиса>:
…
healthcheck:
test: <script>
interval: <interval>
timeout: <timeout>
retries: <retries>
* где:
Ниже рассмотрим несколько примеров.
1. Проверка работы веб-портала. Рассмотрим пример, когда сайт при правильной работы должен возвращать слово works:
healthcheck:
test: curl -s http://127.0.0.1 | grep works
interval: 30s
timeout: 2s
retries: 10
* в данном примере мы запросим у нашего сервера страницу по http и выведем строку, в которой есть слово works. Если такой строки не найдется, команда вернет код 1.
2. Проверка СУБД mysql. Проверку можно выполнить с помощью запроса SELECT 1. В композ-файле это выглядит так:
healthcheck:
test: [«CMD», «mysql» ,»-h», «mysql», «-P», «3306», «-u», «root», «-e», «SELECT 1», «cache»]
interval: 30s
timeout: 2s
retries: 10
Настройка логирования может быть выполнена в конфигурационном файле docker. Однако, если мы хотим для отдельного контейнера выставить определенные значения параметров журналирования, нам поможет директива logging.
Приведем несколько примеров:
services:
…
service_name:
…
logging:
driver: «json-file»
options:
max-size: 100m
max-file: «5»
* в нашем примере мы указываем, что формат лога должен быть json ( json-file ); также ограничиваем размер одного файла логов ( max-size ) и задаем максимальное количество данных файлов ( max-file ).
Отдельно рассмотрим варианты сетевых настроек.
Список сетей, созданных для docker можно увидеть командой:
docker network ls
Получить подробную информацию по сети можно командой:
docker network inspect <имя сети>
1. Указать определенную подсеть. Задается с помощью опции subnet в отдельной секции networks. В последней мы создаем конфигурацию для определенной сети (в данном примере, default). Для конкретного сервиса мы также задаем привязку к созданной сети default в подразделе networks:
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 сервиса:
services:
<srv_name>:
…
networks:
default:
aliases:
— <alternative_name>
* в данном примере наш контейнер будет также резолвиться по имени <alternative_name> .
Такого же эффекта можно добиться с помощью links, но его принцип настройки немного отличается. Предположим, у нас есть сервисы webserver и database. Мы хотим, чтобы webserver видел database по имени db. Тогда настраиваем:
webserver:
…
links:
— database:db
database:
…
3. Внешняя сеть. Если необходимо, чтобы наши контейнеры могли видеть по сети другие контейнеры, создаем сеть external:
services:
<srv_name>:
…
networks:
— dnet
networks:
dnet:
name: dnet
external: true
4. Статические IP-адреса. По docker идеологии все контейнеры должны получать IP-адреса автоматически. Но все же, метод для указания контейнерам статических адресов предусмотрен. Рассмотрим на примере:
services:
<srv_name>:
…
networks:
vpcbr:
ipv4_address: 172.28.0.2
networks:
vpcbr:
driver: bridge
ipam:
config:
— subnet: 172.28.0.0/24
gateway: 172.28.0.1
* в нашем примере будет создана подсеть 172.28.0.0/24 , а контейнеру будет присвоен адрес 172.28.0.2 .
5. Добавить сопоставление имя — IP-адрес (на подобие локального файла hosts). С помощью данной настройки мы можем указать отдельно для контейнеров, в какой IP-адрес должен разрешаться определенный хост. Задается с помощью директивы extra_hosts :
services:
<srv_name>:
…
extra_hosts:
foo: 1.2.3.4
bar: 5.6.7.8
* в данном примере имени foo будет соответствовать адрес 1.2.3.4 , а bar — 5.6.7.8 .
Если нам нужно сделать сопоставление с IP-адресом docker-хоста, существует специальное значение host-gateway :
services:
<srv_name>:
…
extra_hosts:
— «remontka.com:host-gateway»
* теперь, когда контейнер будет обращаться по адресу remontka.com , он будет попадать на хост docker.
6. Связь двух контейнеров из разных compose.
Предположим, нам нужно связать два контейнера, которые запускаются с помощью разных docker-compose. Такие контейнеры будут привязаны к разным сетям и не смогут взаимодействовать.
Для решения проблемы мы создадим внешнию подсеть и привяжем ее к контейнеру. Это делается в обоих docker-compose файлах:
services:
…
networks:
— default
— net_split1
…
networks:
net_split1:
name: net_split1
driver: bridge
external: true
* где:
Рассмотрим различные примеры выполнения команды docker-compose.
1. Посмотреть версию:
docker-compose —version
2. Создание и запуск контейнеров:
docker-compose up -d
* напомним, что в текущем каталоге находится созданный файл с названием docker-compose.yml .
С указанием альтернатнативного файла docker-compose.
docker-compose -f /foo/bar/other-docker-compose.yml up -d
Мы можем не указывать каждый раз файл docker-compose, если зададим путь к нему в файле .env:
COMPOSE_FILE=other-docker-compose.yml
3. Перечитать файл docker-compose:
docker-compose up -d
* на самом деле, команда такая же, как для запуска. Система если определит, что есть изменения, пересоздаст контейнер.
Перечитать и пересобрать контейнеры, если есть инструкция build:
docker-compose up -d —build
4. Остановить контейнеры.
Только остановить контейнеры:
docker-compose down
Остановить контейнеры с удаление данных (в volumes):
docker-compose down —volumes
5. Перезапуск контейнеров.
Перезагрузить все контейнеры для docker-compose файла:
docker-compose restart
Перезагрузить определенный контейнер:
docker-compose restart app
* в данном примере будет перезапущен контейнер app .
6. Запуск команды внутри контейнера (exec).
Запуск команды:
docker-compose exec app npm run build
* в данном примере в контейнере app будет запущена команда npm run build .
Провалиться в shell контейнера:
docker-compose exec -it app sh
Рассмотрим несколько примеров, которые пока сложно классифицировать и вывести в отдельную группу.
1. Якоря.
Позволяют делать ссылку на определенный блок кода, что позволит не повторять его. Важно отметить, что это возможность не docker-compose, а yml.
Чтобы создать якорь, указываем тег с & в начале:
logging: &logging
driver: «json-file»
options:
max-size: 100m
max-file: «5»
* в данном примере мы создали якорь с названием logging . Данный якорь ведет на все настройки блока logging .
Чтобы применить якорь:
logging:
<<: *logging
При попытке запустить compose получаем ошибку:
Network <net-name>_default Error
failed to create network <net-name>_default: Error response from daemon: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
Причина: при запуске композа автоматически создается сеть с префиксом _default. Данная ошибка означает, что такую сеть не удалось создать, так как существует лимит на пулы IP-адресов и данный лимит был исчерпан.
Решение: быстрее всего выполнить чистку docker от неиспользуемых сетей. Для этого выполняем команду:
docker network prune
Ошибка появляется при попытке загрузить образ с репозитория docker (docker pull или docker-compose pull). Более полный текст:
toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading
Причина: с ноября 2020 года docker ввел ограничение на количество обращений к их репозиторию анонимных пользователей. Либо вы обратились к данному репозиторию много раз, либо адрес находится за NAT и кто-то другой использовал лимит.
Решение: есть 2 решения:
1. Подождать, пока не закончится действие лимита. Может потребоваться до 6 часов.
2. Залогиниться под своей учетной записью docker hub с помощью команды:
docker login
Другие инструкции, связанные с Docker:
1. Установка Docker на Linux .
2. Создание собственного образа Docker .
3. Настройка локального репозитория для образов Docker и работа с ним .
Zulip — программное обеспечение для реализации корпоративного чата. Разработан в 2012 году, в 2014 был…
Zookeeper — cервис-координатор, который позволяет обеспечить контроль синхронизации данных. Разработан на Java компанией Apache Software…
Zimbra — программное обеспечение для реализации почтового сервиса или, если сказать точнее, автоматизации совместной деятельности…
Zabbix — бесплатная система мониторинга. Позволяет отслеживать состояние сетевых узлов, компьютеров и серверов. Возможности: Поддержка…
YouTube — компания-владелец одноименного портала для просмотра и хранения видео. Чтобы пользоваться данным порталом достаточно…
Yota — провайдер, предоставляющий доступ к сети Интернет по беспроводной связи. Впервые, сервис начал работать…