Skip to content

Instantly share code, notes, and snippets.

@binakot
Last active January 11, 2024 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save binakot/7b48361d5f611f68611b59a99230d1e3 to your computer and use it in GitHub Desktop.
Save binakot/7b48361d5f611f68611b59a99230d1e3 to your computer and use it in GitHub Desktop.
Docker Swarm

Docker Swarm

Общая концепция и диаграммы

Функционал

  • Оркестрация и конфигурирование кластера.

  • Децентрализованная архитектура. Нет главного узла, при падении которого отказывает вся система. Используется кворум между управляющими нодами. Упавший лидер заменяет один из его подчиненных.

  • Работает на основе docker-контейнеров. Кластеру без разницы, что в нем будет запускаться: frontend, backend, db и любые другие программные компоненты. Главное, чтобы они были упакованы в docker-образы.

  • Средства масштабирования. Каждому сервису можно указать необходимое количество реплик, которое будет автоматически поддерживаться в кластере.

  • Балансировка нагрузки "из коробки" с помощью перенаправления вызовов между репликами на основе публичного порта.

  • Управление и поддержание состояния кластера. Управляющие узлы следят за состоянием кластера (количество реплик, рабоющие узлы и прочее), и при необходимости меняют конфигурацию, чтобы она соответствовала исходным требованиям.

  • Внутренняя виртуальная сеть. Именование сервисов внутри сети с помощью DNS. Защищенный траффик внутри и между узлами на основе TLS.

  • Средства обновления компонентов кластера. Динамическое изменение настроек узлов и сервисов не требует остановки работы кластера.


Ключевые концепции

  • Docker Swarm кластером называется некое множество физических и/или виртуальных хостов с установленным Docker Engine, работающим в режиме swarm. Хосты могут выполнять роль менеджера (manager) или воркера (worker), либо и то, и другое одновременно. По умолчанию все управляющие ноды также являются рабочими и могут запускать в себе сервисы (режим active), но их можно настроить на работу только в качестве управляющих (режим drain).

  • Узлы деляться на 2 вида: управляющие (manager) и рабочие (worker). Управляющие узлы занимаются конфигурирование и оркестрацией кластера, именно они создают задачи для поддержания нужного количества реплик сервисов. Среди управляющих узлов всегда есть лидер (lead manager), остальные узлы являются его подчиненными (follow manager). При падении лидера, один из оставшихся узлов заменяет его. Рабочие узлы являются контейнерами для запуска docker-образов необходимых программных компонентов.

  • В кластере можно создать сервис (service) с необходимым количеством реплик (replicas), настройками виртуальной сети и доступными ресурсами (cpu, ram), а также портом для доступа из внешней сети и многое другое. Поддержкой работы необходимого количества реплик конкретного сервиса называется задачей (task). Задача назначается управляющим узлом определенному рабочему узлу в кластере. Запуск сервиса возможен в двух режимах: реплицированный (replicated), используемых по умолчанию, который запускает указанное количество реплик на свободных узлах, и глобальный (global), который запускает ровно по одной реплики на каждом узле (можно использовать для агентов мониторинга, антивирусных сканеров и прочего ПО, которое должно быть запущено на всех нодах, включая управляющие).

  • Для балансировки нагрузки между репликами используется ingress load balancing. Балансировка работает на основе заданного публичного порта и внутреннего DNS имени сервиса. Каждая из реплик по очереди обрабатывает запрос на указанный порт. Обращаться к сервису по его порту можно на любом узле кластера, он будет автоматически перенаправлен на нужный узел.

replicated-vs-global

ingress-routing-mesh


Общая диаграмма

Кластер состоит из двух видов узлов: менеджеры (manager) и воркеры (worker). Менеджеры занимаются управлением кластера, отвечают за консенсус и непрерывную работу сервисов. Сервисы запускаются и работают на рабочих нодах (воркерах).

swarm-diagram

Абстракция сервиса и задач

