В одной из предыдущих статей мы рассмотрели процесс запуска Docker-контейнера из образа. Основная концепция Docker заключается в том, что логически разделенные части инфраструктуры запускаются каждая в выделенном, изолированном от других контейнере с необходимой средой. Однако при проектировании относительно сложно построенной инфраструктуры можно столкнуться с рядом трудностей.
Рассмотрим проект, которому требуется возможность работы с базами данных и веб-сервер. Данный набор уже предполагает управление несколькими отдельными контейнерами, конфигурировать и обслуживать работу которых по отдельности становится неудобно. Для решения этой проблемы разработали утилиту docker-compose. Она позволяет работать с комплексами контейнеров как с единым целым, облегчая создание, настройку и удаление сущностей с помощью нескольких команд. Цель данной статьи — познакомить новичков с Docker, уделяя особое внимание практической стороне вопроса.
Установка Docker-compose
Прежде всего установите “сопутствующее” ПО:
apt-get update && apt-get install -y ca-certificates curl gnupg && sudo install -m 0755 -d /etc/apt/keyrings && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg && chmod a+r /etc/apt/keyrings/docker.gpg
echo \ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update && apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Последующая установка достаточно проста – скачаем предварительно “собранную” разработчиками утилиту:
curl -L "https://github.com/docker/compose/releases/download/1.27.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
Предоставим доступ на уровне файловой системы:
chmod +x /usr/local/bin/docker-compose
Проверим корректность установки, заодно узнаем версию программы:
docker-compose --version
Создание проекта
Любой проект, базирующийся на Docker, описывается в файле docker-compose.yaml, размещенным в один каталог с данными проекта. Указанные в конфигурации контейнеры разворачиваются пакетом docker-compose. Описание основывается на языке YAML и содержит как минимум следующие данные:
version: 'file_version'
networks: 'used_networks'
volumes: 'used_storages'
services: 'used_containers'
Директивой version обозначается версия конфигурационного файла, мы будем использовать версию 3.5. Далее нам нужно перечислить тома, сети и собственно контейнеры.
Синтаксис YAML аналогичен JSON, есть пары ключ-значение, разделенные двоеточиями, но здесь значение может быть совершенно пустым, может содержать другие ключи, а также может быть массивом значений, и в этом случае каждый элемент массива начинается со знака “-“. В структуре файла очень важны отступы, показывающие вложенность значений, ошибки в отступах – одна из самых частых причин неработоспособности конфигурации.
Давайте создадим папку с именем «serverspace-docker» и создадим внутри нее файл «docker-compose.yaml»:
mkdir /opt/serverspace-docker && nano /opt/docker-compose.yaml
И поместим в него следующий код:
version: '3.5'
services: docker-nginx: image: nginx
Этого уже достаточно для запуска контейнера.
Работа контейнеров
Чтобы запустить группу контейнеров, что перечислены в файле docker-compose.yaml, необходимо перейти в папку с проектом, и выполнить там команду docker-compose up:
cd /opt/serverspace-docker/
docker-compose up
После этого контейнеры запустятся, что будет наглядно показано в терминале. Чтобы остановить контейнеры, просто нажмите Ctrl+C. Если потребуется запускать контейнеры в фоновом режиме, используйте опцию -d:
docker-compose up -d
Для остановки работающих фоново контейнеров используется команда docker-compose stop:
А команда docker-compose down позволяет не только остановить контейнеры, но и удалить их:
Организация доступа к контейнерам по сети
Следуя предыдущим шагам инструкции, мы можем запустить онтейнеры, но в таком виде они практически бесполезны, ведь доступа к ним нет. Исправим это, с помощью Docker «пробросим» порт 80 контейнера в операционную систему хоста. Для этого используется директива ports. Синтаксис следующий:
ports:
- external_port:internal_port
Итак, перенаправим порт 80 контейнера на «внешний» порт 8098:
В результате сервис станет доступен через сеть по «внешнему» порту:
Монтирование каталогов
Чтобы «примонтировать» папку хост-системы к контейнеру используется директива volumes. Синтаксис очень похож на описанный в разделе про «проброс» портов:
volumes:
- /path/to/external/folder:/path/to/internal/folder
Давайте создадим файл с именем «index.html» в текущей папке проекта и смонтируем эту папку вместо папки «/usr/share/nginx/html/» контейнера:
echo "You're the best!" > index.html
И опишем процедуру его использования в конфигурационном файле docker-compose:
После перезапуска контейнера отображаемая браузером информация изменится с предлагаемой веб-сервером по умолчанию на указанную нами:
Монтирование docker-контейнера как каталога
Мы можем монтировать в контейнер не только папки хост-машины, но и каталоги другого Docker-контейнера. Для этого потребуется добавить описание монтируемого тома в конфигурацию проекта. Назовем наш том «serverspace-vl». Большинству веб-приложений требуется база данных, например MySQL. Давайте добавим еще один контейнер для этой базы данных и добавим в него наш том. Том добавляется так же, как внешняя папка, с той лишь разницей, что вместо папки указывается имя тома. Добавим поддержку MySQL в нашу конфигурацию:
docker-mysql:
image: mysql
volumes:
- serverspace-vl:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=VeryStr0ngPassword
- MYSQL_DATABASE=database
- MYSQL_USER=user
- MYSQL_PASSWORD=AnotherPassw0rd
Далее видно, что мы также добавили параметр «environment» с переменными среды, которые будет использовать контейнер. Они необходимы для указания имени базы данных, логинов и паролей:
Настройка сети между контейнерами
Для обмена данными между контейнерами Docker организуются виртуальные сети. Для примера добавим в нашу конфигурацию PHPMyAdmin, тем самым свяжем веб-сервер с сервером баз данных. Сети добавляются аналогично томам:
networks:
serverspace-network:
Затем добавим эту сеть к каждому контейнеру, к которому требуется доступ «извне». В результате контейнеры смогут обмениваться данными между собой. Для примера настроим PhpMyAdmin и предоставим ему доступ к базе данных:
docker-phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
ports:
- "8099:80"
environment:
- PMA_HOST=docker-mysql
networks:
- serverspace-network
Здесь в переменной PMA_HOST описывается хост «docker-mysql», который используется в качестве хранилища баз данных. Контейнер PhpMyAdmin доступен как «docker-phpmyadmin». В результате можно открыть адрес http://docker-server:8099 и авторизоваться с данными, указанными в переменных среды.
Подключение к контейнеру
Утилита docker-compose позволяет подключиться к любому контейнеру, входящему в в группу. Для этого используется команда exec. Запустим проект в фоновом режиме:
docker-compose up -d
Теперь подключимся к контейнеру, содержащему данные веб-сервера:
docker-compose exec docker-nginx /bin/bash
Заключение
В этой статье было рассмотрено использование Docker новичками. Также мы описали, как управлять несколькими докер-контейнерами как единым целым. Данная методология заслуженно завоевала большую популярность среди разработчиков и DevOps.