Современная инфраструктура немыслима без автоматизации. Практически никто уже не настраивает сервера вручную, не вносит правки непосредственно в конфиги. Мир инфраструктуры заполонили системы управления конфигурациями, такие как puppet, saltstack, chef, ansible и пр. Каждый хипстер-программист обязан написать свою собственную систему управления конфигурациями.
Но не будем о велосипедостроении, посмотрим на недостатки таких систем глазами пользователей. В данной статье я хочу затронуть проблему сваливания всего puppet кода в один большой репозиторий, где копошатся несколько людей, привнося свою лепту в общий процесс энтропии. Чем больше ваша инфраструктура, тем больше модулей вы используете, тем больше кода вы пишете, тем сложней становится управлять всей этой кухней.

Именно поэтому разработчики puppet и предложили r10k — инструмент, позволяющий собирать окружение (modules) по кирпичикам из разных источников: будь то ваши закрытые репозитории, github или puppetforge. Концепция атомарных модулей очень удобна для совместной разработки и переиспользования уже написанного кода без его копирования и изменения. Все что вам нужно, это написать специальный puppetfile, в котором будут написаны названия модулей и их источники. Пример конфига r10k:

---
moduledir '/etc/puppet/modules'
mod "my_module",
  :git => "git://github.com/user/my_module",
  :ref => "feature"
mod 'puppetlabs/apache', :latest

Мы указываем нахождение модуля и его ветку. Очень удобно, особенно для динамических окружений, которые поддерживают люди из разных комманд и могут привнести изменения в модуль, ломающие чужие системы, и даже не узнать об этом. r10k подерживает git, svn и puppetforge. Подробнее про r10k можно прочитать здесь.

Я же хочу рассказать, как мы решили написать аналог r10k для развертывания своих puppet модулей из git. Мы использовали исключительно git и если и использовали внешние модули, то переносили их в локальные репозитории, чтоб повысить их доступность и скорость работы с ними, поэтому r10k показался для нас излишне громоздким и усложненным. Для нас хватало самой концепции, которая легла в основу небольшого скрипта-замены r10k.

В самом начале мы рассматривали разнесение puppet модулей по разным репозиториям и соединение их в один с помощью git-submodule и git-subtree, но как показала практика, пользоваться этим неудобно и все равно встает вопрос о чужих изменениях, ломающих ваше окружение. Это происходит потому, что у нас всего один puppet мастер на всю инфраструктуру, и мы не хотели плодить мастеров для каждой команды. Опять же, есть какие-то базовые модули, которые использовали все команды. Итак, было решено написать свой простенький аналог r10k.

Основными требованиями к инструменту была скорость работы и простота реализации. Форматом для puppetfile был выбран yaml. Вот пример конфига:

sudo:
    git: gitlab@gitlab.srv.local:puppet/sudo
    ref: master
jdk_dirtyhack:
    git: gitlab@gitlab.srv.local:puppet/jdk_dirtyhack
    ref: master
module-users:
    git: gitlab@gitlab.srv.local:puppet/module-users
    ref: master
cdh4:
    git: gitlab@gitlab.srv.local:puppet/cdh4
    ref: master

sudo — это имя папки модуля, которая будет положена в /etc/puppet/modules (или какой у вас там modulepath);
git — путь к git репозиторию, с указанием пользователя
ref — название ветки, по-умолчанию master

Для организации окружений мы использовали hiera и держали окружения в разных ветках одного репозитория. Подробнее про динамические окружения можете почитать здесь.
Для того, чтобы создать свое окружение из набора разных модулей, достаточно было создать ветку в репозитории окружений, описать его в hiera и создать puppetfile с набором нужных модулей.
Специальный git hook запускал наш скрипт, который пересоздавал /etc/puppet/$env/modules исходя из содержания puppetfile. Скрипт клонирует модули внутрь директории, где лежит puppetfile.
Пример запуска

for i in `find /etc/puppet/environments -maxdepth 3 -path "*modules*" -name "puppetfile.yaml"`;
  do /etc/puppet/puppet-scripts/puppetfile.py $i &
done

При тестировании с пятью окружениями, внутри которых по 15-20 модулей, скрипт отрабатывал менее, чем за 20 секунд. Все репозитории были в локальной сети.
Разработка и тестирование puppet модулей из проблемы превратились в приятную работу.

Ах да, чуть не забыл, вот сам скрипт: https://github.com/kshcherban/pinocchio