Настало время рассмотреть стеки в Docker Swarm. Благодаря стекам можно создавать группы сервисов, пописывая всю конфигурацию в compose-файле.

Stack — это “пакет” (группа) из нескольких сервисов, сетей, томов, описанных в одном compose-файле.

1️⃣ Самый простой compose-файл для Docker Swarm Stack

Ниже самый банальный пример compose-файла для создания “пакета” (группы) сервисов web, api. У каждого сервиса по одной реплике задачи/контейнера.

🗃️ stack1.yml

version: "3.8"

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    networks:
      - backend

  api:
    image: tipoit/py-hostname:1.0
    networks:
      - backend

networks:
  backend:
    driver: overlay

Для того, чтобы создать сервисы из файла выше использую команду docker stack deploy -c stack1.yml mystack1. В итоге при выполнении этой команды Swarm создаёт:

  • сервис mystack_web
  • сервис mystack_api
  • сеть mystack1_backend

Данная команда на вид выполнится довольно быстро, но выполнение всех необходимых задач происходит в фоном режиме.

swarm-stack-basics.svg

2️⃣ Просмотр стеков

Когда стек создан можно и проверить что там внутри него. Первым делом выведу список всех стеков в кластере.

docker stack ls
NAME       SERVICES
mystack1   2

3️⃣ Просмотр сервисов стека

Для того чтобы получить список сервисов определённого стека используется команда docker stack services.

docker stack services mystack1
ID             NAME           MODE         REPLICAS   IMAGE                    PORTS
j3n3r4fv6itm   mystack1_api   replicated   1/1        tipoit/py-hostname:1.0
iz5pz1t2p4uz   mystack1_web   replicated   1/1        nginx:latest             *:8080->80/tcp

4️⃣ Просмотр задач/контейнеров стека

Да для этого можно использовать и обычную команду docker service ps, но можно заменить её и на docker stack ps и получить вообще все задачи всех сервисов в стеке.

docker stack ps mystack1
ID             NAME             IMAGE                    NODE             DESIRED STATE   CURRENT STATE            ERROR     PORTS
sutyb5hy2irr   mystack1_api.1   tipoit/py-hostname:1.0   c-stream-9-vm4   Running         Running 39 seconds ago
dnd7kdyct9qa   mystack1_web.1   nginx:latest             c-stream-9-vm8   Running         Running 37 seconds ago

5️⃣ Как связаны stack и service

Как уже стало понятно из текста выше стек состоит из сервисов, стало быть сервисы из одного стека как-то связанны с ним. Во-первых, все сервисы связанны между собой, так как в примере выше используется только одна сеть mystack1_backend, которая принадлежит стеку mystack1.

Каждый сервис стека после создания имеет следующую структуру имени: _, например, `mystack1_api`.

Также можно использовать docker service inspect для того чтобы узнать к какому стеку принадлежит сервис.

docker service inspect mystack1_web --format ''
{"com.docker.stack.image":"nginx:latest","com.docker.stack.namespace":"mystack1"}
docker service ls --filter label=com.docker.stack.namespace=mystack1
ID             NAME           MODE         REPLICAS   IMAGE                    PORTS
krlkybxksuvk   mystack1_api   replicated   1/1        tipoit/py-hostname:1.0
mkdr6mt164tx   mystack1_web   replicated   1/1        nginx:latest             *:8080->80/tcp

swarm-stack-service-linking.svg

6️⃣ Удаление стека

Как и в случае с удалением других компонентов кластера используется опция rm, т.е. команда удаления стека выглядит так: docker stack rm. Причём тут не надо задавать никакого подтверждения после выполнения этой команды весь стек сервисов будет удалён без единого запроса подтверждения на это, будьте осторожны.

docker stack rm mystack1

Удаление стека также проходит в фоновом режиме. Так что пока стек полностью не удалится не создавайте новый с таким же именем, либо можно использовать --detach=false.

6️⃣ Build не работает

При использовании docker compose в файле можно использовать параметр build, для того чтобы собрать образ для контейнера при создании контейнеров. Но в файле конфигурации для стека build использовать нельзя. При попытке это сделать вы просто получите ошибку services.api.build Additional property build is not allowed выполняя команду docker stack build.

Причина на самом деле проста. Swarm — это кластер. Он может запускать сервисы на любом узле кластера, а build происходит только локально. Значит, собирать образ внутри stack нельзя.

Дело в том, что Docker не может гарантировать:

  • что образ соберётся одинаково на каждой ноде;
  • что нода, на которую Swarm поставит сервис, имеет исходники;
  • что билд-окружение одинаковое.

Поэтому правильнее всего будет сделать так:

  1. Собираешь образ локально или в CI (docker build)
  2. Загрузить его в репозиторий (docker push)
  3. В файле stack.yml указать образ с репозитория

Помимо build в файле конфигурации стека нельзя указывать следующее:

  • depends_on
  • container_name
  • restart
  • links

swarm-stack-build-forbidden.svg