В этой статье я хотел бы рассказать про то, как мы используем Puppet и Hiera для конфигурирования железных и виртуальных серверов. В основном, в ней будет идти речь об архитектуре и придуманной нами иерархии, облегчающей и систематизирующей конфигурацию серверов.  Написать эту статью меня побудило то, что в интернете я особо не находил хороших, реально рабочих примеров того, как можно работать с hiera и для чего она нужна. В основном, это туториалы с примерами для того, чтобы въехать в тему. Но реальное практическое применение hiera там не написано. Возможно, я плохо искал, но вот вам реальный пример, который, возможно, вам поможет расставить все точки над i, как и мне когда-то. Если: Эта статья для вас. Предупрежу сразу, статья получилась длинной, но, я надеюсь, полезной. Кроме того, подразумевается, что у вас уже подключена hiera в puppet, и вы хоть как-то, но знакомы с puppet. Если hiera не подключена, это не сложно сделать. Изначально у нас все было в паппете версии 3, потом решили внедрить 4-й паппет, и все новые сервера начали размещать в нем, а старые потихоньку портировать в 4й. В третьем паппете у нас раньше использовалась классическая система нодных файлов и модулей. Модули создавали в специальной группе проектов в Gitlab, клонировали их на паппет-сервер (с помощью r10k), дальше паппет агенты приходили к мастеру и получали каталог, чтобы применить его на сервере. Потом начали стараться так не делать и не использовать локальные модули, а помещать ссылки на нужные модули и их репозитории в Puppetfile. Почему? Потому что те модули постоянно поддерживаются и улучшаются (ну, в идеале) сообществом и разработчиками, а наши локальные — нет. Позже внедрили hiera и перешли полностью на нее, а нодные файлы (типа nodes.pp) канули в лету.  В четвертом паппете мы постарались полностью отказаться от локальных модулей и использовать только remote модули. К сожалению, тут снова следует вставить оговорку, так как “полностью” не получилось, иногда все равно приходится что-то склонировать и доделать самим. Конечно, здесь только hiera и никаких нодных файлов. Когда у вас 30 команд с зоопарком технологий, проблема того, как содержать этот зверинец с >1000 серверов становится особенно остро. Дальше я расскажу, как в этом нам помогает hiera. У hiera (собственно, от чего она и получила свое название) настраивается иерархия. У нас она выглядит следующим образом: Сначала разберемся с непонятными переменными (фактами).  Каждый сервер в SEMrush в идеале должен иметь 4 выставленных, специальных факта, описывающих его принадлежность: Как это работает? Паппет агент приходит к паппет мастеру и на основе данных фактов ищет файлы для себя, проходясь по папкам в соответствии с нашей иерархией. Не нужно указывать принадлежность конфигурационых файлов к серверам. Вместо этого сервера сами знают, какие файлы относятся к ним, смотря только лишь на их путь и свои факты. При сетапе сервера админы связываются с разработчиками и уточняют данные параметры (часто даже наоборот, знающие люди сами связываются с админами), чтобы в дальнейшем построить иерархию в hiera, на основе которой потом описать конфигурацию сервера. Такая система помогает повторно использовать код и быть более гибким в плане конфигурации серверов.  Например, есть у нас проект special. В этом проекте может быть какой-то фронтенд-сервер с nginx, backend-сервер с python, db-кластер с mysql, redis-сервера для кэширования. Все эти сервера следует поместить в один проект под названием special, а дальше назначать серверам роли.  В проектном файле мы описываем общие для всего проекта параметры. Первое, что приходит на ум, это создание на всех серверах пользователя для деплоя с выдачей ему нужных прав и раскаткой его ssh-ключей.  В роли для каждого сервера обычно описывается и кастомизируется конкретно сервис — для чего данный сервер предназначен (nginx, python, mysql и т.д.) Tier в данном случае нам обязательно понадобится, если нам также нужно разворачивать копию продакшн окружения на dev-площадке, но что-то в ней изменить (пароли, например). В таком случае, dev-сервера и prod-сервера будут лишь отличаться выставленным фактом tier в нужное “положение” (prod или dev). А дальше немного магии и hiera сделает свое дело. Если же нам нужно развернуть два идентичных сервера в одинаковой роли, но что-то в них должно отличаться, например, какие-то строки в конфигурации, то на помощь придет другая часть иерархии. Помещаем файлы с названием формата {fqdn сервера}.yaml в нужное место (например, nodes/myserver.domain.net), выставляем нужные значения переменных на уровне конкретного сервера, и паппет применит на оба сервера одинаковую конфигурацию для роли, и уникальную для каждого из серверов. Пример: два бэкэнда с php-кодом находятся в одной роли и полностью идентичные. Понятно, что мы не хотим бэкапить оба сервера — нет смысла. Мы можем создать роль, в которой описать одинаковую конфигурацию для обоих серверов, а потом создать еще файл nodes/backend1.semrush.net, в который поместить конфигурацию для бэкапа. В командном файле teams/team-name.yaml указывается конфигурация для всех серверов, принадлежащих команде. Чаще всего там описываются пользователи, которые могут взаимодействовать с этими серверами, а также их права доступа. На основе этих переменных у нас построена данная иерархия. Чем выше найденный файл по иерархии, тем выше приоритет конфигурации, указанной в нем. Отсюда следует, что переменные могут оверрайдиться исходя из данной иерархии. То есть переменная в файле роли "projects/%{::project}/%{::role}" имеет больший приоритет, чем переменная в файле проекта "projects/%{::project}". Также переменные могут мерджиться на всех уровнях иерархии, если у вас модуль и/или профиль/роль написаны так, что позволяют это делать. Указав общую часть конфига mysql для всех серверов проекта, можно добавить в ту же переменную на других уровнях иерархии специальные части, имеющие вес для данной роли (для слейва будет дополнительная секция в конфиге). Получается, самый высокий приоритет имеет файл конкретной ноды, расположенный по пути — "hieradata/nodes/%{::fqdn}". Дальше следует файл ноды, но уже на уровне команды. Ниже всего находится блок, описывающий другие, более общие факты: Соответственно, в файле common.yaml у нас содержится конфигурация, которая точно должна приезжать на все сервера, в файле users.yaml описаны все юзеры (но не все они создаются на серверах, конечно же), в os/%{::operatingsystem} общая конфигурация, свойственная серверам с определенной ОС (используется факт ::operatingsystem) и так далее. Думаю, взглянув на данную иерархию, становится все понятно. Ниже я рассмотрю пример использования такой иерархии. Но сначала следует рассказать о профилях. Важным моментом в конфигурировании серверов с помощью модулей является использование профилей. Они располагаются по пути site/profiles и являются точками входа в модули. Благодаря им можно более тонко настраивать навешиваемые модули на сервера и создавать нужные ресурсы.  Рассмотрим простой пример. Есть модуль, устанавливающий и настраивающий redis. И мы хотим также при подключении данного модуля установить sysctl параметр vm.overcommit_memory в значение 1, потому что вот. Тогда пишем небольшой профиль, обеспечивающий этот функционал: Как было сказано выше, профили являются инструментом, позволяющим менять/улучшать поведение модуля, а также уменьшать количество конфигурации в hiera. Если вы используете удаленные модули, то часто можете столкнуться с проблемой, что "одобренные" модули часто не обладают нужным вам функционалом, или имеют какие-то баги/недоработки. Тогда в принципе можно склонировать этот модуль и поправить/добавить функционал. Но правильным решением будет, если это возможно, написать хороший профиль, который способен “приготовить” модуль нужным вам образом. Ниже будут представлены несколько примеров профилей, и можно будет лучше понять, для чего они нужны. Одним из важных преимуществ hiera по сравнению с “голым” паппетом является ее способность хранить sensitive data в конфигурационных файлах в зашифрованном виде в репозитории. Ваши пароли будут в безопасности.  Вкратце, вы с помощью публичного ключа шифруете нужную информацию и помещаете ее такой строкой в файл hiera. На паппет мастере хранится приватная часть ключа, которая позволяет эти данные дешифровать. Более подробно с этим можно ознакомиться на странице проекта. На клиенте (рабочем компьютере) тулза ставится просто, можно через gem install hiera-eyaml. Дальше с помощью команды вида eyaml encrypt --pkcs7-public-key=/path/to/public_key.pkcs7.pem -s 'hello' можно шифровать данные и вставлять в файл с расширением eyaml или просто yaml в зависимости от того, как вы настроите, а дальше паппет сам разберется. Получится что-то вроде: Или многострочной строкой: Кажется, с подготовкой закончили, теперь можно рассмотреть пример. Спойлер: дальше будет много конфигураций, так что тем, кому эта статья представляла чисто теоретический интерес, можно пропускать этот раздел и переходить в конец. Давайте теперь рассмотрим пример, как можно конфигурировать сервера с помощью hiera в puppet4. Я не буду публиковать код всех профилей, потому что иначе пост получится довольно больших размеров. Основной акцент я сделаю на иерархии и конфигурации hiera. Задача такая: нам нужно развернуть: Будем создавать нашу иерархию по порядку и начнем мы с проектного файла. Создаем файл проекта projects/kicker.yaml. Поместим в него то, что общее у всех серверов: нам нужны некоторые репозитории и папки для деплоя, а также сам пользователь deploy. Создаем файл роли для БД-серверов projects/kicker/db.yaml. Пока что обойдемся без разделения серверов на окружения: Здесь мы подключаем один профиль, написанный для общего использования всеми, кто захочет установить postgres себе на сервера. Профиль конфигурируем и позволяет гибко настроить модуль перед его применением.  Для самых любопытных ниже под катом код этого профиля: Таким образом, мы одним махом устанавливаем Postgresql 10, настраиваем конфиг (listen), создаем БД kicker, а также записываем в pg_hba.conf два правила для доступа к этой базе. Круто! Беремся за frontend. Создаем файл projects/kicker/frontend.yaml следующего содержания: Здесь все просто. Мы подключаем профиль profiles::webserver::nginx, который подготавливает вход в модуль nginx, а также определяем переменные, а конкретно server и location для этого сайта. Внимательный читатель заметит, что правильнее будет поместить описание сайта выше по иерархии, ведь у нас будет еще dev-окружение, и там будут использоваться другие переменные (server_name, proxy), но это не слишком важно. Описывая роль таким образом, мы сможем увидеть, как переопределяются эти переменные только лишь иерархией. Осталась роль docker projects/kicker/docker.yaml: Профиль profiles/docker.pp очень прост и изящен. Приведу его код: Все готово. Этого уже достаточно, чтобы развернуть нужный нам продукт на множестве серверов, просто назначив им определенные проект и роль (например, положив файлик в нужном формате в директорию facts.d, местоположение которой зависит от способа установки puppet). Сейчас мы имеем следующую структуру файлов: Разберемся теперь с окружениями и определением конфигурации, уникальной для роли на конкретной площадке. Создадим общую конфигурацию для всего прода. Файл projects/kicker/tiers/prod.yaml содержит указание, что нам нужно подключить класс с файрволом на это окружение (ну, прод же все-таки), а также некий класс, обеспечивающий повышенный уровень безопасности: Для dev-окружения, если нам нужно описать что-то специфичное, создается такой же файл, и в него вносится нужная конфигурация. Далее нужно все-таки переопределить переменные для nginx-конфига роли frontend в dev-окружении. Для этого понадобится создать файл projects/kicker/tiers/dev/frontend.yaml. Обратите внимание на новый уровень иерархии. Класс указывать уже не надо, он наследуется с предыдущих уровней иерархии. Здесь мы изменили server_name и proxy_pass. Сервер, у которого будут факты role=frontend и tier=dev, сначала найдет для себя файл projects/kicker/frontend.yaml, но потом переменные из этого файла будут переопределены файлом с бОльшим приоритетом projects/kicker/tiers/dev/frontend.yaml. И таким образом у нас остается последний пункт на повестке дня — это задать пароли для PostgreSQL.  Пароли должны различаться в окружениях. Будем использовать eyaml для безопасного хранения паролей. Создадим пароли: Вставляем полученные строки в файлы **projects/kicker/tiers/prod/db.yaml** и **projects/kicker/tiers/dev/db.yaml** (или можно использовать расширение eyaml, это настраиваемо) соответственно. Вот пример: Далее пароль для роли kicker приедет, расшифруется и применится на БД-сервере в PostgreSQL. На этом, собственно, и все. Да, пример получился массивным, но, надеюсь, функциональным, не оставляющим вопросов, понятным и полезным. Итоговая иерархия в hiera получилась такая: Вы можете посмотреть эти файлы "вживую", склонировав специально созданный репозиторий Puppet хорош и удобен в связке с hiera. Я бы не назвал его идеальным инструментом конфигурации в современном мире, вовсе нет, но он заслуживает внимания. С некоторыми задачами он справляется очень хорошо, а его “философия” поддержки постоянно одинакового состояния ресурсов и конфигурации может играть немаловажную роль в обеспечении безопасности и единообразия конфигураций. Современный мир постепенно синергирует и развивается. Мало кто сейчас использует только одну систему конфигурации, часто в арсенале девопсов и админов сразу несколько систем. И это хорошо, так как есть из чего выбрать. Главное, чтобы все было логично и понятно, как и где это можно сконфигурировать.  Наша цель как админов в итоге — ничего не конфигурировать самим. Все это в идеале должны делать сами команды. А мы им должны дать инструмент или продукт, позволяющий это делать безопасно, легко и, главное, с точным результатом. Ну, и помогать решать архитектурные и более серьезные задачи, чем "Нужно установить PostgreSQL на сервер и создать пользователя". Камон, 2018-й год на дворе! Поэтому выкидывайте puppet и ansible и двигайтесь в serverless future. C развитием облаков, контейнеризации и систем оркестраций контейнеров, системы управления конфигураций потихоньку отступают и отходят на задний план для пользователей и клиентов. Можно же в облаке поднять отказоустойчивый кластер контейнеров и держать свои приложения в контейнерах с авто-скелингом, бэкапированием, реплицированием, авто-дискавери и т.д, не написав ни строчки для ansible, puppet, chef etc. Ни о чем заботиться не надо (ну почти). С другой стороны, железных серверов из-за облаков меньше не стало. Просто вам их больше не нужно конфигурировать, это действие находится в ответственности облачного провайдера. Но вряд ли они пользуются теми же системами, что и простые смертные. Спасибо: Linux администратор