Установка Docker Swarm
Docker Swarm — это родная система кластеризации для Docker, которая превращает набор хостов Docker в один последовательный кластер, называемый Swarm.
Каждая/ый нода/хост, в составе такого кластера выступает в качестве либо управляющей(manager) либо рабочей ноды(worker).
В кластере должна быть, как минимум, одна управляющая нода(manager).
Технически физическое расположение машин не имеет значения, однако, желательно иметь все Docker-ноды внутри одной локальной сети, в противном случае — управление операциями (или
поиск консенсуса между несколькими управляющими нодами) может занять значительное количество времени.
Начиная с Docker 1.12, Docker Swarm уже интегрирован в Docker Engine как Swarm-режим
В более старых версиях необходимо было запускать swarm-контейнер на каждом из хостов для обеспечения функционала кластеризации.
Термины в Docker Swarm:
Service – запущенный образ ( в отличии от Docker Engine, где запущенный на Docker-хосте образ называется контейнером).
Одна service запускает определенное количество задач.
Задача — это атомная запланированная единица Docker Swarm, которая содержит информацию о контейнере и команду, которая должна запущена внутри контейнера.
Реплика – каждый контейнер, который запускается на ноде
Количество реплик — это ожидаемое число всех контейнеров для данной service
Запуск Docker Swarm происходит с указанием имени service, образа Docker, который нужно использовать для контейнеров и желаемого количества реплик.
Управляющая нода автоматически назначает задачи рабочим нодам.
Каждый реплицируемый контейнер запускается с одного и того же Docker-образа.
Docker Swarm может быть рассмотрен как слой поверх механизма Docker Engine, который отвечает за оркестрацию контейнеров
В данном изображения у нас есть три задачи, и каждая из них запускается на отдельной Docker-ноде.
Тем не менее, также может случиться так, что все контейнеры будут запущены на одной и той же Docker-ноде.
Все зависит от управляющей ноды, которая распределяет задачи для рабочих нод, используя стратегию планирования, которая будет описана в разделе
Стратегия планирования – распределения задач по рабочим нодам
Интересные возможности Docker Swarm:
Балансировка нагрузки: Docker Swarm отвечает за балансировку нагрузки и назначение
уникальных DNS-имен, чтобы приложение, развернутое в кластере, можно было использовать
так же, как и, если приложение было бы развернуто на одном Docker-хосте.
Другими словами, Docker Swarm может публиковать порты так же, как контейнер в Docker Engine, а затем управляющая нода распределяет запросы между service-ами в кластере.
Динамическое управление ролями: Docker-хосты могут быть добавлены Swarm-кластеру без необходимости перезапуска кластера. Более того, роль узла (управляющий или рабочий) также может динамически меняться.
Динамическое масштабирование сервисов: Каждая service может динамически масштабироваться как в сторону увеличения, так и в сторону уменьшения с клиентом Docker. Управляющая нода заботится о добавлении или удалении контейнеров на узлах.
Восстановление отказа: ноды постоянно контролируются управляющей нодой и, если
какая-либо нода сбоит, то новые задачи запускаются на других рабочих нодах с целью, чтобы обеспечивалось заявленное/желаемое количество реплик.
Docker Swarm также позволяет создавать несколько управлющих нод для предотвращения поломки кластера в случае выхода со строя единственной управляющей ноды
Rolling-обновления: обновление сервисов может применяться постепенно.
Например, если у нас есть 10 реплик, и мы хотим внести изменения, мы можем определить задержку между развертыванием для каждой реплики.
В таком случае, когда что-то пойдет не так, процесс обновления автоматически прерывается, тем самым защищая нас от ситуации, когда в кластере не останется рабочих реплик.
Режимы работы: Есть два режима, в которых можно запускать Docker Swarm:
Реплицированные service: указанное количество реплицируемых контейнеров
распределяются между узлами на основе стратегии планированния
Глобальные service: один контейнер запускается на каждом доступном узле в
кластере
Безопасность: Как и все в Docker, Docker Swarm обеспечивает TLS
аутентификации и шифрования связи. Также возможно использовать CA (или
самоподписанные) сертификаты.
Инициализация manager-ноды
1 |
# docker swarm init |
1 2 3 4 5 6 7 |
Swarm initialized: current node (0tan0z483jgw3rhpj6kndp60n) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-5cbvu9zv8u8o2qkddjlfctrd3lfbk2l1gek0hec1dsgexuxw6h-1tls8aogc4443pb7zcq7c5gkf 163.172.XXX.YYY:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. |
Если хост имеет несколько интерфейсов,то можно определить IP-адрес, на котором нужно запускать Swarm-cluster
1 |
# docker swarm init --advertise-addr IP-address |
Проверяем состояние управляющей ноды
1 |
# docker node ls |
1 2 |
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION 0tan0z483jgw3rhpj6kndp60n * lxc Ready Active Leader 18.06.1-ce |
На всех нодах кластера в файрволле открываем следующие порты и протоколы
2377-tcp
7946-tcp/udp
4889-udp
1 |
# iptables -N swarm |
1 |
# iptables -A INPUT -p tcp --dport 2377 -j swarm |
1 |
# iptables -A INPUT -p tcp --dport 7946 -j swarm |
1 |
# iptables -A INPUT -p udp --dport 7946 -j swarm |
1 |
# iptables -A INPUT -p udp --dport 4889 -j swarm |
1 |
# iptables -A swarm -s IP-address-manager-node -j ACCEPT |
1 |
# iptables -A swarm -s IP-address-worker-node1 -j ACCEPT |
1 |
# iptables -A swarm -s IP-address-worker-node2 -j ACCEPT |
1 |
# iptables -A swarm -j DROP |
Добавление рабочих нод
В выводе команды, выполненной на предыдущем этапе
1 |
# docker swarm init |
Есть подсказка, как добавить рабочие ноды
1 |
docker swarm join --token SWMTKN-1-5cbvu9zv8u8o2qkddjlfctrd3lfbk2l1gek0hec1dsgexuxw6h-1tls8aogc4443pb7zcq7c5gkf 163.172.XXX.YYY:2377 |
Также для получения необходимой команды для добавления ноды в качестве worker-ноды в swarm-кластер можно воспользоваться командой
1 |
# docker swarm join-token worker |
Добавим пару нод
1 |
root@ubuntu161 ~ # docker swarm join --token SWMTKN-1-5cbvu9zv8u8o2qkddjlfctrd3lfbk2l1gek0hec1dsgexuxw6h-1tls8aogc4443pb7zcq7c5gkf 163.172.XXX.YYY:2377 |
1 |
This node joined a swarm as a worker. |
1 |
root@ubuntu162 ~ # docker swarm join --token SWMTKN-1-5cbvu9zv8u8o2qkddjlfctrd3lfbk2l1gek0hec1dsgexuxw6h-1tls8aogc4443pb7zcq7c5gkf 163.172.XXX.YYY:2377 |
1 |
This node joined a swarm as a worker. |
Проверим список нод в Swarm-кластере
1 |
# docker node ls |
1 2 3 4 |
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION 0tan0z483jgw3rhpj6kndp60n * lxc Ready Active Leader 18.06.1-ce 01bpf2z62uloky089twg380je ubuntu161 Ready Active 18.06.1-ce rgchzlys98v1cj6mvzdrmqwie ubuntu162 Ready Active 18.09.0 |
Как видно, в даном случае 3 ноды в кластере, одна управляющая нода(lxc) и две рабочих ноды(ubuntu161 и ubuntu162)
По умолчанию в Docker Swarm контейнеры/службы/задачи могут запускаться,как на рабочих нодах(worker), так и на управляющих нодах(manager)
Для отключения запуска задач на управляющей ноде,чтобы она занималась только орекстрацией задач/контейнеров, а не их выполнением, установим для управляющей ноды дотупность в drain
1 |
# docker node update --availability drain lxc |
1 |
lxc |
Проверим,что статус управляющей ноды изменился с Active на Drain
1 |
# docker node ls | grep lxc |
1 |
0tan0z483jgw3rhpj6kndp60n * lxc Ready Drain Leader 18.06.1-ce |
Альтернативным вариантом для НЕ запуска задач на управляющей ноде используется параметр –constraint с указанным ниже значением
1 |
--constraint node.role==worker |
Запуск/деплой сервиса
Запуск приложения в кол-ве одной копии (—replicas 1) с именем tomcat(—name tomcat) из Docker-образа tomcat
Эта команда создает service и затем посылает задачу по запуску контейнера на одну из рабочих нод
1 |
# docker service create --replicas 1 --name tomcat tomcat |
Просмотр запущенных сервисов
1 |
# docker service ls |
Сервис tomcat запустился в одном контейнера
1 2 |
ID NAME MODE REPLICAS IMAGE PORTS x6e11qurmz4q tomcat replicated 1/1 tomcat:latest |
Для просмотра рабочей ноды,на которой был запущен контейнер с tomcat
1 |
# docker service ps tomcat |
1 2 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS hwx3mbu3lt9h tomcat.1 tomcat:latest ubuntu161 Running Running 2 minutes ago |
Как видно из вывода команды,контейнер запустился на рабочей ноде ubuntu161
Для получения более детальной информации о созданном tomcat service используем
1 |
# docker service inspect tomcat |
Проверим на рабочей ноде ubuntu161 наличие запущенного контейнера с tomcat
1 |
# docker ps |
1 2 |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8559c0850228 tomcat:latest "catalina.sh run" 4 minutes ago Up 4 minutes 8080/tcp tomcat.1.hwx3mbu3lt9h9yaes05gnjrq9 |
Масштабирование сервиса
Например, увеличим кол-во реплик(контейнеров) с 1-го до 3-х
1 |
# docker service scale tomcat=3 |
1 2 3 4 5 6 |
tomcat scaled to 3 overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged |
1 |
# docker service ps tomcat |
1 2 3 4 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS hwx3mbu3lt9h tomcat.1 tomcat:latest ubuntu161 Running Running 16 minutes ago rlgx0kxvga3q tomcat.2 tomcat:latest ubuntu162 Running Running 55 seconds ago r7swq41e9jqb tomcat.3 tomcat:latest ubuntu162 Running Running 55 seconds ago |
Проверим,что на рабочей ноде ubuntu162 запущено два контейнера
1 |
# docker ps |
1 2 3 |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 073f200f226b tomcat:latest "catalina.sh run" About a minute ago Up About a minute 8080/tcp tomcat.3.r7swq41e9jqbs2u391pcojapx de42a01c66bb tomcat:latest "catalina.sh run" About a minute ago Up About a minute 8080/tcp tomcat.2.rlgx0kxvga3qjvpgv5pjdpvf7 |
Удаление сервиса
Удалим сервис tomcat
1 |
# docker service rm tomcat |
1 |
tomcat |
1 |
# docker service ls |
1 |
ID NAME MODE REPLICAS IMAGE PORTS |
Публикация портов
Docker service подобно контейнерам используют port-forwarding механизм, заключающийся в перенаправлении портов с ноды на сервис/контейнер
Это достигается за счет использования опции
1 |
-p <host_port>:<container:port> |
Например, запустим tomcat сервисы с публикацией наружу(на рабочей ноде) порта 8080, который внутренним механизмом docker swarm(routing mesh) пробрасывается на любой активный контейнер на любой worker-ноде
1 |
# docker service create --replicas 1 --publish 8080:8080 --name tomcat tomcat |
1 2 3 4 |
im8c7q650wqwep78m2e4x9ffs overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged |
1 |
# docker service ls |
1 2 |
ID NAME MODE REPLICAS IMAGE PORTS im8c7q650wqw tomcat replicated 1/1 tomcat:latest *:8080->8080/tcp |
1 |
# docker service ps tomcat |
1 2 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS rs5e5dgxshf0 tomcat.1 tomcat:latest ubuntu161 Running Running about a minute ago |
Провеяем,что с наружи доступен Tomcat-сервер на рабочей ноде ubuntu161
1 |
# curl -Iv http://ubuntu161.mydomain.com:8080 |
На самом деле на каждой ноде в кластере автоматически средствами Docker Swarm создается правило для проброса порта 8080 снаружи внутрь на VIP-адрес(virtual IP), благодаря механизму routing mesh запрос будет переанаправлен на одну из нод, на которой запущен активный(действительно рабочий) контейнер с tomcat
1 |
root@ubuntu161 ~ # iptables -t nat -L | grep 8080 |
1 |
DNAT tcp -- anywhere anywhere tcp dpt:http-alt to:172.19.0.2:8080 |
В данном случае 172.19.0.2 — это VIP-адрес сервиса tomcat. Он создается/назначается динмамически при создании сервиса. И уже за этим VIP-адресом стоят ip-адреса контейнеров с tomcat, которые запускаются в сервисе tomcat.
Удобство Docker Swarm в том,что управляющая нода действует как лоадбалансер, распределяя входящие на нее запросы на порт 8080 на соответствующию ноды, на которых запущены контейнеры с tomcat. Этот внутренний механизм балансировки и используется по умолчанию
Управляющая нода следит за состоянием запущенных контейнеров на рабочих нодах, поддерживает всегда желаемое кол-во реплик, определяемых при запуске сервиса, перенаправляет запросы на действительно рабочие контейнеры tomcat
Поэтому достаточно все запросы адресовать на управляющую ноду, которая уже сама выберет подходящую рабочую ноду, на которой запущен контейнер, и перенаправит на такую рабочую ноду запрос
Однако также можно адресовать запросы на все worker-ноды(даже на те, на которых не запущены контейнеры, в таком случае внутренний механизмом routing mesh такие запросы будут перенаправлены на запущенные/активные контейнеры на другой ноде)
1 2 3 4 |
Docker Engine swarm mode makes it easy to publish ports for services to make them available to resources outside the swarm. All nodes participate in an ingress routing mesh. The routing mesh enables each node in the swarm to accept connections on published ports for any service running in the swarm, even if there’s no task running on the node. The routing mesh routes all incoming requests to published ports on available nodes to an active container. |
Полезные возможности Docker Swarm с точки зрения Continuous Delivery
1.Rolling-обновления
Возможность обновлять запущенный service без простоя (zero downtime)
Представляет собой автоматический метод замены реплики на реплики с новым/обновленным кодом/продуктом
Docker Swarm использует Rolling-обновления по умолчанию и они могут управляться с помощью двух параметров
1 |
update-delay |
– задержка между запуском одной реплики и остановки следующей реплики(по умолчанию 0 секунд)
1 |
update-parallelism |
– максимальное кол-во реплик обновляемых одновременно (по умолчанию 1)
Процесс rolling-обновления в Docker Swarm выглядит следующим образом
1 2 3 4 |
1.Останавливается кол-во реплик, определенных параметром update-parallelism 2.На их место запускается такое же кол-во обновленных контейнеров/задач 3.Если задача возвращает статус RUNNING, то ожидается период времени, указанный параметром update-delay 4.Если в любой время, любая задача возвращает состояние FAILED, тога процесс обновления становится на паузу/удержание |
Значение параметра update-parallelism следует устанавливать исходя из кол-ва реплик, которое мы запускам. Если такое кол-во маленькое и загрузка сервиса происходит быстро, то разумно оставить значение по умолчанию — 1
Значение параметра update-delay следует устанавливать длинее/дольше, чем ожидаемое время загрузки приложения, т.к. это позволяет своевременно обнаружить возможные ошибки после старта приложения и не позволит продолжить процесс обновления, а поставит его на паузу
Запустим 3 реплики/контейнера с tomcat 8-й версии и установим задержку обновления в 10 секунд
1 |
# docker service create --replicas 3 --name tomcat --update-delay 10s --publish 8080:8080 tomcat:latest |
1 2 3 4 5 6 |
phd8r5remhpqaerlca63vzgp7 overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged |
Проверим значение различных параметров
1 |
# docker service inspect --pretty tomcat |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
ID: phd8r5remhpqaerlca63vzgp7 Name: tomcat Service Mode: Replicated Replicas: 3 Placement: UpdateConfig: Parallelism: 1 Delay: 10s On failure: pause Monitoring Period: 5s Max failure ratio: 0 Update order: stop-first RollbackConfig: Parallelism: 1 On failure: pause Monitoring Period: 5s Max failure ratio: 0 Rollback order: stop-first ContainerSpec: Image: tomcat:latest@sha256:99df9b4bf508a5ff6e6575f0852ce5fdbb5ea3d308015f1b45b4530878922619 Init: false Resources: Endpoint Mode: vip Ports: PublishedPort = 8080 Protocol = tcp TargetPort = 8080 PublishMode = ingress |
Видно,что запущено 3 реплики контейнер tomcat:latest и задержка в обновлении составляет 10 секунд, кол-во одновременных обновлений-1
Обновим контейнер с tomcat с 8-й до 9-й версии
1 |
# docker service update --image tomcat:9 tomcat |
1 2 3 4 5 |
tomcat overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] |
В процессе обновления одна реплика с tomcat8 будет остановлена, на ее место запущена одна реплика с tomcat9, после чего будет выдержана пауза в 10 секунд.
После чего следующая реплика с tomcat8 будет остановлена, на ее место запущена одна реплика с tomcat9, снова пауза в 10 секунд. Таким образом будут обновлены все реплики
1 |
# docker service ps tomcat |
1 2 3 4 5 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS et1gutls31ye tomcat.1 tomcat:9 ubuntu161 Running Running less than a second ago 03xq590yjujp \_ tomcat.1 tomcat:latest ubuntu162 Shutdown Shutdown 2 seconds ago klfi8uw84s88 tomcat.2 tomcat:latest ubuntu162 Running Running about a minute ago gtlhvj8gi8er tomcat.3 tomcat:latest ubuntu161 Running Running about a minute ago |
1 |
# docker service ps tomcat |
1 2 3 4 5 6 7 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS et1gutls31ye tomcat.1 tomcat:9 ubuntu161 Running Running 32 seconds ago 03xq590yjujp \_ tomcat.1 tomcat:latest ubuntu162 Shutdown Shutdown 33 seconds ago l244lblp0v85 tomcat.2 tomcat:9 ubuntu162 Running Running 1 second ago klfi8uw84s88 \_ tomcat.2 tomcat:latest ubuntu162 Shutdown Shutdown 2 seconds ago z4tbsq4t5snj tomcat.3 tomcat:9 ubuntu161 Running Running 17 seconds ago gtlhvj8gi8er \_ tomcat.3 tomcat:latest ubuntu161 Shutdown Shutdown 18 seconds ago |
Если,например, нам необходимо откатиться до предыдущей версии приложение, то достаточно выполнить команду
1 |
# docker service rollback tomcat |
Draining nodes
Когда необходимо остановить рабочую ноду, например, для обслуживания или просто удалить ее с кластера, можно использовать Swarm draining-нод.
Перевод статуса ноды из состояния Active в состояние Drain приводит к тому, что управляющая нода перемещает все запущенные задачи/контейнеры с drain-ноды на остальные активне ноды путем остановки таких контейнеров на drain-ноде и запуске их на active-нодах
А также управляющая нода больше не посылает задачи на drain-ноду для запуска нових контейнеров.
В данный момент обе рабочие ноды находятся в статусе Active
1 |
# docker node ls | grep ubuntu |
1 2 |
01bpf2z62uloky089twg380je ubuntu161 Ready Active 18.06.1-ce rgchzlys98v1cj6mvzdrmqwie ubuntu162 Ready Active 18.09.0 |
C 2-я запущенными контейнерами на рабочей ноде ubuntu161 и 1-м — на ubuntu162
1 |
# docker service ps tomcat | grep ubuntu | grep -i running |
1 2 3 |
et1gutls31ye tomcat.1 tomcat:9 ubuntu161 Running Running 12 minutes ago l244lblp0v85 tomcat.2 tomcat:9 ubuntu162 Running Running 11 minutes ago z4tbsq4t5snj tomcat.3 tomcat:9 ubuntu161 Running Running 11 minutes ago |
Переведем рабочую ноду ubuntu162 в статус Drain
1 |
# docker node update --availability drain ubuntu162 |
1 |
ubuntu162 |
1 |
# docker node ls | grep ubuntu |
1 2 |
01bpf2z62uloky089twg380je ubuntu161 Ready Active 18.06.1-ce rgchzlys98v1cj6mvzdrmqwie ubuntu162 Ready Drain 18.09.0 |
Проверим,что запущенный контейнер на рабочей ноде ubuntu162 был перемещен на рабочую ноду ubuntu161
1 |
# docker service ps tomcat | grep ubuntu | grep -i running |
1 2 3 |
et1gutls31ye tomcat.1 tomcat:9 ubuntu161 Running Running 14 minutes ago ups2a79r9wg9 tomcat.2 tomcat:9 ubuntu161 Running Running 35 seconds ago z4tbsq4t5snj tomcat.3 tomcat:9 ubuntu161 Running Running 14 minutes ago |
Для первода состояния рабочей ноды из Drain в Active используем команду
1 |
# docker node update --availability active ubuntu162 |
1 |
ubuntu162 |
1 |
# docker node ls | grep ubuntu |
1 2 |
01bpf2z62uloky089twg380je ubuntu161 Ready Active 18.06.1-ce rgchzlys98v1cj6mvzdrmqwie ubuntu162 Ready Active 18.09.0 |
Несколько управляющих нод
Docker Swarm позволяет использовать 2-е и более упраляющие ноды
Для достижения отказоустойчивости в случае выхода со строя одной управляющей ноды рекомендуется использовать 2 или более управляющих нод
Для добавления второй управляющей ноды, выполним команду на действующей управляющей ноде
1 |
# docker swarm join-token manager |
1 2 3 |
To add a manager to this swarm, run the following command: docker swarm join --token SWMTKN-1-5cbvu9zv8u8o2qkddjlfctrd3lfbk2l1gek0hec1dsgexuxw6h-1fy7l7p6ofkvu3eb27aknxos9 163.172.XXX.YYY:2377 |
В результате выполнения предыдущей команды мы получаем команду, которую необходимо выполнить на ноде, которую нужно сделать управляющей
1 |
# docker swarm join --token SWMTKN-1-5cbvu9zv8u8o2qkddjlfctrd3lfbk2l1gek0hec1dsgexuxw6h-1fy7l7p6ofkvu3eb27aknxos9 163.172.XXX.YYY:2377 |
Другим вариантом добавление управляющей ноды может быть повышение роли одной из текущих рабочих нод до управляющей ноды
Например, переведем рабочую ноду ubuntu162 в статус управляющей
1 |
# docker node ls |
1 2 3 4 |
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION 0tan0z483jgw3rhpj6kndp60n * lxc Ready Drain Leader 18.06.1-ce 01bpf2z62uloky089twg380je ubuntu161 Ready Active 18.06.1-ce rgchzlys98v1cj6mvzdrmqwie ubuntu162 Ready Active 18.09.0 |
1 |
# docker node promote ubuntu162 |
1 |
Node ubuntu162 promoted to a manager in the swarm. |
1 |
# docker node ls |
1 2 3 4 |
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION 0tan0z483jgw3rhpj6kndp60n * lxc Ready Drain Leader 18.06.1-ce 01bpf2z62uloky089twg380je ubuntu161 Ready Active 18.06.1-ce rgchzlys98v1cj6mvzdrmqwie ubuntu162 Ready Active 18.09.0 |
т.е. в данный момент текущая активная нода lxc, имеющая статус Leader, которая и выполняет все управление Swarm-кластером, а нода ubuntu162, которая также является управляющей( ее значение в колонке manager status либо остается пустым либо изменяется на Reachable) находится в режиме ожидания и готовности подхватить роль Leader в случае проблем с текущей Leader-нодой
Лидер нода выбирается из управляючих нод путем Raft согласованного алгоритма.
Сам Raft-алгоритм имеет ограничение на количество управляющих нод. Распределенные решения
должны быть одобрены большинством управляющих узлов, называемых кворумом. Это означает, что рекомендуется нечетное количество управляющих узлов.
Для перевода назад из управляющей в рабочую ноду выполняем
1 |
# docker node demote ubuntu162 |
Стратегия планирования – распределения задач по рабочим нодам
Как Docker Swarm определяет на каких нодах какие задачи запускать?
Docker Swarm использует два критерия для выбора рабочей ноды
1.Доступность ресурсов – планировщик Docker Swarm имеет информацию о доступных ресурсах на рабочих нодах и запускает задачу на наименее загруженной рабочей ноде
2.Метки(labels) и ограничение(constrains)
Метки – это атрибут ноды. Некоторые метки назначаются автоматически(например, node.id или node.hostname), другие метки могут быть назначены администратором кластера(например, node.labels.segment)
Ограничения – применяется автором сервиса, например, для выбора конкретной ноды с определенной меткой
Метки разделяются на две категории
1 |
node.labels |
– добавляются администратором
1 |
engine.labels |
– собираются Docker Engine
Например, запустим на рабочей ноде ubuntu162 новый сервис/контейнер с именем tomcat2
Для этого будем использовать
1 |
--constraint 'node.hostname == ubuntu162' |
1 |
# docker service create --constraint 'node.hostname == ubuntu162' --name tomcat2 --replicas 1 --publish 8888:8080 tomcat:latest |
1 2 3 4 |
vjqqnz732r4wcbhxxzrutvjl7 overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged |
1 |
# docker service ps tomcat2 |
1 2 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 7n3m5nnpkf9j tomcat2.1 tomcat:latest ubuntu162 Running Running 27 seconds ago |
Добавим метку node.labels.segment со значением AA к ноде ubuntu162
1 |
# docker node update --label-add segment=AA ubuntu162 |
1 |
ubuntu162 |
1 |
# docker node inspect --pretty ubuntu162 |
1 2 3 4 5 6 7 8 9 |
ID: rgchzlys98v1cj6mvzdrmqwie Labels: - segment=AA Hostname: ubuntu162 Joined at: 2018-11-16 12:05:22.738177693 +0000 utc Status: State: Ready Availability: Active …… |
Теперь можно использовать эту метку для запуска сервиса
Например, запустим на рабочей ноде ubuntu162 новый сервис/контейнер с именем tomcat23
1 |
# docker service create --constraint 'node.labels.segment == AA' --name tomcat23 --replicas 1 --publish 8889:8080 tomcat:latest |
1 2 3 4 |
khevuj979wny81warqgbb0bcw overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged |
1 |
# docker service ps tomcat23 |
1 2 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS seq5maa7vjr1 tomcat23.1 tomcat:latest ubuntu162 Running Running 28 seconds ago |
Интеграция Docker Swarm и Docker Compose в Docker Stack
Docker Swarm запускает контейнеры на разных физических хостах не предоставляя связи между такими запущенными контейнерами(т.е. для того, чтобы контейнеры могли коммуницировать между собой необходимо вручную создавать такую сетевую связь)
Docker-compose, наоборот, запускает несколько взаимосвязанных между собой контейнеров, но в пределах одного физического сервера(т.е. горизонтальное масштабирование ограничено ресурсами одной физической ноды)
Docker Stack объединяет в себе обе технологи и позволяет запускать несколько связанных контейнеров на различных физических нодах(хостах Docker-кластера)
Возможность запуска нескольких контейнеров, описанных в Docker-compose на нескольких физических нодах кластера Dcocker-swarm реализуется с помощью Docker Stack
Создадим docker-compose.yaml файл, который будет запускать 3 контейнера с приложеним calculator и 1 контейнер с Redis размещая контейнеры на рабочих нодах ubuntu16{1..2}
1 |
# cat docker-compose.yaml |
1 2 3 4 5 6 7 8 9 10 11 12 |
version: "3" services: calculator: deploy: replicas: 3 image: mydocker.repo.servername/calculator:latest ports: - "8080:8080" redis: deploy: replicas: 1 image: redis:latest |
При этом docker-образ mydocker.repo.servername/calculator:latest уже должен присутствовать на всех рабочих нодах Swarm-кластера(иначе на ноде, на которой нет этого образа, не запустится приложение calculator). Альтернативным вариантом для получения рабочими нодами docker-образа mydocker.repo.servername/calculator:latest является использование параметра
1 |
--with-registry-auth |
при выполнении команды docker stack deploy(это позволит рабочим нодам аутентифицироваться в Docker-репозитарии и скачать этот образ)
Запуск такого стека приложений
1 |
# docker stack deploy --compose-file docker-compose.yaml app |
1 2 3 |
Creating network app_default Creating service app_calculator Creating service app_redis |
Просмотр наличия docker stack с именем app
1 |
# docker stack ls |
1 2 |
NAME SERVICES ORCHESTRATOR app 2 Swarm |
Просмотр списка задач в стеке app
1 |
# docker stack ps app |
1 2 3 4 5 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS r4a13jnzo81x app_redis.1 redis:latest ubuntu161 Running Preparing 7 seconds ago v9lp4rszjfbs app_calculator.1 mydocker.repo.servername/calculator:latest ubuntu162 Running Running 3 seconds ago 2ruw2ixbowc1 app_calculator.2 mydocker.repo.servername/calculator:latest ubuntu161 Running Running 5 seconds ago 009zxdbj9i98 app_calculator.3 mydocker.repo.servername/calculator:latest ubuntu162 Running Running 3 seconds ago |
Как видно, 2 контейнера с приложением запустились на рабочей ноде ubuntu162 и один – на ubuntu161.
Один контейнер с Redis запустился на рабочей ноде ubuntu161
Просмотр списка сервисов в стеке app
1 |
# docker stack services app |
1 2 3 |
ID NAME MODE REPLICAS IMAGE PORTS 3vxo2wtrejuo app_calculator replicated 3/3 mydocker.repo.servername/calculator:latest *:8080->8080/tcp yeafmbvtk0wu app_redis replicated 1/1 redis:latest |
1 |
# docker service ls |
1 2 3 |
ID NAME MODE REPLICAS IMAGE PORTS 3vxo2wtrejuo app_calculator replicated 3/3 mydocker.repo.servername/calculator:latest *:8080->8080/tcp yeafmbvtk0wu app_redis replicated 1/1 redis:latest |
1 |
# docker service ps app_calculator |
1 2 3 4 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS v9lp4rszjfbs app_calculator.1 mydocker.repo.servername/calculator:latest ubuntu162 Running Running 5 minutes ago 2ruw2ixbowc1 app_calculator.2 mydocker.repo.servername/calculator:latest ubuntu161 Running Running 5 minutes ago 009zxdbj9i98 app_calculator.3 mydocker.repo.servername/calculator:latest ubuntu162 Running Running 5 minutes ago |
1 |
# docker service ps app_redis |
1 2 |
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS r4a13jnzo81x app_redis.1 redis:latest ubuntu161 Running Running 5 minutes ago |
С управляющей ноды, а также с обоих рабочих нод, на которых запущено приложение калькулятор проверяем
1 |
# curl http://localhost:8080/sum?a=1\&b=2 |
1 |
3 |
Удаление docker stack
1 |
# docker stack rm app |
1 2 3 |
Removing service app_calculator Removing service app_redis Removing network app_default |
Источник: Книга Сontinuous delivery with Docker and Jenkins by Rafal Leszko