Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Доброго дня
У нас имеется несколько облачных кластеров с большим количеством виртуальных машин в каждом. Все это дело у нас хостится в Hetzner'e. В каждом кластере у нас имеется по одной мастер-машине, с нее делается снэпшот и автоматически разносится по всем виртуалкам внутри кластера.
Эта схема не позволяет нам нормально использовать gitlab-runner'ы, так как возникает очень много проблем при появлении множества одинаковых зарегистрированных раннеров, что и побудило к нахождению обходного пути и к написанию этой статьи/мануала.
Вероятно, это не best practice, но это решение показалось максимально удобным и простым.
За туториалом прошу под кат.
Необходимые пакеты на мастер-машине:
- python
- git
- файл с ssh ключами
Общий принцип реализации автоматического gut pull'a на всех виртуалках заключается в том, что необходима машина, на которой будет установлен Ansible. С этой машины ansible будет отправлять команды git pull и рестарт сервиса, который заапдейтился. Мы создали для этих целей отельную виртуальную машину вне кластеров, поставили на нее:
- python
- ansible
- gitlab-runner
Из организационных вопросов — необходимо зарегистрировать gitlab-runner, сделать ssh-keygen, закинуть публичный ssh ключ этой машины в
.ssh/authorized_keys
на мастер-машине, открыть на мастер-машине 22 порт для ansible. Теперь настроим ansible
Так как наша цель — автоматизировать все, что только можно. В файле
/etc/ansible/ansible.cfg
мы раскомментим строку host_key_checking = False
, чтобы ansible не запрашивал подтверждение новых машин. Далее, необходимо автоматически генерировать инвентаризационный файл для ansible, откуда он будет забирать ip машин, на которых нужно делать git pull.
Мы генерируем этот файл с помощью API Hetzner'a, вы же можете брать список хостов из вашей AWS, Asure, БД (у вас же где-то есть API для вывода ваших запущенных машин, да?).
Для Ansible очень важна структура инвентаризационного файла, его вид должен быть следующим:
[группа]
ip-адрес
ip-адрес
[группа2]
ip-адрес
ip-адрес
Для генерации такого файла сделаем простенький скрипт (назовем его
vm_list
):#!/bin/bash
echo [group] > /etc/ansible/cloud_ip &&
"ваш CLI запрос на получение IP запущенных машин в кластере" >> /etc/ansible/cloud_ip
echo " " >> /etc/ansible/cloud_ip
echo [group2] > /etc/ansible/cloud_ip &&
"ваш CLI запрос на получение IP запущенных машин в другом кластере" >> /etc/ansible/cloud_ip
Самое время проверить, что ansible работает и дружит с получалкой ip адресов:
/etc/ansible/./vm_list && ansible -i /etc/ansible/cloud_ip -m shell -a 'hostname' group
В аутпуте должны получить хостнэймы машин, на которых выполнилась команда.
Пара слов о синтаксисе:
- /etc/ansible/./vm_list — генерируем список машин
- -i — абсолютный путь до инвентаризационного файла
- -m — говорим ансиблу использовать модуль shell
- -a — аргумент. Сюда можно вписать любую команду
- group — название вашего кластера. Если нужно сделать на всех кластерах, меняем group на all
Идем дальше — попробуем сделать git pull на наших виртуальных машинах:
/etc/ansible/./vm_list && ansible -i /etc/ansible/cloud_ip -m shell -a 'cd /path/to/project && git pull' group
Если в аутпуте видим already up to date или выгрузку из репозитория, значит все работает.
Теперь то, ради чего это все задумывалось
Научим наш скрипт выполняться автоматически при коммите в мастер-ветке в gitlab'e
Сначала сделаем наш скрипт красивее и засунем его в исполняемый файл (назовем его exec_pull) —
#!/bin/bash
/etc/ansible/./get_vms && ansible -i /etc/ansible/cloud_ip -m shell -a "$@"
Идем в наш gitlab и в проекте создаем файл
.gitlab-ci.yml
Внутрь помещаем следующее:
variables:
GIT_STRATEGY: none
VM_GROUP: group
stages:
- pull
- restart
run_exec_pull:
stage: pull
script:
- /etc/ansible/exec_pull 'cd /path/to/project/'$CI_PROJECT_NAME' && git pull' $VM_GROUP
only:
- master
run_service_restart:
stage: restart
script:
- /etc/ansible/exec_pull 'your_app_stop && your_app_start' $VM_GROUP
only:
- master
Все готово. Теперь —
- делаем коммит
- радумеся тому, что все работает
При переносе .yml в другие проекты достаточно только поменять имя сервиса для рестарта и имя кластера, на котором будут выполняться команды ansible.