Допустим, вы уже создали свой новенький Docker кластер и морально готовы заполонить своими приложениями. Такой вопрос: как именно вы будете это делать? Не руками ведь, через docker service create
, правда? Кластер же большой, а приложение, которому он потребовался, явно будет состоять не из одного сервиса.
В обычном Docker была такая прекрасная штука как docker-compose
, с которой можно было описать все контейнеры и их параметры в одном docker-compose.yml
файле и потом запустить всё одним махом через docker-compose up
. Вот бы можно было сделать так и в кластере.
Оказывается, можно.
Что такое docker stack
Среди стайки новых команд, пришедших в мир с Докером в Swarm режиме, есть одна под названием docker stack
, и вы будете смеяться, но она делает ровно то же самое, что и docker-compose
. С минимальными изменениями ей можно скормить компоузовский же YAML файл, и если вы решили задаться такой целью, то нужно всего пара шагов:
- Заменить версию файла на хотя бы третью. Например,
version: '3.1'
- Убедиться, что в файле нет команды
build
(ну и парочки других).
И всё. После этого можно запускать docker stack deploy -c my-compose-file.yml my-stack-name
и отправлять YAML прямиком в облако.
Пример
В прошлом посте мы сделали Докер кластер, в котором оказалось два сервиса: viz
для визуализации состояния кластера, и отмасштабированный web
сервис для замеров пропускной способности. Хотя для этого и не потребовалось много писанины, в командах запуска было пару непривычных моментов, вроде требований к хостам, на которых можно запускать viz
, так что, положив всю конфигурацию в отдельный файл, можно сделать свою жизнь немного проще.
0. Что для этого потребуется
Docker в Swarm режиме. Можно даже на одном хосте. Как сделать его не на одном хосте было написано тут.
1. Создаём описание стэка для viz
Чтобы освежить память, вот как выглядела команда для создания viz
сервиса:
1 2 3 4 5 6 |
docker service create \ --name=viz \ --publish=8080:8080 \ --constraint=node.role==manager \ --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \ dockersamples/visualizer |
Похожий на docker-compose.yml файл для него можно создать элементарно:
1 2 3 4 5 6 7 8 9 10 11 12 |
version: "3.1" services: viz: image: dockersamples/visualizer ports: - 8080:8080 volumes: - /var/run/docker.sock:/var/run/docker.sock deploy: placement: constraints: [node.role == manager] |
Выглядит, как обычный compose файл. Из отличий только номер версии (3.1
) и секция deploy
, куда пошли требования к хостам. Чтобы отправить файл в кластер, нужна одна простая команда:
1 2 3 |
docker stack deploy -c viz.yml viz #Creating network viz_default #Creating service viz_viz |
-c viz.yml
говорит, откуда брать файл конфигурации, а viz
— имя стэка. В общем, всё просто. Теперь, когда команда выполнилась, можно запустить какой-нибудь docker stack ls
, чтобы убедиться, что всё прошло хорошо, и сходить на порт 8080, чтобы посмотреть на сервис в действии:
1 2 3 |
docker stack ls #NAME SERVICES #viz 1 |
2. Создаём описание стэка для web
web
сервис был старым добрым nginx контейнером с приоткрытым для внешней публики портом 80. Чтобы сделать процесс немного интереснее, добавим-ка к нему ещё один сервис. Просто так, чтобы убедиться, что, как и в compose, в один YAML файл для стэка можно запихать несколько сервисов.
YAML файл прост и эстетически прекрасен:
1 2 3 4 5 6 7 8 9 10 11 |
version: '3.1' services: web1: image: nginx ports: - 8081:80 web2: image: httpd ports: - 8082:80 |
Запуск его в облаке ничуть не хуже:
1 2 3 4 |
docker stack deploy -c web.yml web #... #Creating service web_web1 #Creating service web_web2 |
И опять же, убеждаемся, что всё работает:
1 2 3 4 |
docker stack ls #NAME SERVICES #web 2 #viz 1 |
Вроде все живы.
3. Как обновить стэк
Я помню, как мне приходилось обновлять контейнеры, установленные через docker-compose. Нужно было аж три шага: docker-compose stop srv
, docker-compose build srv
и docker-compose up -d --no-deps srv
. Остановить, пересобрать, перезапустить. Со стэками процесс будет немного проще.
В прошлом посте web
оказался зверски надруган и отмасштабирован аж до двух копий. Сегодня, думаю, стоит сделать шаг дальше и отмасштабировать уже оба сервиса и прямо в конфигурационном файле. На выходе должна получиться красивая картинка в viz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
version: '3.1' services: web1: image: nginx ports: - 8081:80 deploy: replicas: 3 web2: image: httpd ports: - 8082:80 deploy: replicas: 2 |
И вот теперь немного той самой уличной магии: как обновить стэк:
1 2 3 |
docker stack deploy -c web.yml web #Updating service web_web2 (id: 18hq0xui4ek3cbczt8cd9kni3) #Updating service web_web1 (id: i8mmj4vfccqodu3fudg3ew507) |
Никакой магии. Там точно такая же команда, как и для начального развёртывания.
Проверяем сервис:
Всё разноцветное и в квадратиках. Красота.
Итого
Хорошие новости всё ещё случаются: docker-compose
подход для развёртывания сложных контейнерных приложений работает даже в Swarm. Просто для этого нужно использовать команду docker stack
и немного обновить существующие compose файлы: какие-то команды устарели, какие-то добавилось для кластеров. Но в целом это всё тот же старый добрый compose. Только stack
.
У нас в проекте вместе живут docker-compose и docker stack deploy. Локально развернуть проще с помощью docker-compose, а docker stack deploy, позволяет делать безшовные обновления на проде. Проект разворачивается и обновляется с помощью make.