В кластере сервисом (service) называется программная компонента, которая должна быть запущена с определенным числом реплик. На изображение сервис nginx должен иметь 3 реплики в кластере. Обеспечение работы каждой реплики называется задачей (task). В данном примере сервис nginx должен иметь 3 реплики в кластере, соответственно мы имеем 3 задачи: nginx.1, nginx.2, nginx.3, которые отвечают за работу docker контейнера с образом nginx внутри.

Разработчики Docker Swarm рекомендуют держать нечетное количество менеджеров. Одного достаточно для тестовой среды. 3 достаточно для работы небольшого кластера. 5 оптимальный вариант для любой конфигурации. 7 и более менеджеров не имеет никакого смысла. Также для продакшен системы управляющие узлы должны располагаться на разных физических серверах.

Сервис в кластере создается командой docker service create с указанием имени сервиса. Команда отправляется на управляющую ноду. Узел создает задачи на рабочих нодах в соответствии с нужным количеством реплик. Задачи на рабочих нодах создаются, подготавливаются и запускаются. У задач могут быть различные состояния (полный список доступен здесь). Просмотреть список задач конкретного сервиса можно с помощью команды docker service ps <service-name>.

services-diagram


Защита

При создании кластера docker swarm init текущий хост становиться управляющим узлом. И по умолчанию генерируется сертификат для защиты трафика по алгоритму TLS. Можно использовать собственный сертификат с использованием ключа --external-ca. По умолчанию каждый узел в кластере обновляет свой сертификат каждые 3 месяца, возможно задать свое время жизни с помощью docker swarm update --cert-expiry <TIME PERIOD>. Также ключ может быть заменен, если есть опасность компрометирования, с помощью команды docker swarm ca --rotate.

Также первый управляющий узел генерирует 2 токена, с помощью которых можно подключать в кластер новые управляющие и рабочие узлы соответственно.

tls


Создание кластера

Инициализация

Инициализация режима кластера командой docker swarm init:

  • Создается новый кластер с именем default по умолчанию.

  • Текущий хост становится главным управляющим узлом (leader manager) и попадает в только что созданный кластер с именем по умолчанию совпадающим с именем хоста (hostname).

  • Управляющий узел начинает прослушивать порт 2377 по умолчанию.

  • Управляющий узел по умолчанию запускается в режиме active. Это означает, что он также выступает и в роли рабочего узла (worker) и может выполнять задачи (task) на запуск сервисов (service).

  • Генерируются новые сертификаты безопасности и токены для подключения новых узлов в кластер.

  • Создается новая виртуальная сеть с именем ingress по умолчанию.

При инициализации следует указать IP адрес управлющей ноды, к которой будут обращаться остальные хосты, добавляемые в кластер, т.к. по умолчанию используется указанный в hosts адрес (который может быть localhost). Выполняется это с помощью команды docker swarm init --advertise-addr <MANAGER-IP>. Для нашей локальной сети это может быть 192.168.0.123. Для продакшен системы это будет внешей IPv4 адрес сервера в сети Интернет.

Добавление узлов в кластер

Добавление происходит с помощью выполнения специальных команд с секретными токенами на хостах, которые надо добавить в кластер. Для получения команд с токенами для добавления менеджеров и воркеров можно выполнить следующие команды соответственно: docker swarm join-token manager и docker swarm join-token worker.

Подключение текущего хоста в кластеру командой docker swarm join --token <TOKEN> <MANAGER-IP>:2377:

  • Текущий хост с Docker Engine переходит в режим swarm.

  • Хост запрашивает TLS сертификат с управляющего узла.

  • Новый узел в кластере получит имя своего хоста (hostname) по умолчанию.

  • Новый узел подключится к кластеру в качестве роли, которая ему была задана: manager или worker. По умолчанию manager запускается в режиме active, что означает, что также является и worker.

  • Новый узел по умолчанию добавляется в виртуальную сеть с именем ingress.

В случае страха компрометирования токенов, как и с сертификатами CA, их можно заменить с помощью команды swarm join-token --rotate.

