Docker Swarm
1Docker Swarm: кластер контейнеров2Services: масштабирование и rolling updates3Stack deploy: продакшн на Swarm← вы здесь
Урок 3~9 минут

Stack deploy: продакшн на Swarm

Stack — способ запустить всё приложение в Swarm одной командой. Это как docker compose up, но для кластера.

docker-stack.yml

Почти идентичен docker-compose.yml, но добавляется секция deploy:

yaml
services:
  web:
    image: registry.example.com/myapp:latest
    ports:
      - "3000:3000"
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
      restart_policy:
        condition: on-failure
        max_attempts: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          memory: 256M
    secrets:
      - db_password
    networks:
      - frontend
      - backend
 
  db:
    image: postgres:16-alpine
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.role==db   # только на db-ноде
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    networks:
      - backend
 
secrets:
  db_password:
    external: true   # создан заранее через docker secret create
 
volumes:
  pgdata:
 
networks:
  frontend:
    driver: overlay
  backend:
    driver: overlay
    internal: true   # недоступна снаружи кластера

Попробуй в симуляции

Secrets — безопасные пароли

Секреты хранятся в зашифрованном Raft-логе, монтируются как tmpfs-файлы:

bash
# Создать secret
echo "super-secret-password" | docker secret create db_password -
docker secret create ssl_cert ./certs/server.crt
 
# Список секретов
docker secret ls
 
# Внутри контейнера — читать как файл
cat /run/secrets/db_password

Приложение читает из файла, а не из env:

python
# Python
with open('/run/secrets/db_password') as f:
    password = f.read().strip()
go
// Go
data, _ := os.ReadFile("/run/secrets/db_password")
password := strings.TrimSpace(string(data))

Деплой стека

bash
# Первый деплой
docker stack deploy -c docker-stack.yml myapp
 
# Обновить (после изменения docker-stack.yml или образа)
docker stack deploy -c docker-stack.yml myapp --with-registry-auth
 
# Флаг --with-registry-auth нужен для приватных registry
bash
docker stack ls                    # все стеки
docker stack services myapp        # сервисы стека
docker stack ps myapp              # задачи (где запущены)
docker stack rm myapp              # удалить стек

Реальный пример: веб-приложение на двух нодах

Типичная продакшн-конфигурация для небольшого проекта:

manager (1 нода):   Traefik, API
worker  (1 нода):   Next.js web
db-node (отдельно): PostgreSQL, Redis
yaml
services:
  traefik:
    image: traefik:v3.3
    ports:
      - "80:80"
      - "443:443"
    deploy:
      placement:
        constraints:
          - node.role==manager
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-certs:/certs
 
  web:
    image: registry/myapp-web:latest
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 15s
        failure_action: rollback
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.web.rule=Host(`example.com`)"
        - "traefik.http.routers.web.tls.certresolver=letsencrypt"
    networks:
      - frontend
 
  api:
    image: registry/myapp-api:latest
    deploy:
      replicas: 2
    secrets:
      - db_password
    networks:
      - frontend
      - backend
 
  db:
    image: postgres:16-alpine
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.role==db
    secrets:
      - db_password
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - backend

CI/CD с автодеплоем

bash
# В pipeline (GitHub Actions, GitLab CI)
 
# 1. Собрать и запушить образ
docker build -t registry/myapp:${GIT_SHA} .
docker push registry/myapp:${GIT_SHA}
 
# 2. Обновить сервис на сервере
ssh deploy@manager "
  docker service update \
    --image registry/myapp:${GIT_SHA} \
    --with-registry-auth \
    myapp_web
"
 
# Или обновить весь стек
ssh deploy@manager "
  docker stack deploy -c /srv/myapp/docker-stack.yml myapp \
    --with-registry-auth
"

Мониторинг кластера

bash
# Состояние нод
docker node ls
 
# Проблемные задачи
docker service ps myapp_web --filter desired-state=shutdown
 
# Логи конкретного сервиса
docker service logs myapp_web -f --tail 50
 
# Статистика
docker stats $(docker ps -q)

Что дальше

Docker Swarm — отличный выбор для небольших и средних проектов. Для масштабного оркестрирования рассмотри Kubernetes, который добавляет:

  • Автомасштабирование по нагрузке (HPA)
  • Более гибкие стратегии деплоя
  • Rich экосистема: Helm, Operators, Service Mesh
  • Продвинутый networking и storage

Но для большинства продакшн-проектов Swarm достаточен — он проще в эксплуатации и не требует отдельной команды DevOps.

Stack = Compose для Swarm. docker stack deploy разворачивает всё приложение: сервисы, сети, volumes. Secrets — безопасное хранение паролей без переменных окружения.
📦
docker stack deploy — продакшн стек
🔐 SECRETS
db_password
jwt_secret
🕸 OVERLAY NETWORKS
myapp_frontend
myapp_backend
🐳 SERVICES
🔀
traefik×1
🌐
web×2
api×2
🐘
db×1
🔴
redis×1
🎯
Миссия 1 из 3
Какой командой задеплоить stack из файла docker-stack.yml?