Docker Swarm — управляем контейнерами

Kubernetes в 2023 году является стандартом в управлении контейнерами, но иногда нужно что-то более легкое, с не столь высоким порогом вхождения.

Docker предлагает свой встроенный оркестратор — Docker Swarm. 

Если описать его работу коротко, то следует отметить следующее:

  • Docker Swarm объединяет Docker хосты в единый кластер и позволяет управлять их запуском и масштабированием.
  • Есть два типа нод, Manager — которые могут как управлять кластером, так и запускать сами контейнеры и Worker — являющиеся своего рода исполнителями.
  • При работе в кластере, помимо масштабирования происходит балансировка нагрузки, а значит повышается и отказоустойчивость нашего приложения.

Нет смысла сравнивать Kubernetes и Docker, нужно просто знать как работают оба, но если сказать совсем просто — Docker Swarm пригодится там где нужен быстрый и простой способ управлять контейнерами, не затрачивая много усилий, Kubernetes больше подойдет в задачах со сложной архитектурой, функционалом и масштабируемостью.

Перейдем к практике.
Устанавливать будем на CentOS 7.
Сначала вам необходимо установить на все виртуальные машины Docker (установка).
В нашей тестовой лабораторной работе будет 3 сервера (1 master и 2 worker ноды).

Схема следующая:
kuber-master — master
kube-node01 — worker1
kube-node02 — worker2

На мастер ноде выполняем

docker swarm init

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

Swarm initialized: current node (wh56mpocukah2oi4dba5b3kuy) is now a manager.

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

docker swarm join --token SWMTKN-1-34vtvtxxbcq9w4al42aurpyiq6rric9cv30bgb995idvppms5e-4ei04zll437bb16lko4kopgmx 10.0.8.68:2377

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

Проверяем список доступных нод

docker node ls

ID                            HOSTNAME           STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
wh56mpocukah2oi4dba5b3kuy *   kuber-master.lan   Ready     Active         Leader           24.0.6

Подключаем worker ноды, у вас будет свой токен и ip адрес

docker swarm join --token SWMTKN-1-34vtvtxxbcq9w4al42aurpyiq6rric9cv30bgb995idvppms5e-4ei04zll437bb16lko4kopgmx 10.0.8.68:2377

Копируем и запускаем на обе worker ноды
Если у вас появляется ошибка 

Error response from daemon: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 10.0.8.68:2377: connect: no route to host"

Проверьте настройки файервола, открыт ли порт 2377. Чтобы открыть сделаем

firewall-cmd --add-port=2377/tcp --permanent
firewall-cmd --reload

Далее пробуем еще раз и получаем в консоли

This node joined a swarm as a worker.

Проверяем на мастере

docker node ls
ID                            HOSTNAME           STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
wh56mpocukah2oi4dba5b3kuy *   kuber-master.lan   Ready     Active         Leader           24.0.6
0hwkwllvoxfd2lpw9j5fa7qdl     kuber-node01.lan   Ready     Active                          24.0.6
iwfyu36w553dq83keji7xh3pj     kuber-node02.lan   Ready     Active                          24.0.6

Деплоить будем nginx (быстро, просто и наглядно). Создаем на мастер ноде уже знакомый docker-compose.yml со следующим содержанием

version: "3.9"
services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == worker
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure

На что стоит обратить внимание.

  • deploy это конкретно секция для работы в docker swarm.

В этом примере мы запускаем сервис nginx, используя последний образ, пробрасываем 80 порт.

  • replicas: 1 указывает, на то, что должна быть запущено только одна реплика контейнера для этой службы.
  • placement: — это секция, в которой определяются ограничения на размещение сервиса.
  • constraints: — это список ограничений на размещение сервиса.
  • node.role == worker — это ограничение, которое говорит, что сервис должен быть развернут только на worker нодах.
  • update_config определяет, как Docker Swarm должен обновлять службу:
  • parallelism: 1 указывает, что Docker Swarm должен обновлять одну реплику контейнера за раз.
  • delay: 10s указывает, что Docker Swarm должен ждать 10 секунд перед обновлением следующей реплики.
  • restart_policy: condition: on-failure определяет, когда Docker Swarm должен перезапускать контейнер, в данном случае если в контейнере возникнет ошибка и он завершит работу