Управление кластером

  • Просмотреть список всех узлов docker node ls. Полный список возможных состояний можно посмотреть здесь.

  • Вывести подробную информацию по конкретному узлу docker node inspect <NODE-ID> --pretty. Без --pretty вывод происходит в JSON формате.

  • Переконфигурирование управляющего узла в режим drain, когда узел является только управляющим и не может выполнять задачи (task): docker node update --availability drain node-1.

  • Добавление мета-данных к конкретному узлу: docker node update --label-add foo --label-add bar=baz node-1. Мета-данные могут быть использованы в качестве специальной метки узла и прочее.

  • У управляющих и рабочих узлов можно менять роли с помощью специальных команды: перевести 2 рабочие ноды в управляющие docker node promote node-3 node-2 и перевести 2 управляющие ноды в рабочие docker node demote node-3 node-2.

  • Удалить текущую ноду из кластера docker swarm leave. После выхода хоста из кластера на управляющей ноде следует удалить ее из списка docker node rm node-2.

Запуск сервисов

  • Создать сервис в кластере docker service create nginx. По умолчанию создает сервис со случайно сгенерированным именем с одной репликой без дополнительных конфигураций и внешнего порта для доступа извне. Доступ к такому сервису вне кластера невозможен. Чтобы создать сервис с именем необходимо указать ключ --name, например docker service create --name my_web nginx. Также можно указать команду, которую должен выполнить контейнер сразу после запуска в конце docker service create --name helloworld alpine:3.6 ping docker.com.
# Типичное создание сервиса nginx с 3 репликами с доступом извне по порту 8080.
$ docker service create --name my_web \
                        --replicas 3 \
                        --publish 8080:80 \
                        nginx
  • В сервисе можно менять практически все параметры с помощью команды docker service update. Когда команда выполняется, старый контейнер уничтожается, на его место создается и запускается новый с обновленной конфигурацией. Например, укажем запущеному сервису внешний порт: docker service update --publish-add 80 my_web.

  • Удалить сервис из кластера можно командой docker service remove и указав его ID или имя.

  • Вывести список сервисов на текущем узле можно командой docker service ls.

  • При создании или обновлении сервиса можно указывать окружение: --env, --workdir, --user. Например,

$ docker service create --name helloworld \
  --env MYVAR=myvalue \
  --workdir /tmp \
  --user my_user \
  alpine ping docker.com
  • Также можно изменить команду, которая выполняется при запуске контейнера с помощью ключа --args: docker service update --args "ping docker.com" helloworld.

  • Внешний порт может быть указан 2 способами: 1) через --publish <TARGET-PORT>:<SERVICE-PORT> - этот способ позволяет маршрутизацию данного порта с любой ноды в кластере и использует встроенную балансировку нагрузки; 2) через --publish mode=host,target=<TARGET-PORT>,published=<SERVICE-PORT> - данный способ не создает "глобального" порта сервиса на всем кластере и не балансирует запросы между нодами, обращаясь к конкретной ноде, Вы 100 % попадете на реплику сервиса именно этой ноды.

  • В кластере можно создавать overlay сети и подключать к ним сервисы. Например, создадим сеть docker network create --driver overlay my-network. Все ноды после создания сети сразу же получают к ней доступ. Теперь добавим новый сервис в эту сеть:

$ docker service create \
  --replicas 3 \
  --network my-network \
  --name my-web \
  nginx
  • Можно также подключить к новой сети уже запущенные сервисы: docker service update --network-add my-network my-web, или удалить из сети: docker service update --network-rm my-network my-web.

  • При запуске сервиса можно указать доступное количество процессоров и памяти: --reserve-memory и --reserve-cpu. Внимание, резервирование именно для сервиса, т.е. суммы его реплик, а не для каждой реплики отдельно.

  • Тут можно почитать про разделение кластера на регионы и привязку отдельных сервисов к конкретным регионам.

  • Тут можно почитать про настройку поведения сервиса при обновлениях и их откатах.

  • Тут можно прочитать про mountинг внешних volumeов. Важное замечание: маунтинг внешних источников очень сильно снижает производительность, следует избегать этого.

  • Тут можно прочитать про использование шаблонов при создании сервисов. Очень удобно генерировать имена, например.

