Настройка docker swarm кластера в Unix/Linux

Настройка docker swarm кластера в Unix/Linux

Docker Swarm — это родная кластеризация для Docker. Он превращает пул Docker хостов в один виртуальный хост.

Имеется:

  • swarm-node-1, будет выступать в роле менеджера (об этом немного ниже).
  • swarm-node-2, будет выступать как воркер (об этом немного ниже).
  • swarm-node-3, будет выступать как воркер (об этом немного ниже).

Основные моменты

  • Управление кластерами, интегрированное с Docker Engine: используется Docker Engine CLI (т.е коммандная оболочка) чтобы создать Docker Engine swarm кластер, где вы можете развернуть различные службы приложений. Вам не нужно дополнительное программное обеспечение для оркестровки, создания или управления всем этим делом. Не круто ли? Конечно!
  • Децентрализованный дизайн: вместо обработки дифференциации ролей узлов во время развертывания Docker Engine обрабатывает любую специализацию во время выполнения. Вы можете развернуть оба типа узлов (manager или workers) используя Docker Engine. Это означает, что вы можете создать целый swarm кластер с одного образа.
  • Модель декларативной службы: Docker Engine использует декларативный подход, позволяющий определить желаемое состояние различных служб в стеке приложений. Например, вы можете описать приложение, состоящее из службы веб-интерфейса с брокер-службами и БД на бэкэнде.
  • Масштабирование: Для каждой службы вы можете объявить количество задач, которые вы хотите запустить. Когда вы увеличиваете или уменьшаете масштаб, менеджер swarm кластера автоматически адаптируется путем добавления или удаления задач для поддержания желаемого состояния в кластере.
  • Согласование желаемого состояния: Менеджер-нода в swarm кластере постоянно контролирует состояние кластера и согласовывает любые различия между фактическим состоянием и вашим желаемым состоянием. Например, если вы настроили службу для запуска 10 репликаций контейнера и worker машину для 2-х сбоев реплик, то менеджер создаст две новые реплики, чтобы заменить реплики, которые разбились.
  • Сеть с несколькими узлами: вы можете указать overlay сеть для своих услуг. Менеджер swarm кластера автоматически присваивает адреса контейнерам в оверлейной сети, когда он инициализирует или обновляет приложение.
  • Обнаружение службы: узлы менеджера  swarm кластера назначают каждой службе в сварме уникальное DNS-имя и балансирует нагрузки с контейнерами. Вы можете запросить каждый контейнер, запущенный в «рое» через DNS-сервер, встроенный в swarm.
  • Балансировка нагрузки. Вы можете открыть порты для обслуживания внешнего балансировщика нагрузки. Внутри sawrm-а можно указать как стоит распределять контейнеры между узлами.
  • Безопастность по умолчанию: каждый узел в рое обеспечивает взаимную аутентификацию и шифрование TLS для обеспечения связи между собой и всеми другими узлами. У вас есть возможность использовать самоподписанные корневые сертификаты или сертификаты от пользовательского корневого центра сертификации.
  • Rolling обновление: во время развертывания (от слова rollout) вы можете постепенно добавлять обновления сервисов к узлам. Swarm-менеджер позволяет вам контролировать задержку между развертыванием службы на разных узлах. Если что-то пойдет не так, вы можете откатить задачу к предедущему релизу.

Перейдем к созданию docker кластера с использованием docker swarm.

Создание машин для Docker Swarm кластера

Docker swarm — это так званый режим, где узлы делятся на 2 типа:

  1. manager — Служит менеджером для workerа(ов).
  2. worker — Подчененные (узлы) manager-у.

С этого выплывает то, что для работы данного кластера нужен менеджер и воркер(ы), но кластер может обходиться без worker-узлов — вообще, т.к manager-ы (узлы) по-умолчанию  и так воркеры.

Среди manager-ор всегда имеется один, который на данный момент является лидером кластера. Все управляющие команды, которые выполняются на других менеджерах автоматически перенаправляются на него:

Активация Docker swarm mode

Создаем 1-ю ноду:

$ docker-machine create --driver virtualbox --virtualbox-cpu-count "2" --virtualbox-memory "2048" --virtualbox-disk-size "20000" swarm-node-1

Вывод:

