ADG Оставить заявку
Блог DevOps 5 мин чтения

Git + GitFlow для инфраструктуры: Ansible и PowerShell DSC под контролем версий

Переносим Ansible playbooks и PowerShell DSC-конфиги в Git с GitFlow-моделью ветвления: история изменений инфраструктуры становится аудитируемой.

Контекст момента

Git и GitFlow-модель ветвления становятся стандартом управления кодом инфраструктуры в 2014 году

Последние несколько месяцев мы активно пишем про Ansible и PowerShell DSC как про инструменты описания инфраструктуры кодом. Но до недавнего времени в этой конструкции был очевидный пробел: сам код жил где попало. У одного инженера в папке на рабочем столе, у другого - в shared-папке на файловом сервере, у третьего - в почте в виде вложений. Понять кто и когда что менял было, мягко говоря, нетривиально.

Очевидное решение - Git. Но Git для инфраструктурного кода немного отличается от Git для приложений, и нам понадобилось время чтобы найти рабочую модель ветвления.

Откуда растут ноги проблемы

Пока playbook один и его редактирует один человек - всё просто. У нас playbook-ов накопилось несколько десятков: базовые роли для Linux-серверов, роли для Windows, DSC-конфиги для разных типов узлов, инвентари по клиентам. Редактируют это несколько инженеров одновременно.

Без контроля версий типичный сценарий выглядел так: инженер А правит base.yml, инженер Б в это время берёт «последнюю версию» из общей папки - но это уже не последняя версия. Через час оба сохраняют свои варианты, один затирает другого. Кто затёр - непонятно. Что именно потерялось - тоже.

Хуже того: когда клиент спрашивал «а что вы делали с нашей инфраструктурой в прошлый вторник?» - ответить честно и точно получалось не всегда.

Почему GitFlow, а не просто Git

Для приложений GitFlow описал Vincent Driessen ещё в 2010 году, и с тех пор это устоявшаяся модель. Для инфраструктурного кода она подходит с небольшими поправками.

Суть модели в нашем случае:

  • main (master) - только то, что применено в продакшне. Прямые коммиты запрещены.
  • develop - рабочая ветка. Сюда идут все изменения после первичной проверки.
  • feature/название - ветка под конкретную задачу: добавить роль nginx, обновить DSC-конфиг для файловых серверов, завести нового клиента в инвентарь.
  • hotfix/название - срочные исправления прямо от main, если нужно быстро починить что-то в продакшне не дожидаясь обычного цикла.

В случае с приложениями есть ещё ветки release, но для инфраструктурного кода мы пока обходимся без них - оверкилл для нашего масштаба.

Как это выглядит в практике

Появляется задача: для нового клиента нужно добавить роль настройки Fail2ban на Linux-серверах. Инженер создаёт ветку feature/fail2ban-role от develop, пишет задачи в playbook, тестирует на изолированной машине, делает pull request в develop. Второй инженер смотрит изменения, комментирует если есть вопросы, мержит.

После применения к реальному клиенту - merge в main с тегом версии.

Простой, но важный момент: теперь в git log видно кто сделал коммит, когда, и с каким комментарием. Комментарий, конечно, надо писать осмысленно - «правки» не считается, «добавил Fail2ban роль, порт SSH меняется на нестандартный через переменную» - это да.

Что изменилось с DSC-конфигами

PowerShell DSC в Git ложится без сюрпризов: .ps1 и .psm1 - обычный текст, diff читаемый. Один нюанс - MOF-файлы (скомпилированные конфиги) мы в репозиторий не кладём, только исходные .ps1. MOF генерируется из исходников и уже применяется на узлы. Иначе репозиторий быстро засоряется бинарными файлами, которые не нужно версионировать.

Отдельно решали вопрос с чувствительными данными. Пароли, ключи, IP адреса внутренних систем - всё это не должно лежать в репозитории открытым текстом. Для Ansible переменные с секретами шифруем отдельно и передаём через зашифрованный файл переменных. Для DSC - переменные конфигурации выносим в отдельные файлы, которые не коммитятся (в .gitignore), а хранятся отдельно и передаются в конфигурацию при компиляции.

Аудитируемость: зачем это нужно клиенту

Вопрос «что вы делали с нашей инфраструктурой» перестал быть неудобным. Теперь у нас есть честный ответ с датами и именами.

Кроме того, разбор инцидентов стал заметно удобнее. Вместо «кажется, кто-то менял конфиг nginx на прошлой неделе» - git log --all --oneline -- roles/nginx/ и сразу видно что именно, когда и почему.

Это же помогает при онбординге нового инженера: вся история изменений открыта, можно понять почему принято именно такое решение, если к коммиту прикреплён нормальный комментарий.

Что пока не доделано

Нет автоматического запуска playbook-ов после мержа в main. То есть git-история есть, но применение изменений по-прежнему ручное: инженер берёт актуальную ветку, запускает ansible-playbook руками. Это создаёт теоретический зазор между тем что в репозитории и тем что реально применено.

Правильное решение тут - CI/CD пайплайн, который при мерже в main автоматически запускает apply на нужные хосты. Смотрим в сторону Jenkins для этого, но это отдельная история.

Ещё не решена проблема тестирования изменений до применения. Сейчас тестируем на изолированной виртуалке руками. Хотелось бы автоматических тестов инфраструктурного кода - что-то вроде serverspec или аналогичного. Пока это больше идея чем практика.

Итог на сегодня

Git с GitFlow - это не решение всех проблем infrastructure-as-code, но базовый порядок наводит сразу. Инфраструктурный код в репозитории, история изменений, понятный процесс для командной работы. Клиенты на сопровождении получают дополнительную прозрачность: можем показать что и когда менялось.

Всё остальное - автоматизация применения, тестирование - следующие шаги. Но их тяжело делать без фундамента в виде нормального контроля версий.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.