Управление конфигурациями (config)

Docker Swarm позволяет хранить конфигурации вне контейнеров. Их можно создавать, обновлять и удалять. Конфигурации можно хранить в compose файлах, которые поддерживаются как docker compose, так и docker stack. docker stack по сути аналог docker compose только в кластерной среде.

  • Создать новую конфигурацию можно командой echo "This is a config" | docker config create my-config -. Создется конфиг с именем my-config, который содержит строку "This is a config".

  • Чтобы какому-то сервису был доступен конфиг, это необходимо указать явно при создании или обновлении сервиса: docker service create --name redis --config my-config redis:alpine. Тут создается сервис redis с доступом к конфигу, который был создан выше. Конфиг по умолчанию доступен внутри контейнера по пути /my-config, т.е. в корне контейнера в каталоге с именем конфига в кластере.

  • Чтобы отключить конфиги от сервиса, необходимо обновить сам сервис: docker service update --config-rm my-config redis. Теперь конфиг сервису недоступен, и каталог /my-config не существует для контейнера.

  • Чтобы удалить конфиг из кластера, необходимо выполнить команду docker config rm my-config. Удаление конфига из кластера возможно только, если ни один сервис его не использует.

  • Для обновления конфига сначала создается новый конфиг с другим именем, например my-config-2. Старый конфиг заменятся на всех использующих его сервисах на новый через docker service update --config-rm my-config --config-add my-config-2 nginx. После чего старый конфиг удаляется из кластера docker config rm my-config.

Простой пример с конфигом index.html страницы:

Сама index-страница

<html>
  <head><title>Hello Docker</title></head>
  <body>
    <p>Hello Docker! You have deployed a HTML page.</p>
  </body>
</html>

Запускаем сервис, который будет использовать наш конфиг с домашней страницей

$ docker swarm init  # Запускаем кластер
$ docker config create homepage index.html  # Создаем конфиг с именем `homepage` с этой `index.html` страницей
$ docker service create  # Запускаем сервис и передаем наш конфиг со страницей в него
    --name my-iis
    -p 8000:8000
    --config src=homepage,target="\inetpub\wwwroot\index.html"
    microsoft/iis:nanoserver  

Открывает адрес http://localhost:8000 и видим нашу index.html страницу.

Тут можно посмотреть более сложный пример с использованием конфигов для подключения сертификатов CA к nginx. Создается два secret для хранения открытого и закрытого ключей, а также создается конфиг с настройками nginx для использования HTTPS с этими ключами. Очень хорошо описан, кстати, процесс генерации SSL ключей.

Конфеденциальные данные (secret)