Running pre-create checks...
Creating machine...
(swarm-node-1) Copying /Users/captain/.docker/machine/cache/boot2docker.iso to /Users/captain/.docker/machine/machines/swarm-node-1/boot2docker.iso...
(swarm-node-1) Creating VirtualBox VM...
(swarm-node-1) Creating SSH key...
(swarm-node-1) Starting the VM...
(swarm-node-1) Check network to re-create if needed...
(swarm-node-1) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env swarm-node-1

Чтобы посмотреть коннект с Docker клиента на Docker Engine, выполните:

$ docker-machine env swarm-node-1

Получаем вывод:

export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/captain/.docker/machine/machines/swarm-node-1"
export DOCKER_MACHINE_NAME="swarm-node-1"
# Run this command to configure your shell:
# eval $(docker-machine env swarm-node-1)

Ном говорят выполнить команду (для конфигурации shell):

# eval $(docker-machine env swarm-node-1)

Подключаемся к ноде:

$ docker-machine ssh swarm-node-1
                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/
 _                 _   ____     _            _
| |__   ___   ___ | |_|___ \ __| | ___   ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__|   <  __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 17.09.1-ce, build HEAD : e7de9ae - Fri Dec  8 19:41:36 UTC 2017
Docker version 17.09.1-ce, build 19e2cf6
docker@swarm-node-1:~$

Чтобы посмотреть какие сетевые интерфейсы имеются, выполняем:

docker@swarm-node-1:~$ ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:85:C7:EC:42
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

eth0      Link encap:Ethernet  HWaddr 08:00:27:0A:EC:10
          inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe0a:ec10/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:751 errors:0 dropped:0 overruns:0 frame:0
          TX packets:493 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:120619 (117.7 KiB)  TX bytes:123042 (120.1 KiB)

