Настройка 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 типа:
- manager — Служит менеджером для workerа(ов).
- worker — Подчененные (узлы) manager-у.
С этого выплывает то, что для работы данного кластера нужен менеджер и воркер(ы), но кластер может обходиться без worker-узлов — вообще, т.к manager-ы (узлы) по-умолчанию и так воркеры.
Среди manager-ор всегда имеется один, который на данный момент является лидером кластера. Все управляющие команды, которые выполняются на других менеджерах автоматически перенаправляются на него:
Создаем 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 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 и шифрование для обеспечения связи между узлами. Все это делается по умолчанию и не требует дополнительного внимания. Также возможно использовать самоподписанные сертификаты, но зачастую, — используется все по умолчанию.
У меня менеджер нода — 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 используется схема называемая 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 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» уже подошла к завершению.
Что-то ничего не понял. Что мы имеем в самом начале!!? docker-machine создаёт виртуалки на какой VirtualBox — откуда этот вируталбокс вообще берется?! Где мы запускаем вообще команды docker-machine ? Как вообще подключать ноды (то есть машины с исталлированным docker) к swarm ?
Вероятно, у меня недостаточно знаний по docker, но эта статья только путает и сбивает с толку.
docker-machine использует различные драйвера, в качестве примера — я взял «VirtualBox». Можно использовать VMware, AWS, GCP и многие другие.