Для хранения секретов используется отдельный механизм, похожий на конфиги, но секреты в отличии от конфигов зашифровываются и не могут быть прочитаны в открытом виде. Для секретов идеально подходят: логины и пароли, TLS сертификаты и ключи, SSH ключи, другие конфеденциальные данные. Если конфиги доступны в корне контейнера в каталоге с именем конфига /<CONFIG-NAME>, то секреты доступны по пути /run/secrets/<SECRET_NAME>. Секреты, как и конфиги работают как с docker compose, так и с docker stack`.

  • Для создания секрета используется команда echo "This is a secret" | docker secret create my_secret_data -, которая создаст секрет с именем my_secret_data и строкой внутри "This is a secret".

  • Чтобы секрет был доступен в сервисе, сервису необходимо дать к нему доступ при создании или обновлении: docker service create --name redis --secret my_secret_data redis:alpine.

  • Чтобы запретить конкретному сервису доступ к секрету, необходимо использовать команду docker service update --secret-rm my_secret_data redis.

  • Чтобы удалить секрет из кластера, необходимо выполнить команду docker secret rm my_secret_data. Удаление секрета невозможно, пока есть хотя бы один сервис, который его использует. Сначала отключаем доступ у всех сервисов, потом удаляем сам секрет из кластера.

  • Для обновления секрета сначала создается новый секрет с другим именем. Старый секрет заменятся на всех использующих его сервисах на новый. После чего старый секрет удаляется из кластера.

Простой пример с секретом index.html страницы:

Сама index-страница

<html>
  <head><title>Hello Docker</title></head>
  <body>
    <p>Hello Docker! You have deployed a HTML page.</p>
  </body>
</html>

Запускаем сервис, который будет использовать наш секрет с домашней страницей

$ docker swarm init  # Запускаем кластер
$ docker secret create homepage index.html  # Создаем секрет с именем `homepage` с этой `index.html` страницей
$ docker service create  # Запускаем сервис и передаем наш конфиг со страницей в него
    --name my-iis
    -p 8000:8000
    --secret src=homepage,target="\inetpub\wwwroot\index.html"
    microsoft/iis:nanoserver  

Открывает адрес http://localhost:8000 и видим нашу index.html страницу.

Тут можно посмотреть более сложный пример с использованием секретов для подключения сертификатов CA к nginx. Создается три secret для хранения открытого и закрытого ключей, а также с настройками nginx для использования HTTPS с этими ключами. Очень хорошо описан, кстати, процесс генерации SSL ключей.

Пример использования секретов в docker-compose файле:

version: '3.1'

services:
   db:
     image: mysql:latest
     volumes:
       - db_data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_root_password
       - db_password

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_password


secrets:
   db_password:
     file: db_password.txt
   db_root_password:
     file: db_root_password.txt

volumes:
    db_data:

Блокирование узлов кластера при их восстановлении (autolock)

После инициализации кластера и подключения узлов к нему, система начинает работать. В процессе эксплуатации узлы могут выходить из строя, перезагружаться, отваливаться и прочее. После восстановления работы узел обратно подключается к кластеру. Данное подключение является возможной брешью в защите.

Для этого в Docker Swarm есть возможность запустить кластер в режиме авто-блокировки: docker swarm init --autolock. Ключ --autolock не позволит подключиться восстановившемуся узлу к кластеру, пока не будет выполнена команда docker swarm unlock со специальным ключом разблокировки, сгенерированным при инициализации кластера. Так гарантируется, что подключается именно тот хост, который был до падения узла.

Ключ --autolock оказывается влияние только на отвалившиеся узлы, при добавлении новых через docker swarm join он не требуется.

Режим можно переключать в работающем кластере через команду docker swarm update --autolock=true. Чтобы вывести ключ, необходимый для разблокировки кластера, требуется ввести команду docker swarm unlock-key. Ключ также можно пересоздать командой docker swarm unlock-key --rotate, если есть подозрения его компрометирования.

Виртуальные сети кластера (network)

В кластере генерируется 2 вида трафика: служебный (управление состоянием кластера и поддержкание его работы) и апликационный (обмен данными между сервисами и с внейшей сетью).

Основные виды сетевого взаимодействия:

  • overlay - частная виртуальная сеть для общения docker-контейнеров между собой. Можно создавать и привязывать сервисы к своим overlay-сетям. Для создания новой overlay сети: docker network create --driver overlay my-network. Для просмотра информации о сети: docker network inspect my-network. Overlay сеть по умолчанию не используется шифрование трафика, чтобы его влючить достаточно указать ключ --opt encrypted, но шифрование трафика внутри кластера для overlay-сетей оказывается влияние на производительность. По умолчанию, сеть используется виртуальные ip-адреса для каждой реплики каждого сервиса. Можно перевести сеть на использование DNS имен с помощью ключа --endpoint-mode dnsrr, который позволяет использовать свои собственные алгоритмы балансировки (DNS round-robin и прочие, основанные на доменных именах).

  • ingress - специальная виртуальная сеть для реализации балансировки нагрузки между репликами одного сервиса. Когда в кластер на любой из узлов приходит запрос на определенный публичный порт, кластер перенаправляет этот запрос на нужную ноду, балансирую между репликами сервиса, который был назначен на этот порт. Эта сеть создается по умолчанию и в большинстве случаев (никогда) ее не стоит переконфигурировать.

  • docker_gwbridge - это мост между физически разделенными хостами кластера. Он создается автоматически при подключении нового хоста к кластеру. В большинстве случаев (никогда) его не стоит переконфигурировать.

Для вывода всех сетей можно выполнить команду docker network ls.

При создании overlay сети можно задать различные настройки:

$ docker network create \
  --driver overlay \
  --subnet 10.0.9.0/24 \
  --gateway 10.0.9.99 \
  my-network

Рекомендуется создавать сети только с ограничением в 24 блока (/24), который используется по умолчанию. Это позволяет создавать внутри сети 256 ip-адресов. Другие размеры блоков оказывают влияние на производительность кластера.

Для создания сервиса и добавления его в конкретную сеть используется команда:

$ docker service create \
  --replicas 3 \
  --name my-web \
  --network my-network \
  nginx

Объединение сервисов в группы (stack)

В Docker Swarm можно запускать группы контейнеров с помощью compose файлов формата yml. Для этого синтаксис docker-compose был расширен для работы с кластером. Список команд можно посмотреть тут.

Добавить сервисы в кластер из compose файла можно командой docker stack deploy -c <COMPOSE_FILE> <STACK_NAME>. И также весь стек можно легко удалить командой docker stack rm <STACK_NAME>. Вывести список стеков в кластере можно командой docker stack ls.

Стеки очень удобны для объединения сервисов в группы. Например, стек микросервисов, стек инфраструктуры, стек средств мониторинга, стек утилит для работы с самим кластером и прочее.

Здесь можно посмотреть примеры.

Прочее

  • Никогда не стоит перезагружать управляющий узел, просто скопировав его кластерные настройки из raft каталога. Лучше всего удалить его из кластера и подключить снова:
$ docker node demote <NODE>  ## Делаем узел обычным воркером
$ docker node rm <NODE>  ## Удаляем узел из кластера
$ docker swarm join  ## Подключаем хост как новый узел
  • Узел можно принудительно удалить с помощью специального ключа --force : docker node rm --force node9. Это следует делать, когда узел недоступен или окончательно сломался и удалить его безопасным способом невозможно.

  • Возможно создавать backup кластера, просто архивируя каталог /var/lib/docker/swarm, в котором находятся все настройки, логи и данные docker swarm. Для восстановления достаточно просто восстановить каталог и перезагрузить узел. Здесь более подробная инструкция.

  • В docker swarm нет автоматической ребалансировки реплик сервисов между узлами, т.е. как они были созданы после docker service create, т.к они и остануться. Но есть ключ --force, который позволяет обновить сервис и заставить кластер пересмотреть физическое расположение реплик на нодах: docker service update --force.

  • Тут можно прочитать про настройку внешнего балансировщика (HAProxy).


Полезные ссылки

Raft

Raft - алгоритм для решения задач консенсуса в сети ненадёжных вычислений. На данном алгоритме основана работа Docker Swarm.

Docker Swarm

Статьи

Порты

  • 2377 (tcp) - взаимодействие узлов для управления кластером

  • 7946 (tcp/udp) - взаимодействие между всеми узлами

  • 4789 (udp) - трафик внутри overlay сетей

  • ip protocol 50 (ESP) - требуется для работы шифрованных overlay сетей (--opt encrypted)

API


Руководство инициализации и настройки кластера

Требования

  • 3 физически разделенных сервера (server1, server2, server3).

  • Доступность серверов друг к другу внутри одной сети (статические IP адреса).

  • Открыте порты на серверах для коммуникации по сети (список портов в разделе выше).

  • Ubuntu 16.04 LTS с установленным Docker версии 1.12+. Гайд по установке на Ubuntu тут.

Конфигурация кластера

  • server1 будет управляющим узлом manager1

  • server2 и server3 будут рабочими узлами worker1 и worker2

Инициализация кластера

Заходим на server1 и выполняем команду: docker swarm init --advertise-addr <MANAGER-IP>, где <MANAGER-IP> - IP адрес server1 в локальной сети с server2 и server3. Например 192.168.0.62.

Запустите команду docker info, чтобы получить информацию о кластере, и команду docker node ls, чтобы увидеть все узлы в кластере.

Добавление узлов в кластер

Чтобы подключать управляющие и рабочие узлы, используется специальные токены, которые выводятся при инициализации кластера и при выполнении команд:

docker swarm join-token manager
docker swarm join-token worker

Подключаем server2 и server3 как рабочие узлы к кластеру с помощью команды:

$ docker swarm join \
  --token  <WORKER_TOKEN> \
  <MANAGER-IP>:2377

Где <WORKER_TOKEN> - токен, который был сгенерирован при инициализации кластера для добавляения рабочих узлов.

Выполним на управлящей ноде manager1 на сервере server1 команду docker node ls, чтобы увидеть список всех узлов в кластере.

Запуск сервисов в кластере

На управляющем узле для создания сервиса необходимо выполнить команду:

docker service create --replicas 1 --name helloworld alpine ping docker.com

Для просмотра списка сервисов в кластере можно выполнить команду docker service ls.

Для просмотра на каких узлах запущен конкретный сервис можно выполнить команду docker service ps <SERVICE-ID>, где <SERVICE-ID> - уникальный ID или имя сервиса.

Для вывода подробной информации о конкретном сервисе можно выполнить команду docker service inspect --pretty <SERVICE-ID>.

Для просмотра запущенных контейнеров на текущем узле выполнить команду docker ps.

Масштабирование сервисов в кластере

Для масштабирования запущенного сервиса достаточно выполнить команду docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>.

Для проверки работы масштабирования достаточно выполнить команду docker service ps <SERVICE-ID>.

Удаление сервиса из кластера

Для удаления севриса (всех его реплик) достаточно выполнить команду docker service rm <SERVICE-ID>.

Для проверки, что сервис был удален можно использовать команду docker service inspect <SERVICE-ID>.

Обновление сервиса в кластере

Создадим новый сервис:

$ docker service create \
  --replicas 3 \
  --name redis \
  --update-delay 10s \
  redis:3.0.6

Проверим, что он создался docker service inspect --pretty redis.

Теперь обновим версии образа внутри контейнера docker service update --image redis:3.0.7 redis. Данная команда остановит каждую из реплик по отдельности, обновит образ используемого redis и запустит его.

Проверим, что redis обновился docker service inspect --pretty redis.

Настройка узла только в качестве управляющей ноды

По умолчанию управляющие ноды также являются воркерами (availability равно ACTIVE).

Чтобы сделать ноду только управляющей достаточно обновить ее настройки: docker node update --availability drain <NODE-ID>, где <NODE-ID> - ID или имя узла кластера.

Чтобы сделать управляющую ноду опять способной запускать реплики, вновь обновляем настройки: docker node update --availability active <NODE-ID>.

Доступ к сервису извне

Для доступа к сервису внутри кластера требуется указать внешний порт с помощью специального ключа:

$ docker service create \
  --name <SERVICE-NAME> \
  --publish <PUBLISHED-PORT>:<TARGET-PORT> \
  <IMAGE>

Например, для nginx:

$ docker service create \
  --name my-web \
  --publish 8080:80 \
  --replicas 2 \
  nginx

Можно добавить публичный порт уже запущенному сервису с помощью команды: docker service update --publish-add <PUBLISHED-PORT>:<TARGET-PORT> <SERVICE-ID>.

Можно также публиковать только tcp или udp порты с помощью явного указания: 53:53/tcp или 53:53/udp.


Быстрый сценарий все пощупать 👶

  • Настраиваем 3 Ubuntu сервера в одной сети. Настраиваем SSH доступ и фаерволл (ssh и docker swarm порты). Устанавливаем Docker.

  • Инициализируем кластер на server1:

$ sudo docker swarm init --advertise-addr 192.168.0.62
$ sudo docker info
$ sudo docker node ls
  • Добавляем server2 и server3 в кластер (команды запускается на server2 и server3):
$ sudo docker swarm join \
  --token  <WORKER_TOKEN> \
  192.168.0.62.100:2377
  • На управляющей ноде (server1) проверяем, что все подключились:
$ sudo docker node ls
  • Запускаем первый сервис (подобные команды работают только на управляющих нодах):
$ sudo docker service create --replicas 1 --name helloworld alpine ping docker.com
$ sudo docker service ls
$ sudo docker service inspect --pretty helloworld
$ sudo docker service ps helloworld
  • На каждой из нод можно посмотреть, что именно на ней запущено:
$ sudo docker ps
  • Масштабируем сервис до 5 реплик:
$ sudo docker service scale helloworld=5
$ sudo docker service ps helloworld
$ sudo docker ps
  • Удаляем сервис из кластера:
$ sudo docker service rm helloworld
$ sudo docker service inspect helloworld
$ sudo docker ps
  • Создадим другой сервис для тестов обновления:
$ sudo docker service create \
  --replicas 3 \
  --name redis \
  --update-delay 10s \
  redis:3.0.6
$ sudo docker service inspect --pretty redis
$ sudo docker service ls
  • Теперь попробуем обновить его:
$ sudo docker service update --image redis:3.0.7 redis
$ sudo docker service inspect --pretty redis
$ sudo docker service ls
  • Перевод worker1 (server2) в неактивное (drain) состояние:
# До отлючения worker1 
$ sudo docker node ls
$ sudo docker node inspect --pretty pmk-local-2
$ sudo docker service ps redis

# После отключения worker1 
$ sudo docker node update --availability drain pmk-local-2
$ sudo docker node ls
$ sudo docker node inspect --pretty pmk-local-2
$ sudo docker service ps redis

# Активируем worker1 обратно
$ sudo docker node update --availability active pmk-local-2
$ sudo docker node ls
$ sudo docker node inspect --pretty pmk-local-2
$ sudo docker service ps redis
  • Добавим еще один сервис для тестирования доступа извне:
$ sudo docker service create \
  --name my-web \
  --publish 8080:80 \
  --replicas 2 \
  nginx
$ sudo docker service ps my-web

Теперь с любого узла по порту 8080 доступен сервер nginx:


Portainer

Запустить панель управления кластером Portainer на порту 5000 на всех управляющий узлах:

$ sudo docker service create \
  --name portainer \
  --publish 5000:9000 \
  --constraint node.role==manager \
  --mode global \
  --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
  portainer/portainer \
  -H unix:///var/run/docker.sock

GitHub


Docker Swarm Visualizer

Запустить простой GUI для мониторинга кластера на порту 5001 на всех управляющий узлах:

$ sudo docker service create \
  --name swarm-visualizer \
  --publish 5001:8080 \
  --constraint node.role==manager \
  --mode global \
  --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
  dockersamples/visualizer

GitHub


Dvizz - Docker Swarm Visualizer (fork)

Запустить простой GUI для мониторинга кластера на порту 5002 на всех управляющий узлах:

$ sudo docker service create \
  --name dvizz \
  --publish 5002:6969 \
  --constraint node.role==manager \
  --mode global \
  --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
  eriklupander/dvizz

GitHub


RabbitMQ

$ sudo docker service create \
  --name rabbitmq \
  --publish 5672:5672 \
  --publish 15672:15672 \
  rabbitmq:3-management

PgAdmin4

$ sudo docker service create \
  --name pgadmin4 \
  -e "PGADMIN_DEFAULT_EMAIL=admin" \
  -e "PGADMIN_DEFAULT_PASSWORD=password" \
  --publish 5555:80 \
  --replicas 1 \
  dpage/pgadmin4

@binakot
Copy link
Author

binakot commented Jan 11, 2024

tls
swarm-diagram
services-diagram
replicated-vs-global
ingress-routing-mesh

@binakot
Copy link
Author

binakot commented Jan 11, 2024

Мой доклад на тему Docker Swarm: https://youtu.be/BrOUx5AMOBE?si=Kk2YF0IHXsXvncLt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment