Swarm Mode — встроенный инструмент Docker для оркестрации контейнеров. С его помощью можно объединять несколько серверов в единый кластер и управлять ими как одной системой. В статье мы разберём, как настроить Swarm на Ubuntu 24.04, развернуть веб-сервисы, а также работать с конфигурациями и секретами.
Для практических задач такой кластер удобно запускать на VPS: это позволяет быстро масштабировать инфраструктуру, распределять нагрузку и проверять работу сервисов в условиях, близких к боевым. Такой подход подойдёт как для небольших проектов, так и для тестирования будущей продакшен-системы.
Введение
Контейнеризация с Docker решила проблему переносимости приложений, но управление десятками контейнеров вручную быстро превращается в хаос: масштабирование под нагрузкой требует скриптов, сбой на ноде останавливает сервисы, а обновления грозят простоем. Оркестрация автоматизирует эти процессы, и Docker Swarm Mode — логичный выбор для тех, кто уже работает с Docker. Будучи встроенным в Docker Engine (с версии 1.12), Swarm не требует установки сложных внешних компонентов — всё управляется знакомыми командами docker service.
Swarm предпочтительнее Kubernetes для малых и средних кластеров (до 50 нод), где доминируют stateless-приложения (веб-серверы, API, фоновые обработчики), если нужно быстро запустить оркестрацию или нет ресурсов на поддержку тяжёлой инфраструктуры. Когда вы столкнётесь с необходимостью Canary-развёртываний, сложных сетевых политик или кластеров размером более 100 нод — тогда стоит задуматься о Kubernetes. Но для старта Swarm остаётся лучшим по эффективности.
В этой статье мы рассказываем, как создать Swarm-кластер на Ubuntu 24.04 на примере веб-приложения.
Подготовка инфраструктуры
В Docker Swarm ноды разделяются на две роли:
- Менеджеры (managers) — управляют состоянием кластера, хранят данные Raft Consensus, обрабатывают API-запросы. Для отказоустойчивости требуется минимум 3 менеджера.
- Воркеры (workers) — это ноды, на которых выполняются задачи (контейнеры). Они не участвуют в управлении кластером, а только получают инструкции от менеджеров.
Хосты могут выполнять роль менеджера и воркера одновременно — менеджеры настроены так по умолчанию, но их можно переключить на работу только в режиме управления.
Требования к сети:
- 2377/tcp — порт для коммуникации с менеджерами и между ними.
- 7946/tcp,udp — для обнаружения узлов overlay-сети.
- 4789/udp — VXLAN-туннели для трафика overlay-сетей.
Убедитесь, что файрвол разрешает этот трафик между всеми нодами.
Перейдём к подготовке серверов Ubuntu 24.04. Выполните на каждой будущей ноде кластера обновление индекса пакетов и установку обновлений:
sudo apt update && sudo apt upgrade -y
Установите Docker Engine из репозитория Ubuntu:
sudo apt install -y docker.io
docker.io — официальный пакет Docker в репозиториях Ubuntu (версия 26.1.3+ на момент релиза 24.04).
Разрешите автозапуск Docker при загрузке и запустите службу:
sudo systemctl enable --now docker
Запустите тестовый контейнер для проверки установки:
sudo docker run --rm hello-world
--rm удалит контейнер сразу после завершения работы.
Вы должны увидеть сообщение от Docker:
Hello from Docker!
This message shows that your installation appears to be working correctly.
Рекомендации для продакшена:
- Аппаратные требования — минимум 2 ядра CPU, 2 ГБ RAM на ноду. Для менеджеров добавьте ещё по 1 ГБ RAM.
- Сеть — статические IP-адреса для всех нод, отключённый swap (команда sudo swapoff -a).
- Безопасность — настройте туннелирование или ограничьте доступ к портам 2377/7946 только доверенным IP.
Все ноды должны:
- иметь одинаковую версию Docker (проверка: sudo docker version);
- разрешать коммуникацию по ключевым портам;
- иметь синхронизированное время (NTP).
Создание Swarm-кластера
Docker Swarm использует архитектуру «менеджер-воркер», где управляющие ноды координируют работу через Raft Consensus — алгоритм распределённого консенсуса. Это обеспечивает отказоустойчивость: кластер сохраняет работоспособность при потере до 50 % менеджеров (например, 1 из 3, 2 из 5). Все коммуникации между нодами защищены TLS-шифрованием «из коробки», включая аутентификацию воркеров.
Инициализация кластера
На сервере, который будет главным менеджером, выполните:
sudo docker swarm init --advertise-addr <MANAGER_IP>
--advertise-addr указывает IP-адрес, который будут использовать другие ноды для подключения; замените <MANAGER_IP> на реальный IP сервера. Если сервер имеет несколько интерфейсов, явное указание 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...) обеспечивает аутентификацию и авторизацию и гарантирует, что к кластеру присоединяются только доверенные ноды. Если токен утерян, просмотреть его можно на менеджере, выполнив:
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 |
Что означают статусы:
- * — текущая нода, где выполняется команда;
- MANAGER STATUS: Leader — нода принимает решения;
- Reachable — резервный менеджер (если их несколько);
- Availability: Active/Drain — может ли нода получать задачи.
Добавление менеджеров
Чтобы добавить дополнительный менеджер, выполните на менеджере-лидере:
sudo docker swarm join-token manager
Эта команда выведет токен и команду для присоединения ноды в качестве менеджера. Если добавить опцию -q (--quiet), то будет выведен только токен.
Затем выполните на новой ноде-менеджере, указав токен, IP-адрес лидера и порт:
sudo docker swarm join --token SWMTKN-1-... 192.168.1.100:2377
Ротация токенов
Проводите ротацию токенов, если токены или узлы кластера были скомпрометированы:
sudo docker swarm join-token --rotate worker # или manager
После этого новые ноды не смогут присоединиться к кластеру со старым токеном.
Если при присоединении появляется ошибка «Timeout» — проверьте файрвол (порты 2377, 7946, 4789) и доступность <MANAGER_IP>.
Развёртывание сервисов
Основная единица развёртывания в Docker Swarm — сервис (service), который описывает желаемое состояние контейнера (образ, количество реплик, сеть). Каждая реплика сервиса — это задача (task), запущенная на одной из нод кластера. Для связи сервисов используются overlay-сети, работающие поверх физической сети, а внешний доступ к сервисам обеспечивается через опубликованные порты.
Запуск Nginx с балансировкой нагрузки
Создадим сервис веб-сервера с 3 репликами, доступный извне кластера:
sudo docker service create --name web \
--replicas 3 \
-p 80:80 \
--network ingress \
nginx:alpine
Пояснение параметров:
- --name web — имя сервиса для управления;
- --replicas 3 — количество идентичных контейнеров (Swarm распределит их по нодам);
- -p 80:80 — публикация порта: внешний порт 80 → порт 80 в контейнере;
- --network ingress — подключение к встроенной сети для входящего трафика;
- nginx:alpine — официальный образ (alpine имеет меньший размер).
Проверка:
sudo docker service ps web # статус задач
curl http://localhost # запрос к Nginx (на любой ноде кластера)
Создание overlay-сети для внутреннего трафика
Для защищённого взаимодействия сервисов создадим изолированную сеть:
sudo docker network create -d overlay \
--subnet 10.13.0.0/24 \
--attachable \
my-net
Здесь:
- -d overlay — драйвер для сетей между нодами;
- --subnet — CIDR задаёт фиксированный диапазон IP в подсети;
- --attachable — разрешает ручной запуск контейнеров в сети.
Запуск Python-API
Развернём сервис с 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"
Разберём параметры:
- --network my-net — подключение к созданной overlay-сети;
- python:3.11-slim — оптимизированный образ Python.
Команда установки Flask и запуска приложения:
- --no-cache-dir — отключение кеширования пакетов для экономии места;
- -u в python -u — небуферизованный вывод (для корректных логов);
- порт Flask по умолчанию (5000) доступен только внутри my-net.
Проверка связи между сервисами
Запустим временный контейнер в сети my-net:
sudo docker run -it --rm \
--network my-net \
alpine sh
Протестируем API изнутри сети:
wget -O- api:5000
Ожидаемый вывод: Hello Swarm!
В результате:
- Сервис web доступен по порту 80 любой ноды кластера.
- Сервис api доступен только через сеть my-net по DNS-имени api.
- Swarm DNS автоматически резолвит api во все IP его задач.
Обратите внимание, что ingress-сеть использует L4-балансировку (TCP/UDP). Для HTTP/HTTPS балансировки потребуется Nginx или Traefik внутри кластера.
Управление конфигурацией и секретами
В Docker Swarm данные конфигурации и секреты управляются централизованно, что обеспечивает безопасность и согласованность развёртываний. При этом секреты — это критичная информация (пароли, ключи): они хранятся в зашифрованном виде в Raft-логе менеджеров и передаются только на ноды, где запущены связанные задачи.
Создание конфига для Nginx
Сгенерируем конфигурацию для оптимизации worker-процессов:
echo "worker_processes auto;" | sudo docker config create nginx-conf -
Здесь:
- docker config create создаёт объект конфигурации в Swarm;
- nginx-conf — имя конфига;
- - — указывает, что данные передаются через STDIN (можно указать файл nginx.conf).
Команда выполняется только на менеджере. Конфигурация будет храниться в распределённом хранилище и автоматически реплицироваться на все менеджеры. Это позволяет хранить конфиги отдельно от образов и менять их без пересборки, а также гарантирует одинаковую конфигурацию для всех реплик сервиса.
Добавление секрета (пароля базы данных)
Создадим защищённый секрет (также на менеджере):
echo "qwerty123" | sudo docker secret create db_password -
Секрет шифруется с помощью AES-256-GCM и сохраняется в Raft. При запуске задачи секрет монтируется в контейнер как файл в tmpfs, то есть он никогда не сохраняется на диске воркеров. Также секреты не видны в логах и docker inspect — там отображается только ID, но не содержимое.
Обновление сервиса
Добавим конфиг и секрет к сервису 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
Параметры:
- --config-add source=... ,target=... — монтирует конфиг как файл по указанному пути;
- --secret-add source=... ,target=... — аналогичное действие для секрета (права 0400);
Swarm выполнит последовательное обновление сервиса с нулевым даунтаймом.
Проверка внутри контейнера
Проверка выполняется на любой ноде, где есть задачи сервиса web (можно на менеджере или воркере). Цель — убедиться, что конфиг действительно смонтирован и имеет правильные права (только для чтения), а секрет доступен в контейнере и содержит корректное значение. Найдите запущенный контейнер сервиса:
sudo docker ps --filter name=web -q
Просмотрите файловую систему:
sudo docker exec <CONTAINER_ID> ls -l /etc/nginx/nginx.conf
sudo docker exec <CONTAINER_ID> cat /run/secrets/db_pass
Ожидаемый результат:
-r--r--r-- 1 root root 20 May 15 10:00 /etc/nginx/nginx.conf # конфиг
qwerty123 # секрет
Преимущества такого обновления:
- Безопасность секретов — даже при компрометации ноды злоумышленник не получит данные.
- Централизованное управление — изменение конфига/секрета через docker config|secret update автоматически обновит все сервисы.
- Версионирование — каждое изменение создаёт новую версию, что позволяет откатиться к предыдущей.
Не используйте секреты для данных более 500 КБ — это нагрузка на Raft-лог. Для больших объёмов (например, TLS-ключи) монтируйте внешние тома.
Читайте в блоге:
- Создаём флешку с Portable Ubuntu 24.04
- Как перенести каталог данных MySQL на другой диск в Ubuntu 24.04
- Миграция баз данных PostgreSQL при обновлении на Ubuntu 24.04