Каждые несколько лет в индустрии разработки ПО происходит смена парадигмы. Одним из таких явлений можно признать рост интереса к концепции микросервисов. Хотя микросервисы — это технология не самая новая, лишь в последнее время её популярность буквально взлетела до небес.
Большие монолитные сервисы в наши дни заменяют независимыми автономными микросервисами. Микросервис можно рассматривать как приложение, которое служит единственной и очень специфической цели. Например — это может быть реляционная СУБД, Express-приложение, Solr-сервис.
В наши дни сложно представить себе разработку новой программной системы без применения микросервисов. А эта ситуация, в свою очередь, ведёт нас к платформе Docker.
Docker
Платформа Docker, в деле разработки и развёртывания микросервисов, стала практически индустриальным стандартом. На сайте проекта можно узнать о том, что Docker — это единственная независимая платформа контейнеризации, которая позволяет организациям без особых усилий создавать любые приложения, а также распространять и запускать их в любых средах — от гибридных облаков, до пограничных систем.
Docker Compose
Технология Docker Compose предназначена для конфигурирования многоконтейнерных приложений. В Docker Compose-проект может входить столько контейнеров Docker, сколько нужно создателю этого проекта.
При работе с Docker Compose для настройки сервисов приложения и организации их взаимодействия друг с другом используется YAML-файл. Docker Compose, таким образом, это инструмент для описания и запуска многоконтейнерных приложений Docker.
Два контейнера, работающие на хост-системе
GNU Make
Программа make
, по существу, представляет собой инструмент для автоматизации сборки программ и библиотек из исходного кода. В целом, можно говорить о том, что make
применима к любому процессу, который включает в себя выполнение произвольных команд для преобразования неких исходных материалов к некоему результирующему виду, к некоей цели. В нашем случае команды docker-compose
будут преобразовываться в абстрактные цели (Phony targets).
Для того чтобы сообщить программе make
о том, чего мы от неё хотим, нам понадобится файл Makefile
.
В нашем Makefile
будут содержаться обычные команды docker
и docker-compose
, которые предназначены для решения множества задач. А именно, речь идёт о сборке контейнера, о его запуске, остановке, перезапуске, об организации входа пользователя в контейнер, о работе с логами контейнера и о решении других подобных задач.
Типичные варианты использования Docker Compose
Представим себе обычное веб-приложение, в котором имеются следующие компоненты:
- База данных TimescaleDB (Postgres).
- Express.js-приложение.
- Ping (просто контейнер, ничего особенного не делающий).
Этому приложению понадобится 3 контейнера Docker и файл docker-compose
, содержащий инструкции по управлению этими контейнерами. Каждый из контейнеров будет обладать разными точками взаимодействия. Например, с контейнером timescale
можно будет работать примерно так, как работают с базами данных. А именно, он позволяет выполнять следующие действия:
- Вход в оболочку Postgres.
- Импорт и экспорт таблиц.
- Создание
pg_dump
таблицы или базы данных.
Контейнер Express.js-приложения, expressjs
, может обладать следующими возможностями:
- Выдача свежих данных из системного журнала.
- Вход в оболочку для выполнения неких команд.
Взаимодействие с контейнерами
После того, как мы настроили связь между контейнерами с использованием Docker Compose, пришло время налаживания взаимодействия с этими контейнерами. В рамках системы Docker Compose имеется команда docker-compose
, поддерживающая опцию -f
, которая позволяет передавать системе файл docker-compose.yml
.
Используя возможности этой опции, можно ограничить взаимодействие с системой только теми контейнерами, которые упомянуты в файле docker-compose.yml
.
Взглянем на то, как выглядят взаимодействия с контейнерами при использовании команд docker-compose
. Если представить, что нам нужно войти в оболочку psql
, то соответствующие команды могут выглядеть так:
docker-compose -f docker-compose.yml exec timescale psql -Upostgres
Та же команда, для выполнения которой используется не docker-compose
, а docker
, может выглядеть так:
docker exec -it edp_timescale_1 psql -Upostgres
Обратите внимание на то, что в подобных случаях всегда предпочтительнее использовать не команду docker
, а команду docker-compose
, так как это позволяет избавиться от необходимости помнить имена контейнеров.
Обе приведённых выше команды не так уж и сложны. Но если бы мы воспользовались «обёрткой» в виде Makefile
, которая давала бы нам интерфейс в виде простых команд и сама бы вызывала подобные длинные команды, то тех же результатов можно было бы добиться так:
make db-shell
Совершенно очевидно то, что использование Makefile
значительно упрощает работу с контейнерами!
Рабочий пример
На основе вышерассмотренной схемы проекта создадим следующий файл docker-compose.yml
:
version: '3.3'
services:
api:
build: .
image: mywebimage:0.0.1
ports:
- 8080:8080
volumes:
- /app/node_modules/
depends_on:
- timescale
command: npm run dev
networks:
- webappnetwork
timescale:
image: timescale/timescaledb-postgis:latest-pg11
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
command: ["postgres", "-c", "log_statement=all", "-c", "log_destination=stderr"]
volumes:
- ./create_schema.sql:/docker-entrypoint-initdb.d/create_schema.sql
networks:
- webappnetwork
ping:
image: willfarrell/ping
environment:
HOSTNAME: "localhost"
TIMEOUT: 300
networks:
webappnetwork:
driver: bridge
Для управления конфигурацией Docker Compose и для взаимодействия с контейнерами, которые она описывает, создадим следующий файл Makefile
:
THIS_FILE := $(lastword $(MAKEFILE_LIST))
.PHONY: help build up start down destroy stop restart logs logs-api ps login-timescale login-api db-shell
help:
make -pRrq -f $(THIS_FILE) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
build:
docker-compose -f docker-compose.yml build $(c)
up:
docker-compose -f docker-compose.yml up -d $(c)
start:
docker-compose -f docker-compose.yml start $(c)
down:
docker-compose -f docker-compose.yml down $(c)
destroy:
docker-compose -f docker-compose.yml down -v $(c)
stop:
docker-compose -f docker-compose.yml stop $(c)
restart:
docker-compose -f docker-compose.yml stop $(c)
docker-compose -f docker-compose.yml up -d $(c)
logs:
docker-compose -f docker-compose.yml logs --tail=100 -f $(c)
logs-api:
docker-compose -f docker-compose.yml logs --tail=100 -f api
ps:
docker-compose -f docker-compose.yml ps
login-timescale:
docker-compose -f docker-compose.yml exec timescale /bin/bash
login-api:
docker-compose -f docker-compose.yml exec api /bin/bash
db-shell:
docker-compose -f docker-compose.yml exec timescale psql -Upostgres
Большинство описанных здесь команд применяются ко всем контейнерам, но использование опции c=
позволяет ограничить область действия команды до одного контейнера.
После того, как Makefile
готов, пользоваться им можно так:
make help
— выдача перечня всех команд, доступных дляmake
.
Справка по доступным командам
make build
— сборка образа изDockerfile
. В нашем примере мы использовали существующие образыtimescale
иping
. Но образapi
мы хотим собрать локально. Именно это и будет сделано после выполнения данной команды.
Сборка контейнера Docker
make start
— запуск всех контейнеров. Для запуска лишь одного контейнера можно воспользоваться командой видаmake start c=timescale
.
Запуск контейнера timescale
Запуск контейнера ping
make login-timescale
— вход в bash-сессию контейнераtimescale
.
Запуск bash в контейнере timescale
make db-shell
— вход вpsql
в контейнереtimescale
для выполнения SQL-запросов к базе данных.
Запуск psql в контейнере timescaledb
make stop
— остановка контейнеров.
Остановка контейнера timescale
make down
— остановка и удаление контейнеров. Для удаления конкретного контейнера можно использовать эту команду с указанием нужного контейнера. Например —make down c=timescale
илиmake down c=api
.
Остановка и удаление всех контейнеров
Итоги
Несмотря на то, что система Docker Compose даёт в наше распоряжение обширный набор команд, предназначенных для управления контейнерами, иногда эти команды становятся длинными, в результате их бывает сложно запомнить.
Методика использования Makefile
помогла нам наладить быстрое и простое взаимодействие с контейнерами из файла docker-compose.yml
. А именно, речь идёт о следующем:
- Разработчик взаимодействует только с контейнерами проекта, описанными в
docker-compose.yml
, работе не мешают другие запущенные контейнеры. - В том случае, если некая команда забыта, можно выполнить команду
make help
и получить справку по доступным командам. - Не нужно запоминать длинных списков аргументов для выполнения таких действий, как получение свежих записей журнала или вход в систему. Например, команда вида
docker-compose -f docker-compose.yml exec timescale psql -Upostgres
превращается вmake db-shell
. - Файл
Makefile
можно, по мере роста проекта, гибко под него подстраивать. Например, в него несложно добавить команду для создания резервной копии базы данных или для выполнения любого другого действия. - Если большая команда разработчиков пользуется одним и тем же
Makefile
, это упорядочивает совместную работу и снижает количество ошибок.
P.S. В нашем маркетплейсе имеется образ Docker, который устанавливается в один клик. Вы можете проверить работу контейнеров на VPS. Всем новым клиентам бесплатно предоставляются 3 дня для тестирования.
Уважаемые читатели! Как вы автоматизируете работу с Docker Compose?
Автор: ru_vds