Блог / Статьи

Полезная информация для вашего хостинга

В мир оркестрации контейнеров: Docker Swarm на Ubuntu 24.04

В мир оркестрации контейнеров: Docker Swarm на Ubuntu 24.04

Содержание

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

Среди множества решений для оркестрации контейнеров особое место занимает Docker Swarm Mode. Встроенный непосредственно в Docker Engine начиная с версии 1.12, он не требует установки сторонних компонентов, таких как etcd или Consul, и управляется уже привычными командами вроде docker service. Это делает Swarm идеальным выбором для команд, которые хотят быстро перейти от локального запуска контейнеров к полноценной распределённой инфраструктуре.

Swarm особенно подходит для небольших и средних кластеров — вплоть до 50 узлов — где доминируют stateless-приложения: веб-серверы, REST API, микросервисы, фоновые обработчики. В то время как Kubernetes предлагает гибкость и мощность для сложных сценариев (например, Canary-деплои, сложные сетевые политики или кластеры свыше 100 узлов), Swarm остаётся оптимальным решением для тех, кто ценит простоту, скорость настройки и минимальные накладные расходы на обслуживание.

В этой статье мы детально разберём, как построить полноценный кластер Docker Swarm на свежей операционной системе Ubuntu 24.04 Noble Numbat, развернуть в нём веб-сервер и API-сервис, настроить безопасную передачу конфигураций и секретов, а также продемонстрируем взаимодействие между компонентами. Погружайтесь — вас ждёт практическое путешествие в мир распределённых систем.

Подготовка инфраструктуры: основа надёжного кластера

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

В архитектуре Swarm различают два типа узлов:

  • Менеджеры (managers) — управляющие ноды, отвечающие за принятие решений, хранение состояния кластера и обработку команд от администратора. Они используют алгоритм Raft Consensus для обеспечения согласованности данных даже при отказе части узлов. Для отказоустойчивости рекомендуется использовать нечётное количество менеджеров — минимум 3, чтобы кластер оставался работоспособным при потере одной ноды.
  • Воркеры (workers) — исполнительные узлы, на которых фактически запускаются контейнеры. Они получают задачи от менеджеров и не участвуют в управлении состоянием кластера.

Важно понимать: любой менеджер по умолчанию также является воркером. Это означает, что на нём могут запускаться задачи, если только вы явно не переведёте его в режим «только управление» с помощью команды docker node update --availability drain.

Сетевые требования кластера Swarm строги и обязательны. Ниже перечислены ключевые порты, которые должны быть открыты во внутренней сети между всеми узлами:

  • 2377/tcp — для присоединения новых узлов и управления кластером (только между менеджерами и для команды join).
  • 7946/tcp и 7946/udp — для обнаружения узлов (node discovery) и распределённого управления overlay-сетями.
  • 4789/udp — для VXLAN-туннелей, через которые транспортируется трафик в overlay-сетях между контейнерами на разных нодах.

Если используется файрвол (например, ufw или nftables), убедитесь, что эти порты открыты. В продакшене также рекомендуется ограничить доступ к порту 2377 только доверенными IP-адресами, чтобы предотвратить несанкционированное присоединение узлов.

Теперь перейдём к подготовке серверов. На каждом узле кластера (и менеджерах, и воркерах) выполните следующие шаги:

sudo apt update && sudo apt upgrade -y

Эта команда обновляет индекс пакетов и устанавливает последние обновления безопасности и функциональности. Затем установите Docker Engine из официального репозитория Ubuntu:

sudo apt install -y docker.io

На момент выхода Ubuntu 24.04 пакет docker.io предоставляет версию Docker Engine 26.1.3 или выше — этого достаточно для работы Swarm.

Разрешите автозапуск Docker при загрузке системы и запустите службу:

sudo systemctl enable --now docker

Проверьте корректность установки, запустив тестовый контейнер:

sudo docker run --rm hello-world

Если вы видите сообщение:

 

Hello from Docker!
This message shows that your installation appears to be working correctly.

 

— значит, всё в порядке.

Рекомендации для production-сред:

  • Аппаратные требования: минимум 2 CPU ядра и 2 ГБ оперативной памяти на узел. Для менеджеров рекомендуется добавить ещё 1 ГБ RAM для стабильной работы Raft-лога.
  • Сетевые адреса: используйте статические IP-адреса на всех нодах. Это предотвратит сбои при перезапуске DHCP-сервера.
  • Swap: отключите подкачку памяти с помощью команды sudo swapoff -a и закомментируйте соответствующую строку в /etc/fstab. Это улучшает предсказуемость производительности контейнеров.
  • Синхронизация времени: установите и запустите NTP-клиент, например, chrony или systemd-timesyncd, чтобы избежать проблем с TLS-сертификатами и логами.

Перед созданием кластера убедитесь, что на всех узлах:

  • установлена одинаковая версия Docker (проверяется командой sudo docker version);
  • открыты необходимые порты;
  • время синхронизировано;
  • сетевая связность между узлами подтверждена (например, с помощью ping или telnet).

docker02

Инициализация первого менеджера: рождение кластера

Теперь пришло время дать жизнь нашему кластеру. Выберите один из серверов — он станет лидирующим менеджером (Leader). На нём выполните команду инициализации:

sudo docker swarm init --advertise-addr 192.168.1.100

Замените 192.168.1.100 на реальный внутренний IP-адрес этого сервера. Параметр --advertise-addr критически важен: он указывает, по какому адресу другие узлы будут подключаться к этому менеджеру. Без него Docker может выбрать неправильный интерфейс (например, loopback или публичный IP), что приведёт к ошибкам связи.

После выполнения команды вы увидите примерно такой вывод:

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

To add a worker to this swarm, run the following command:
    docker swarm join --token SWMTKN-1-59fl8... 192.168.1.100:2377

Это означает, что кластер создан, и текущая нода теперь является менеджером. Обратите внимание на токен присоединения — это уникальная строка, необходимая для аутентификации новых узлов.

Присоединение воркеров: расширение вычислительной мощности

На каждой ноде, которую вы хотите сделать воркером, выполните команду, полученную на предыдущем шаге:

sudo docker swarm join --token SWMTKN-1-59fl8... 192.168.1.100:2377

Токен SWMTKN-1-... действителен только для роли воркера. Он гарантирует, что присоединяющийся узел прошёл аутентификацию и авторизацию на уровне кластера. Все коммуникации между узлами защищены TLS-шифрованием, сгенерированным автоматически при инициализации кластера.

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

sudo docker swarm join-token worker

Эта команда покажет актуальную команду для присоединения воркера, включая полный токен и адрес лидера.

Диагностика состояния: проверка работоспособности кластера

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

sudo docker node ls

Вы получите список всех узлов:

ID       HOSTNAME   STATUS  AVAILABILITY  MANAGER STATUS  ENGINE VERSION
d4n5g... * manager1  Ready   Active        Leader          26.1.3
x8qk2...   worker1   Ready   Active                        26.1.3
p3mz7...   worker2   Ready   Active                        26.1.3

Разберём, что означают статусы:

  • ID — уникальный идентификатор узла.
  • * — текущая нода, с которой выполняется команда.
  • STATUS: Ready — узел в рабочем состоянии и может принимать задачи.
  • AVAILABILITY: Active — узел доступен для размещения задач. Другие варианты: Drain (задачи не назначаются, но работающие остаются) и Pause.
  • MANAGER STATUS: Leader — активный менеджер, принимающий решения; Reachable — резервный менеджер; пусто — воркер.

Если все узлы в состоянии Ready и Active, кластер готов к работе.

Укрепление управления: добавление дополнительных менеджеров

Для повышения отказоустойчивости добавьте ещё хотя бы двух менеджеров. Это позволит кластеру пережить отказ одного узла без потери управления.

На лидере получите токен для менеджеров:

sudo docker swarm join-token manager

Вы увидите команду вида:

docker swarm join --token SWMTKN-1-abcdef... 192.168.1.100:2377

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

sudo docker swarm join --token SWMTKN-1-abcdef... 192.168.1.100:2377

После этого проверьте список узлов — новые менеджеры появятся с пометкой Reachable. Убедитесь, что общее число менеджеров нечётное (3, 5, 7...) для корректной работы Raft.

Безопасность на первом месте: ротация токенов

Если вы подозреваете, что токен был скомпрометирован (например, попал в логи или был опубликован), его необходимо повернуть (rotate). Это создаст новый токен и сделает старый недействительным.

Для воркеров:

sudo docker swarm join-token --rotate worker

Для менеджеров:

sudo docker swarm join-token --rotate manager

После ротации новые узлы смогут присоединиться только с новым токеном. Существующие узлы продолжат работу без изменений — их аутентификация основана на TLS-сертификатах, а не на токенах.

Развёртывание приложений: сервисы как единое целое

В Docker Swarm основной единицей развёртывания является сервис (service). Сервис описывает желаемое состояние: какой образ использовать, сколько реплик запустить, какие сети подключить, какие порты опубликовать. Docker Swarm автоматически распределяет задачи (tasks) — экземпляры контейнеров — по доступным узлам, обеспечивая отказоустойчивость и балансировку нагрузки.

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

docker01

Запуск веб-сервера: Nginx под управлением Swarm

Начнём с простого, но важного компонента — веб-сервера. Создадим сервис на основе образа nginx:alpine с тремя репликами:

sudo docker service create --name web \
  --replicas 3 \
  -p 80:80 \
  --network ingress \
  nginx:alpine

Разберём параметры:

  • --name web — задаёт имя сервиса, по которому к нему можно будет обратиться из других сервисов.
  • --replicas 3 — указывает, что нужно запустить три идентичные задачи (контейнера).
  • -p 80:80 — публикует порт 80 на всех узлах кластера. Это означает, что Nginx будет доступен по IP любого узла (менеджера или воркера).
  • --network ingress — подключает сервис к специальной встроенной overlay-сети для входящего трафика.

Проверим статус задач:

sudo docker service ps web

И протестируем доступность:

curl http://localhost

Вы должны увидеть HTML-код стандартной страницы Nginx.

Создание изолированной сети: overlay для внутреннего трафика

Для безопасного взаимодействия между сервисами (например, между веб-сервером и API) создадим собственную overlay-сеть:

sudo docker network create -d overlay \
  --subnet 10.13.0.0/24 \
  --attachable \
  my-net

Пояснение:

  • -d overlay — указывает драйвер сети, поддерживающий межузловое взаимодействие.
  • --subnet — задаёт фиксированный диапазон IP-адресов для этой сети (необязательно, но полезно для предсказуемости).
  • --attachable — позволяет запускать временные контейнеры в этой сети (например, для отладки командой docker run).

Эта сеть видна только внутри кластера и изолирована от внешнего мира и от других overlay-сетей.

Запуск API-сервиса: Python-микросервис в своей среде

Теперь развернём простое Flask-приложение в сети my-net:

sudo docker service create --name api \
  --replicas 2 \
  --network my-net \
  python:3.11-slim \
  sh -c "pip install --no-cache-dir flask && echo 'from flask import Flask; app=Flask(__name__); @app.route(\"/\") def home(): return \"Hello Swarm!\"' > app.py && python -u app.py"

Этот многострочный вызов выполняет следующее:

  • Устанавливает Flask без кэширования (--no-cache-dir экономит место в образе).
  • Создаёт простой Python-скрипт, который при запросе к корню возвращает Hello Swarm!.
  • Запускает сервер Flask в режиме без буферизации вывода (python -u), чтобы логи отображались в реальном времени.

Обратите внимание: порт 5000 (по умолчанию у Flask) не опубликован наружу. Сервис доступен только внутри сети my-net по DNS-имени api.

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

Для проверки связи запустим временный контейнер в сети my-net:

