Четвертая часть цикла, посвященного контейнеризации MEAN-stack приложений, в которой приложение мы разворачиваем в кластере Docker Swarm.
Содержание цикла
- Часть 1 - Dockerfile, образы, контейнеры
- Часть 2 - Docker Compose
- Часть 3 - Traefik reverse proxy
- Часть 4 - Docker Swarm
- Часть 5 - Mongo Replica Set в Docker Swarm
Введение
Docker позволяет объединить в кластер группу машин, на которых он установлен. Этот кластер называется Swarm (рой). После этого можно выполнять все те же команды Docker, но теперь они будут выполняться в кластере swarm-менеджером. Помимо менеджеров в swarm могут быть и воркеры (workers). Все машины, подключенные к swarm, называются нодами (nodes). Менеджеры также отвечают и за распределение сервисов между всеми нодами. Правила распределения и взаимодействия сервисов описываются в уже известном нам docker-compose YAML-файле. Совокупность всех сервисов в swarm носит название stack.
Создаем машины
Для начала нужно заиметь группу машин.
Под виндой 3 виртуальные машины можно создать следующим образом:
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" vm0
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" vm1
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" vm2
Под Mac/Linux:
docker-machine create --driver virtualbox vm0
Если хочется поиграться в условиях, приближенных к боевым, то можно поднять машины на дроплетах Digital Ocean:
docker-machine create --driver digitalocean --digitalocean-access-token xxxxx vm0
...
Пример c Digital Ocean Docker Machine >>
Посмотреть список доступных машин:
docker-machine ls
Инициируем Swarm-режим
Получим команды, которые настроят текущий shell для работы с демоном Docker на виртуальной машине:
docker-machine env vm0
Будет выведен список команд для текущей оболочки, которые нужно выполнить. В списке машин (docker-machine ls
) в колонке ACTIVE
символом *
будет отмечена активная машина. Теперь все команды docker ...
будут выполняться на ней.
Для инициации swarm-режима выполняем:
docker swarm init
В ответе будет указано, что текущая машина теперь менеджер. Также будет выведена команда для подключения к swarm рабочих нод.
Подключаем рабочие (worker) ноды
Переключаемся на другую машину и выполняем на ней предоставленную ранее команду:
docker-machine env vm1
...
docker swarm join --token SWMTKN-1-52qk72ooyql1zfxb0lezwmj52oipimmgln6zh3skbdokl6pp3c-179u2zzjdffcaqjni4zjst188 192.168.2.36:2377
Эту же процедуру проведем и с vm2
.
Подключение менеджеров
Для подключения к swarm других менеджеров нужно запросить соответствующий токен:
docker swarm join-token manager
Docker Stack
Теперь у нас есть кластер на Docker Swarm, готовый к деплою нашего приложения. Однако приложение осталось чутка подготовить к запуску.
Stack - это, по сути, тот же docker-compose файл, но есть небольшие отличия. Так убираем из файла все depends_on
- в swarm они не работают. Все сервисы запускаются параллельно и независимо. Поэтому на сервере пришлось настроить reconnect к базе данных в случае неудачи. Сервис может быть запущен до запуска базы данных, и тогда он уходит в цикл "падение-запуск" и, тем самым, солидно так грузит весь стек.
У сервисов добавляется раздел deploy
, в котором настраиваются:
- restart_policy (
condition: on-failure
); - update_config (
parallelism: 2
); - число экземпляров сервиса (
replicas: 3
); - правила размещения сервиса (
placement constraints
,preferences
) - и ряд других параметров
Также в секцию deploy необходимо перенести все lebels
.
Для стека создадим новый файл:
docker-stack.yml
version: "3.5"
services:
server:
image: myusername/public:mean-docker-server
deploy:
replicas: 2
restart_policy:
condition: on-failure
placement:
constraints:
- node.role == worker
labels:
- traefik.docker.network=traefik-net
- traefik.frontend.rule=Host:api.docker-example.local
- traefik.port=3000
environment:
- "db:uri=mongodb://db/docker"
networks:
- traefik-net
- db-net
client:
image: myusername/public:mean-docker-client
deploy:
replicas: 2
restart_policy:
condition: on-failure
placement:
constraints:
- node.role == worker
labels:
- traefik.frontend.rule=Host:docker-example.local
- traefik.port=4000
networks:
- traefik-net
db:
image: mongo
command:
- "--smallfiles"
deploy:
mode: global
restart_policy:
condition: on-failure
placement:
constraints:
- node.role == manager
labels:
- traefik.enable=false
networks:
- db-net
reverse-proxy:
image: traefik
command:
- "--api"
- "--entrypoints=Name:http Address::80"
- "--defaultentrypoints=http"
- "--docker"
# Включаем режим Swarm
- "--docker.swarmMode"
- "--docker.domain=docker-example.local"
- "--docker.watch"
deploy:
mode: global
placement:
constraints:
- node.role == manager
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
labels:
- traefik.frontend.rule=Host:traefik.docker-example.local
- traefik.port=8080
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
traefik-net:
aliases:
- api.docker-example.local
Запустим по 2 реплики "server" и "client". В placement:constraints
указываем, что запускать их требуется только на воркерах (node.role == worker
).
Для сервисов "db" и "reverse-proxy" укажем mode: global
(запускать по 1 сервису на каждую ноду) и node.role == manager
в constraints
(только на менеджерах).
Docker Swarm Visualizer
Также в сервисы добавим визуализатор работы Swarm.
services:
...
visualizer:
image: dockersamples/visualizer:stable
deploy:
placement:
constraints:
- node.role == manager
labels:
- traefik.frontend.rule=Host:visualizer.docker-example.local
- traefik.port=8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- traefik-net
Hosts
Заменим/добавим наши фейковые домены:
# windows: c:/windows/system32/drivers/etc/hosts
# ubuntu/mac: /etc/hosts
192.168.2.40 docker-example.local
192.168.2.40 api.docker-example.local
192.168.2.40 traefik.docker-example.local
192.168.2.40 visualizer.docker-example.local
Здесь 192.168.2.40
- IP-адрес менеджера (vm0). Узнать его можно с помощью docker-machine ls
.
Deploy
Для развертывания приложения переключаемся на ноду-менеджер:
docker-machine env vm0
...
Создаем сеть:
docker network create -d overlay traefik-net
и выполняем деплой:
docker stack deploy -c docker-stack.yml meanstack
В браузере по адресу http://visualizer.docker-example.local/ мы должны увидеть какую-то такую картину:
В следующей части попробуем зареплицировать нашу базу данных.