Этот пример сделан для доклада на митапе DistilleryTech
Ссылка на репозиторий тут.
Ссылка на презентацию тут
В данном примере находится рабочая конфигурация ansible для развертывания веб-приложения в кластере из трех хостов.
О том, как сделать простую инфраструктуру для разработки и эксплуатации приложения со всякими современными свистелками.
- Командам без выделенного devops-направления
- Тем кто только начинает в docker и микросервисы
- Да и вообще тем, кто хочет разобраться как работают с кластером на простом примере.
- ansible - система управления конфигурациями. Используется для автоматизации настройки и развертывания программного обеспечения
- несколько хостов(в данном случае созданные в VirtualBox)
- traefik - Edge Router, реверс-проксии, балансер и пр.
- consul - Service Discovery(обнаружение сервисов), K/V-хранилище, DNS и многое другое
- registrator - небольшой сервис, регистрирующий запущенные контейнеры в consul
- docker - собственно docker. При необходимости в режиме swarm
- portainer - веб-интерфейс для управления docker'ом, особенно удобно если у нас swarm
- gitlab - ПО, для запуска CI/CD. Из него выполняются все действия в автоматизированном режиме
Компоненты traefik
, consul
и registrator
образуют группу ingress
, которая выполняет функцию маршрутизации входных http-запросов к динамически поднимаемым контейнерам с приложением(ями).
Прежде всегод надо иметь инфраструктуру для развертывания данного кластера. Для этого подойдут любые(аппаратные или виртуальные) сервера с доступом по ssh, с установленным python и под управлением ОС Debian(поскольку это пример). В данном примере используются три сервера:
- 192.168.99.104 - cluster1 (роли: swarm manager)
- 192.168.99.105 - app1 (роли: swarm worker, db, consul, apps, persistent - тут хранятся данные)
- 192.168.99.106 - app2 (роли: swarm worker, gate, apps)
Им назначены определенные фукнции, которые они выполяют. Нет никаких проблем все функции делегировать одному хосту и все развернуть на нём одном.
Работать с docker'ом через сварм можно несколькими путями: через модуль docker/docker-swarm и через ssh/docker-compose. Если использовать модули docker то кататься будет хорошо, быстро, но вы никак не узнаете что и как было запущено. Вы увидите только результат - контейнеры, сети. Чтобы посмотреть настройки запуска контейнеров необходимо делать docker inspect
и читать json.
Во втором варианте на сервер санчала закидывается docker-compose.yml а потом там выполнятеся docker-compose up -d
. В этом случае docker-compose.yml остается и вы можете посмотреть что и откуда было запущено. Этот способ очень удобен при небольшом разамере кластера(до 5ти нод) или при начальном освоении кластерных подходов. Все файлы кладутся в папку /storage/configs/<группа>/....
Развертывание можно условно разделить на несколько шагов.
Выполняется в плейбуке playbook/setup.yml
Команда: ansible-playbook -i example.ini playbook/setup.yml -D
Что делает:
- настраивает ssh-доступы из gitlab
- ставит docker, docker-compose, подключает репозитории и пр.
Данный плейбук можно прокатить только один раз, или когда у вас добавляются хосты. Но если катать часто - ничего страшного.
Если у вас нет желания использовать swarm то плейбуки и таски можно немного изменить и просто работать с несколькими независимыми docker-хостами. Архитектура кластера от этого не изменится, но вот способы распределения приложений по нодам придется придумать. В данном случае используется swarm для облегчения деплоя - можно иметь соединение только с одной машиной(swarm manager) и все развертывать через неё, а ограничения накладываются через метки(labels) на нодах docker-swarm и в ограничениях(constraints) при описании сервисов.
Выполняется в плейбуке playbook/swarm.yml
Команда: ansible-playbook -i example.ini playbook/swarm.yml -D
Что делает:
- переводит докеры на хостах в режим swarm
- переводит некоторые ноды(согласто группам в example.ini) в режим manager
- собирает ноды в кластед docker swarm(инициализирует подключения через токены)
- раздает метки(labels) нодам
В данном примере у нас три метки(роли):
- gate - это шлюз который "торчит" в интернет. К нему стандартные требования безопасности для шлюзов. он обеспечивает TLS-терминацию и пр. В частности именно на шлюзах должен быть запущен traefik. Шлюзов может быть много
- apps - ноды на которых будут запущены наши веб-приложения. Тоесть именно бизнес-приложения, выполняющие бизнес-функции.
- persistent - ноды(в данной конфигурации обязательно ОДНА) на которой хранятся данные. База данных, consul могут быть запущены только на ней
Данный плейбук можно прокатить только один раз, или когда у вас добавляются хосты, меняются роли и пр. Но если катать часто - ничего страшного.
Выполняется в плейбуке playbook/infra.yml
Команда: ansible-playbook -i example.ini playbook/infra.yml -D
Что делает:
- запускает все наши служебные сервисы
- запускает базу на
persistent
ноде. Катается на группе db НЕ через swarm - катает portainer через swarm(на любой-первой
manger
ноде и через неё деплоит). Один portaner всего и portainer-agent накаждой
ноде кластера - катает portainer через swarm. На каждой
gate
ноде - запускает consul на нодах
consul
НЕ через swarm - запускает registrator на
всех
нодах НЕ через сварм
Запуск через swarm/не swarm обусловлен только удобством. Через swarm значит с использованием docker deploy
. Не через сварм значит docker-compose up -d
Данный плейбук можно прокатить только один раз, или когда у вас добавляются хосты, меняются роли и пр. Но если катать часто - ничего страшного.
Собственно именно этот шаг выполняется в CI/CD на регулярной основе.
Выполняется в плейбуке playbook/app.yml
Команда: ansible-playbook -i example.ini -e instance=dev playbook/app.yml -D
Что делает:
- запускает наше приложение в кластере. На всех нодах
apps
. Через swarm.
Плейбук app.yml использует параметр instance
и глобальный параметр domain
. В данном примере domain=example.local
. Это означает что с приложением после деплоя произойдут следуюшщие шаги:
- запустятся контейнеры. Им назначатся случайные порты на каждой машине на которой они запустились
registrator
увидит это и зарегистрирует информацию о них вconsul
. Укажет правильные ip хостов и эти случайные порты. При падении или перезапуске приложенияregistrator
будет удалять/обновлять информацию вconsul
. Кроме тогоregistrator
зарегистрирует указанные healthcheck'и в консуле, и он начнет периодически проверять приложение на доступность.traefik
будет ожидать что вconsul
появится приложение, выполнится healthcheck и только после этого добавит к себе соответствующий маршрут(virtual host). Этот маршрут будет иметь вид:http://<service_name>.<instance>.<domain>
, например:http://hello.dev.example.local
Если вы хотите для QA развернуть отдельный инстанс, то это делается передачей в переменную instance нужного вам параметра. Например при деплое ветки feature/fix-JIRA-100500
, из гитлаба можно передать туда COMMIT_REF_SLUG, который будет выглядеть так: feature-fix-jira-100500
и в результате мы получем доступ по адресу: http://hello.feature-fix-jira-100500.example.local
Вот собственно и все. В данном репозитории лежит .gitlab-ci.yml, который настроен на возможность развертывания стенда dev
из ветки master
и любого временно стенда из любой другой ветки или мердж-реквеста.
Команда RND-SOFT желает вам удачи.