sudo docker run -it --rm \
  --network my-net \
  alpine sh

Внутри контейнера выполните:

wget -O- api:5000

Вы должны увидеть ответ:

Hello Swarm!

Это доказывает, что:

  • Сервис api успешно разрешается по DNS-имени.
  • Трафик между сервисами проходит через overlay-сеть.
  • Swarm автоматически балансирует запросы между всеми репликами API.

Внешние пользователи по-прежнему не видят API — он изолирован, что соответствует принципам безопасности.

Управление данными: конфигурации и секреты в Swarm

Жёстко закодированные конфигурации и пароли в образах — антипаттерн. Docker Swarm предоставляет два механизма для безопасного и декларативного управления данными:

  • Конфиги (configs) — для несекретных данных: Nginx-конфиги, JSON-настройки, сертификаты CA и т.д.
  • Секреты (secrets) — для конфиденциальной информации: пароли, API-ключи, токены.

Оба типа данных хранятся в зашифрованном виде в Raft-логе менеджеров и передаются только на те узлы, где запущены связанные задачи. Они монтируются в контейнер как файлы в tmpfs — то есть никогда не попадают на диск воркера и не видны в логах.

Конфигурация Nginx: оптимизация через централизованный config

Создадим конфиг для Nginx на менеджере:

echo "worker_processes auto;" | sudo docker config create nginx-conf -

Здесь:

  • docker config create — команда для создания объекта конфигурации в кластере.
  • nginx-conf — имя конфига.
  • - — указывает, что данные поступают из stdin.

Теперь этот конфиг можно подключить к любому сервису без пересборки образа.

docker03

Секреты безопасности: защита учётных данных

Создадим секрет с паролем базы данных:

echo "qwerty123" | sudo docker secret create db_password -

Этот пароль будет:

  • зашифрован алгоритмом AES-256-GCM;
  • доступен только сервисам, которым он явно назначен;
  • смонтирован в контейнер как файл /run/secrets/db_pass с правами 0400 (только владелец, только чтение).

Команда docker secret inspect db_password покажет метаданные, но никогда не содержимое.

Обновление сервиса: применение конфигураций и секретов

Теперь обновим сервис web, чтобы он использовал наш конфиг и секрет:

sudo docker service update \
  --config-add source=nginx-conf,target=/etc/nginx/nginx.conf \
  --secret-add source=db_password,target=/run/secrets/db_pass \
  web

Swarm выполнит постепенное обновление (rolling update): по одной реплике будет остановлена старая версия и запущена новая с подключёнными данными. Это обеспечивает нулевой простой (zero downtime).

Финальная проверка: заглянем внутрь контейнера

Найдём ID контейнера одной из реплик сервиса web:

sudo docker ps --filter name=web -q

Проверим наличие конфига:

sudo docker exec  ls -l /etc/nginx/nginx.conf

Ожидаемый вывод:

-r--r--r-- 1 root root 20 May 15 10:00 /etc/nginx/nginx.conf

Проверим содержимое секрета:

sudo docker exec  cat /run/secrets/db_pass

Результат:

qwerty123

Всё работает! Конфиг и секрет доставлены, права корректны, данные доступны приложению.

Заключение: путь к надёжной и безопасной инфраструктуре

Docker Swarm — это не просто инструмент, а философия: простота, встроенность, предсказуемость. На Ubuntu 24.04 вы можете развернуть отказоустойчивый кластер за считанные минуты, использовать встроенные механизмы безопасности для управления секретами, а также легко масштабировать и обновлять приложения без простоев. Для небольших команд и средних проектов Swarm остаётся непревзойдённым по соотношению «функциональность/сложность».

Помните: секреты не предназначены для больших объёмов данных (более 500 КБ) — для этого используйте внешние тома. Также всегда следите за версиями Docker, ротируйте токены при компрометации и ограничивайте сетевой доступ к управляющим портам.

С этого момента ваша инфраструктура — не набор машин, а единый оркестр, где каждый контейнер играет свою партию под управлением Docker Swarm.