eth1      Link encap:Ethernet  HWaddr 08:00:27:3B:74:0F
          inet addr:192.168.99.100  Bcast:192.168.99.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe3b:740f/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:34 errors:0 dropped:0 overruns:0 frame:0
          TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:7063 (6.8 KiB)  TX bytes:6781 (6.6 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

docker@swarm-node-1:~$

Идем дальше…

Создаем 2-ю ноду:

$ docker-machine create --driver virtualbox --virtualbox-cpu-count "2" --virtualbox-memory "2048" --virtualbox-disk-size "20000" swarm-node-2

Чтобы посмотреть коннект с Docker клиента на Docker Engine, выполните:

$ docker-machine env swarm-node-2

Получаем вывод:

export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.101:2376"
export DOCKER_CERT_PATH="/Users/captain/.docker/machine/machines/swarm-node-2"
export DOCKER_MACHINE_NAME="swarm-node-2"
# Run this command to configure your shell:
# eval $(docker-machine env swarm-node-2)

Ном говорят выполнить команду (для конфигурации shell):

# eval $(docker-machine env swarm-node-2)

Подключаемся к ноде:

$ docker-machine ssh swarm-node-2

Чтобы посмотреть какие сетевые интерфейсы имеются, выполняем:

$ ifconfig

Чтобы не выполнять такой ряд команд, можно использовать:

$ docker-machine create \
-d virtualbox \
--virtualbox-cpu-count "2" \
--virtualbox-memory "2048" \
--virtualbox-disk-size "20000" \
--swarm \
--swarm-master \
--swarm-discovery token://SWARM_CLUSTER_TOKEN \
swarm-node-2

Где:

  • SWARM_CLUSTER_TOKEN — Токен от сварм кластера.

Этим действием, я добавлю создаваемую ноду к swarm кластеру в виде — swarm manager-а.

Чтобы добавить воркера в кластер, можно использовать:

$ docker-machine create \
-d virtualbox \
--virtualbox-cpu-count "2" \
--virtualbox-memory "2048" \
--virtualbox-disk-size "20000" \
--swarm \
--swarm-discovery token://SWARM_CLUSTER_TOKEN \
swarm-node-2

Где:

  • SWARM_CLUSTER_TOKEN — Токен от сварм кластера.

Следовотельно при таком расскладе:

$ docker-machine env --swarm swarm-node-2

Идем дальше…

Создаем 3-ю ноду:

$ docker-machine create --driver virtualbox --virtualbox-cpu-count "2" --virtualbox-memory "2048" --virtualbox-disk-size "20000" swarm-node-3

Чтобы посмотреть коннект с Docker клиента на Docker Engine, выполните:

$ docker-machine env swarm-node-3

Получаем вывод:

export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.102:2376"
export DOCKER_CERT_PATH="/Users/captain/.docker/machine/machines/swarm-node-3"
export DOCKER_MACHINE_NAME="swarm-node-3"
# Run this command to configure your shell:
# eval $(docker-machine env swarm-node-3)

Ном говорят выполнить команду (для конфигурации shell):

# eval $(docker-machine env swarm-node-3)

Подключаемся к ноде:

$ docker-machine ssh swarm-node-3

Чтобы посмотреть какие сетевые интерфейсы имеются, выполняем:

$ ifconfig

Ну что, 3 узла созданы для дальнейшего создания кластера:

$ docker-machine ls

NAME           ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
swarm-node-1   *        virtualbox   Running   tcp://192.168.99.100:2376           v17.09.1-ce
swarm-node-2   -        virtualbox   Running   tcp://192.168.99.101:2376           v17.09.1-ce
swarm-node-3   -        virtualbox   Running   tcp://192.168.99.102:2376           v17.09.1-ce

Инициализация вашего менеджера (manager)

Выбираем узел, который выступит как начальным лидером в кластере (Как я говорил, swarm-node-1 выступит в роле менеджера):

$ docker-machine ssh swarm-node-1

И, собственно, выполняем инициализацию менеджера:

docker@swarm-node-1:~$ docker swarm init --advertise-addr 192.168.99.100:2377
Swarm initialized: current node (lx5fnkz55n6b55y4nlaat03zx) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-1i7ik8b0n68ef90wnkyd69zt22onze1gctbquv8atkk1oj9yxe-5c1nk36dq340cir8s7riiq16m 192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

docker@swarm-node-1:~$

Где:

  • 192.168.99.100 — Это IP узла.
  • 2377 — Порт по которому будут общатся менеджер и воркер.

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

docker@swarm-node-1:~$ docker info

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

docker@swarm-node-1:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
gdoltr46rs5acsyxa3sromegc *   swarm-node-1        Ready               Active              Leader
docker@swarm-node-1:~$

Данный докер сварм уже инициализирован и готов к использованию, но состояние данного кластера —  неконсистентное (консистентное состояние кластера должно включать в себя, более 3-х менеджеров). И при таком раскладе, у нас ни отказоустойчивости, ни маштабирования (Для этого нужно подкинуть хотя бы несколько узлов для управления).

Добавление воркеров (workers)

Как я говорил, swarm-node-2 выступит в роле воркера:

$ docker-machine ssh swarm-node-2

И, выполняем:

docker@swarm-node-2:~$ docker swarm join --token SWMTKN-1-1i7ik8b0n68ef90wnkyd69zt22onze1gctbquv8atkk1oj9yxe-5c1nk36dq340cir8s7riiq16m 192.168.99.100:2377
This node joined a swarm as a worker.
docker@swarm-node-2:~$

Аналогичные действия проделываем и для 3-го узла, но одной командой:

$ docker-machine ssh swarm-node-3 "docker swarm join \
--token SWMTKN-1-1i7ik8b0n68ef90wnkyd69zt22onze1gctbquv8atkk1oj9yxe-5c1nk36dq340cir8s7riiq16m  \
192.168.99.100:2377"

Работать с узлами можно в любое время (создавать, добавлять, удалять узлы) — это никак не нарушит работоспособность созданного кластера.

Проверяем состояние кластера на менеджерском узле:

docker@swarm-node-1:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
lx5fnkz55n6b55y4nlaat03zx *   swarm-node-1        Ready               Active              Leader
mslk69yjtp04mgmerew60427i     swarm-node-2        Ready               Active
7d9sxj6aj5oj384eqtylnp350     swarm-node-3        Ready               Active
docker@swarm-node-1:~$

Как видно, все отлично работает!

Можно выкинуть один узел из кластера, например:

$ docker-machine ssh swarm-node-3 "docker swarm leave --force"

И можно проверить что вышло:

docker@swarm-node-1:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
lx5fnkz55n6b55y4nlaat03zx *   swarm-node-1        Ready               Active              Leader
mslk69yjtp04mgmerew60427i     swarm-node-2        Ready               Active
7d9sxj6aj5oj384eqtylnp350     swarm-node-3        Down                Active
docker@swarm-node-1:~$

Я верну как было:

$ docker-machine ssh swarm-node-3 "docker swarm join \
 > --token SWMTKN-1-1i7ik8b0n68ef90wnkyd69zt22onze1gctbquv8atkk1oj9yxe-5c1nk36dq340cir8s7riiq16m  \
 > 192.168.99.100:2377"
This node joined a swarm as a worker.

И проверяем сново:

docker@swarm-node-1:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
lx5fnkz55n6b55y4nlaat03zx *   swarm-node-1        Ready               Active              Leader
mslk69yjtp04mgmerew60427i     swarm-node-2        Ready               Active
7d9sxj6aj5oj384eqtylnp350     swarm-node-3        Down                Active
s81quwp4mr9qnndr4tmg54kxb     swarm-node-3        Ready               Active
docker@swarm-node-1:~$

Как видно с вывода выше, у нас есть рабочая и не рабочая нода (я за swarm-node-3), я ее щас удалю:

docker@swarm-node-1:~$ docker node rm 7d9sxj6aj5oj384eqtylnp350
7d9sxj6aj5oj384eqtylnp350
docker@swarm-node-1:~$

И смотрим сново:

docker@swarm-node-1:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
lx5fnkz55n6b55y4nlaat03zx *   swarm-node-1        Ready               Active              Leader
mslk69yjtp04mgmerew60427i     swarm-node-2        Ready               Active
s81quwp4mr9qnndr4tmg54kxb     swarm-node-3        Ready               Active
docker@swarm-node-1:~$

То что нада! Идем дальше 😉

Сетевое взаимодействие в кластере Docker Swarm

Docker swarm управляет сетью с несколькими узлами, которая поддерживает оверлейные сетевые службы. Диспетчер кластеров автоматически назначает виртуальные IP-адреса контейнерам, которые присоединяются к наложению. Сварм запускает встроенный DNS-сервер, что позволяет swarm-у также назначать каждому контейнеру уникальное DNS-имя, которое разрешимо из любого контейнера в оверлейной сети. Это значительно упрощает обнаружение служб и позволяет балансировать нагрузку с самого начала:

Сетевое взаимодействие в кластере docker swarm

Сетевое взаимодействие в кластере docker swarm

Подготовьте кластер для контейнерных сервисов, создав сетевой оверлей для прикрепляемых контейнеров, для этого:

$ docker network create \
--driver overlay \
--subnet 10.10.1.0/24 \
--opt encrypted \
services

Для того чтобы просмотреть сетевые интерфейсы, выполните:

docker@swarm-node-1:~$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
2cb106b2ff5b        bridge              bridge              local
930261177e8e        docker_gwbridge     bridge              local
1f09ded4338a        host                host                local
1dp6w3n47pdx        ingress             overlay             swarm
44daf4990847        none                null                local
g1p3glk9gews        services            overlay             swarm
docker@swarm-node-1:~$

Сеть создали, можно двигатся дальше.

Создание, запуск сервиса в Docker Swarm

Сервисы в кластере развертываются (деплоятся) простыми запросами на несколько контейнеров определенного образа. Например, если вы разворачиваете 5 репликаций контейнера веб-хоста, менеджер принимает запрос и инструктирует воркер-узлы запускать контейнеры до тех пор, пока не будет выполнено заданное количество реплик.

Swarm узлы обеспечивают проверку подлинности TLS и шифрование для обеспечения связи между узлами. Все это делается по умолчанию и не требует дополнительного внимания. Также возможно использовать самоподписанные сертификаты, но зачастую, — используется  все по умолчанию.

Создание, запуск сервиса в Docker Swarm

У меня менеджер нода — 1 и имеется 2 воркера. Давайте построим приложенько. Я не буду строить сразу отказоустойчивый кластер, по этому, запущу только 1 контейнер (для начала):

docker@swarm-node-1:~$ docker service create \
> --name busybox \
> --network services \
> busybox \
> sleep 3000
i97rdz05iwa9jbxepplrnoavr
Since --detach=false was not specified, tasks will be created in the background.
In a future release, --detach=false will become the default.
docker@swarm-node-1:~$

Смотрим что вышло:

docker@swarm-node-3:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
2b6a0da5d4e0        busybox:latest      "sleep 3000"        4 minutes ago       Up 4 minutes                            busybox.1.rvd3le97dekezp9d3ir6o0mbi
docker@swarm-node-3:~$

Т.к как у меня настроен докер сварм, он распределил нагрузку и закинул контейнер на 3-ю ноду (как работает баллансировака и скейлинг — позже!) чтобы проверить куда закинуло контейнер, выполняем на ноде (менеджер):

docker@swarm-node-1:~$ docker service ps busybox
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
rvd3le97deke        busybox.1           busybox:latest      swarm-node-3        Running             Running 2 minutes ago
docker@swarm-node-1:~$

Используйте полное имя контейнера, чтобы подключится к нему:

docker@swarm-node-3:~$ docker exec -it busybox.1.rvd3le97dekezp9d3ir6o0mbi /bin/sh
/ #

Следующие команды nslookup работают только в контейнере, подключенном к наложению. Попробуйте найти службу nginx:

/ # nslookup nginx
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      nginx
Address 1: 10.10.1.2
/ #

Address 1 — это IP-адрес для балансировки нагрузки. Вы можете протестировать подключение с помощью wget в busybox:

/ # wget -O- 10.10.1.2

Connecting to 10.10.1.2 (10.10.1.2:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
-                    100% |***********************************************************************************************************************************************************|   612   0:00:00 ETA
/ #

Кроме того, вы также можете просмотреть конкретные адреса контейнеров:

/ # nslookup tasks.nginx
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      tasks.nginx
Address 1: 10.10.1.4 b6bb9151f775.services
Address 2: 10.10.1.3 490149c284ee.services
/ #

Аналогичным образом, адреса прямого контейнера доступны из контейнера busybox:

/ # wget -O- 10.10.1.3
Connecting to 10.10.1.3 (10.10.1.3:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
-                    100% |***********************************************************************************************************************************************************|   612   0:00:00 ETA
/ #

Я уже задеплоил nginx в виде кластера, по этому — он виден с сетки  busybox (использую созданную сеть).

Обновление сервиса в Docker Swarm

Если у вас имеется 1 контейнер, то для его обновления, — нужно остановить контейнер, развернуть новый и запустить его. Но это приведет к небольшому даунтайму — не так ли? Когда используете сервис хотя бы с 2-мя репликациями простой сервиса не будет затронут (не беру во внимания кривизну рук и другие форс мажоры). Это достигается за счет того, что Docker обновляет контейнеры сервиса по очереди. То есть в один и тот же момент времени всегда есть хотя бы один работающий контейнер, который может обслужить запрос пользователя.

Для обновления (в том числе добавления и удаления) свойств сервиса, которые могут иметь несколько значений (например, —publish или —label), Docker предлагает использовать специальные опции, оканчивающиеся суффиксами -add и -rm.

Чтобы добавить метку в новый сервис, юзайте:

$ docker service update --label-add foo=bar nginx

Чтобы удалить созданную метку по имени, используйте:

$ docker service update --label-rm foo nginx

Чтобы удалить порты, используйте:

$ docker service update --publish-rm 80 nginx

Идем дальше…

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

Масштабирование и балансировка выглядит следующим образом:

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

Для распределения запросов между имеющимися нодами Docker используется схема называемая ingress load balacing. Суть этого механизма заключается в том, что на какую бы из нод не пришел запрос пользователя, он сначала пройдет через внутренний механизм балансировки, а затем будет перенаправлен на ту ноду, которая в данный момент может обслужить такой запрос. То есть, любая нода способна обработать запрос к любому из сервисов кластера.

Затем запустите пару веб-хостов со следующей командой:

$ docker service create \
--replicas 2 \
--name nginx \
--network services \
--publish 80:80 \
nginx

Данной командой, я запустил 2 реплики в моем кластере.

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

docker@swarm-node-1:~$ docker service ls

ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
uxovll7xua4h        nginx               replicated          2/2                 nginx:latest        *:80->80/tcp
docker@swarm-node-1:~$

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

docker@swarm-node-1:~$ docker service ps nginx

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
1f3g97a38r5t        nginx.1             nginx:latest        swarm-node-2        Running             Running 2 minutes ago
isebv5gj86rk        nginx.2             nginx:latest        swarm-node-1        Running             Running 2 minutes ago
docker@swarm-node-1:~$

На выходе показано, какие узлы запускают контейнеры.

Еще выполним несколько проверок, подключаемся к swarm-node-2:

$ docker-machine ssh swarm-node-2

Смотрим что ранается:

docker@swarm-node-2:~$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
490149c284ee        nginx:latest        "nginx -g 'daemon ..."   3 minutes ago       Up 3 minutes        80/tcp              nginx.1.1f3g97a38r5tx5341x916wvos
docker@swarm-node-2:~$

Аналогичные действия сделаю и на swarm-node-3:

$ docker-machine ssh swarm-node-3

Смотрим что ранается:

docker@swarm-node-3:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
docker@swarm-node-3:~$

Как видно с вывода, веб-контейнер не был запущен на 3-й ноде потому что он запущен на менеджере (как я уже говорил, менеджер может быть воркером):

docker@swarm-node-1:~$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
b6bb9151f775        nginx:latest        "nginx -g 'daemon ..."   5 minutes ago       Up 5 minutes        80/tcp              nginx.2.isebv5gj86rkvqukaprn7eqy7
docker@swarm-node-1:~$

Вроде бы круто! Не так ли?

Масштабирование сервиса Docker достигается за счет указания необходимого количества реплик. В тот момент, когда вам необходимо увеличить (или уменьшить) количество нод, обслуживающих запросы от клиента, вы просто обновляете свойства сервиса с указанием нужного значения опции —replicas:

$ docker service update --replicas 3 nginx

Я обновил реплику с 2-х до 3-х! Но при этом, стоит проверить и убедится что к-во доступных нод не меньше количества самих репликаций. И тем не менее, если так произошло что вы увеличели реплику, а количество нод меньше — то некоторые ноды запустят у себя более одного контейнера одного и того же сервиса (в противном случае Docker будет стараться запускать реплики одного сервиса на разных нодах).

Отказоустойчивость/Масштабирование в Docker Swarm

Отказоустойчивость сервиса гарантируется самим Docker. Это достигается в том числе за счет того, что в кластере могут одновременно работать несколько управляющих нод, которые могут в любой момент заменить вышедшего из строя лидера. Если говорить более подробно, то используется так называемый алгоритм поддержания распределенного консенсуса — Raft. Интересующимся рекомендую посмотреть эту замечательную визуальную демонстрацию: Raft в работе.

Raft и Docker

Raft: выбор нового лидера:

Raft: выбор нового лидера

Службы, выполняемые на кластере, легко масштабируются с помощью одного параметра. Вы можете объявить количество реплик, которые должна иметь служба, и менеджер docker swarm-а автоматически адаптируется путем добавления или удаления контейнеров для поддержания желаемого состояния.

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

Выполняем команду:

$ docker service inspect --pretty nginx

Получаем вывод:

ID:		uxovll7xua4h9jzpjjy1v2r8c
Name:		nginx
Service Mode:	Replicated
 Replicas:	3
Placement:
UpdateConfig:
 Parallelism:	1
 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:		nginx:latest@sha256:2ffc60a51c9d658594b63ef5acfac9d92f4e1550f633a3a16d898925c4e7f5a7
Resources:
Networks: services
Endpoint Mode:	vip
Ports:
 PublishedPort = 80
  Protocol = tcp
  TargetPort = 80
  PublishMode = ingress

Так уже лучше и наглядно! Создайте дополнительный контейнер для nginx, обновив скейлинг следующей командой:

docker@swarm-node-1:~$ docker service scale nginx=4

И смотрим что вышло:

docker@swarm-node-1:~$  docker service inspect --pretty nginx

ID:		uxovll7xua4h9jzpjjy1v2r8c
Name:		nginx
Service Mode:	Replicated
 Replicas:	4
Placement:
UpdateConfig:
 Parallelism:	1
 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:		nginx:latest@sha256:2ffc60a51c9d658594b63ef5acfac9d92f4e1550f633a3a16d898925c4e7f5a7
Resources:
Networks: services
Endpoint Mode:	vip
Ports:
 PublishedPort = 80
  Protocol = tcp
  TargetPort = 80
  PublishMode = ingress
docker@swarm-node-1:~$

Затем проверьте, какой узел был назначен для запуска 4-й задачи. Обратите внимание, что один узел может принимать несколько контейнеров одной и той же службы:

docker@swarm-node-1:~$ docker service ps nginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
1f3g97a38r5t        nginx.1             nginx:latest        swarm-node-2        Running             Running 2 hours ago
isebv5gj86rk        nginx.2             nginx:latest        swarm-node-1        Running             Running 2 hours ago
wnf9fanorvfc        nginx.3             nginx:latest        swarm-node-3        Running             Running about an hour ago
x8mdt3qwukjw        nginx.4             nginx:latest        swarm-node-3        Running             Running about a minute ago
docker@swarm-node-1:~$

Если вам придется масштабировать весь кластер или даже временно удалить узел, вы можете заранее подготовить swarm, обновив доступность узла. Очистите один из узлов вашего кластера с помощью приведенной ниже команды:

docker@swarm-node-1:~$ docker node update --availability=drain swarm-node-3
swarm-node-3
docker@swarm-node-1:~$

Где:

  • swarm-node-3 -Хостнейм машины!

Смотрим что вышло:

docker@swarm-node-1:~$ docker service ps nginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
1f3g97a38r5t        nginx.1             nginx:latest        swarm-node-2        Running             Running 2 hours ago
isebv5gj86rk        nginx.2             nginx:latest        swarm-node-1        Running             Running 2 hours ago
qvquy3sq4619        nginx.3             nginx:latest        swarm-node-1        Ready               Ready 2 seconds ago
wnf9fanorvfc         \_ nginx.3         nginx:latest        swarm-node-3        Shutdown            Running 3 seconds ago
o0jn01a2i9yi        nginx.4             nginx:latest        swarm-node-2        Ready               Ready 2 seconds ago
x8mdt3qwukjw         \_ nginx.4         nginx:latest        swarm-node-3        Shutdown            Running 3 seconds ago
docker@swarm-node-1:~$

Видим что кластер начал перенастраивать (расспределять) контейнеры. Менеджер перенесет все контейнеры, которые были запущены на выключенном узле в другое место на кластера. Увеличьте масштаб обслуживания снова:

$ docker service scale nginx=4

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

$ docker node update --availability=actives swarm-node-3

Где:

  • swarm-node-3 -Хостнейм машины!

Уменьшим к-во контейнеров:

docker@swarm-node-1:~$ docker service scale nginx=2

и потом, выполняем:

docker@swarm-node-1:~$ docker service ps nginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
l5ku34nj3b21        nginx.1             nginx:latest        swarm-node-2        Running             Running 3 minutes ago
isebv5gj86rk        nginx.2             nginx:latest        swarm-node-1        Running             Running 2 hours ago
docker@swarm-node-1:~$ docker service scale nginx=4
nginx scaled to 4
Since --detach=false was not specified, tasks will be scaled in the background.
In a future release, --detach=false will become the default.
docker@swarm-node-1:~$ docker service ps nginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                    ERROR               PORTS
l5ku34nj3b21        nginx.1             nginx:latest        swarm-node-2        Running             Running 3 minutes ago
isebv5gj86rk        nginx.2             nginx:latest        swarm-node-1        Running             Running 2 hours ago
slv94x427ar7        nginx.3             nginx:latest        swarm-node-3        Running             Running 1 second ago
yt6dcslaxwsf        nginx.4             nginx:latest        swarm-node-3        Running             Running less than a second ago
docker@swarm-node-1:~$

Вот и все, статья «Настройка docker swarm кластера в Unix/Linux» уже подошла к завершению.

2 thoughts on “Настройка docker swarm кластера в Unix/Linux

  1. Что-то ничего не понял. Что мы имеем в самом начале!!? docker-machine создаёт виртуалки на какой VirtualBox — откуда этот вируталбокс вообще берется?! Где мы запускаем вообще команды docker-machine ? Как вообще подключать ноды (то есть машины с исталлированным docker) к swarm ?
    Вероятно, у меня недостаточно знаний по docker, но эта статья только путает и сбивает с толку.

    • docker-machine использует различные драйвера, в качестве примера — я взял «VirtualBox». Можно использовать VMware, AWS, GCP и многие другие.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.