Важно отметить что Docker Swarm не перезапускает контейнеры, если они были явно остановлены пользователем.

Деплоим

docker stack deploy -c docker-compose.yml devopslife

Проверяем

docker stack services devopslife

ID             NAME               MODE         REPLICAS   IMAGE          PORTS
s9qirt16uztv   devopslife_nginx   replicated   0/1        nginx:latest   *:80->80/tcp


docker service ps s9qirt16uztv (id сервиса)

ID             NAME                 IMAGE          NODE               DESIRED STATE   CURRENT STATE                    ERROR     PORTS
wvh5jswsabft   devopslife_nginx.1   nginx:latest   kuber-node01.lan   Running         Running less than a second ago             

Для масштабирования, есть специальная команда

docker service scale devopslife_nginx=<количество_экземпляров>

Допустим сделаем 

docker service scale devopslife_nginx=2

devopslife_nginx scaled to 2
overall progress: 2 out of 2 tasks 
1/2: running   [==================================================>] 
2/2: running   [==================================================>] 
verify: Service converged 


docker service ps s9qirt16uztv

ID             NAME                 IMAGE          NODE               DESIRED STATE   CURRENT STATE                ERROR     PORTS
wvh5jswsabft   devopslife_nginx.1   nginx:latest   kuber-node01.lan   Running         Running about a minute ago             
fgq6t20wrfvc   devopslife_nginx.2   nginx:latest   kuber-node02.lan   Running         Running 22 seconds ago                 

Выключим одну из нод (имитируем выключение сервера)

Проверим

docker node ls
ID                            HOSTNAME           STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
wh56mpocukah2oi4dba5b3kuy *   kuber-master.lan   Ready     Active         Leader           24.0.6
0hwkwllvoxfd2lpw9j5fa7qdl     kuber-node01.lan   Ready     Active                          24.0.6
iwfyu36w553dq83keji7xh3pj     kuber-node02.lan   Down      Active                          24.0.6

Как видите одна из нод ушла в Down

docker service ps s9qirt16uztv
ID             NAME                     IMAGE          NODE               DESIRED STATE   CURRENT STATE                    ERROR     PORTS
wvh5jswsabft   devopslife_nginx.1       nginx:latest   kuber-node01.lan   Running         Running 3 minutes ago                      
x32uug6yyoaq   devopslife_nginx.2       nginx:latest   kuber-node01.lan   Running         Running less than a second ago             
fgq6t20wrfvc    \_ devopslife_nginx.2   nginx:latest   kuber-node02.lan   Shutdown        Running 2 minutes ago                      

Теперь восстановим работу сервера
И еще раз проверим

docker node ls
ID                            HOSTNAME           STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
wh56mpocukah2oi4dba5b3kuy *   kuber-master.lan   Ready     Active         Leader           24.0.6
0hwkwllvoxfd2lpw9j5fa7qdl     kuber-node01.lan   Ready     Active                          24.0.6
iwfyu36w553dq83keji7xh3pj     kuber-node02.lan   Ready     Active                          24.0.6

При заходе на ip адреса по 80 порту любой из машин мы увидим приветственное окно nginx

Можно еще выполнить

docker service scale devopslife_nginx=1

посмотреть что будет и вновь сделать

docker service scale devopslife_nginx=2

Для завершения работы необходимо выполнить команду

docker service rm <service_name>

docker service rm devopslife_nginx

Для выхода из кластера выполнить на каждой ноде

docker swarm leave (для worker)
или
docker swarm leave --force (для manager)

Получаем

Node left the swarm

Таким образом мы можем использовать Docker Swarm для управления и масштабирования контейнерами.

Photo by James Wainscoat on Unsplash