Введение

Когда инфраструктура насчитывает тысячи хостов, ручное управление превращается в источник нестабильности. Становится невозможным гарантировать единое состояние систем, своевременно обновлять конфигурации и быстро реагировать на инциденты. Особенно остро это ощущается в масштабах 9000+ рабочих станций, где даже малейшая ошибка масштабируется мгновенно.

Для централизованного и безопасного управления такой инфраструктурой используется связка Puppet и GitLab CI/CD. Эта комбинация позволяет автоматизировать весь цикл: от написания конфигурации до её контролируемого применения на каждом узле.

В основе подхода — принцип постепенного внедрения изменений: сначала изменения тестируются в безопасной среде, где можно экспериментировать без риска, потом — раскатываются на небольшую группу хостов (канареечное тестирование), чтобы посмотреть, как они поведут себя в реальных условиях. И только если всё прошло гладко — обновление отправляется на весь флот.

В этой статье я описал:

  • Архитектуру кластера Puppet и способы масштабирования без единых точек отказа;

  • Конвейер доставки изменений через GitLab CI/CD;

  • Организацию окружений и продвижение между ними (test → pilot → prod);

  • Управление Puppet-модулями и зависимостями через Puppetfile;

  • Практики контроля качества, мониторинга конфигурационного дрейфа и безопасного отката изменений.

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

Ключевые элементы и как это работает

Инфраструктура управления конфигурациями — это не просто один Puppet‑сервер где‑то в углу. Это разнесённый, отказоустойчивый кластер, состоящий из нескольких взаимосвязанных ролей. Каждая выполняет свою задачу, а вместе они обеспечивают стабильность, масштабируемость и прозрачность.

Puppet-agent — исполнитель на местах

Все конфигурационные изменения применяются на хостах с помощью puppet-agent — фонового демона, установленного на каждом управляемом устройстве. Он выполняет роль «исполнителя»: подключается к кластеру, получает чёткий набор инструкций — так называемый каталог конфигурации, описывающий, как должна выглядеть система.

Как это работает:

  1. Сначала агент удостоверяется, есть ли у него действующий сертификат, и если нет, запрашивает его у Puppet CA.

  2. Далее через HAProxy он отправляет запрос на одну из компиляционных нод.

  3. Нода собирает индивидуальный каталог для этого хоста и отправляет его обратно.

  4. Агент получает каталог и начинает применять: создаёт файлы, настраивает сервисы, правит конфиги, меняет права и владельцев.

Агент можно запустить вручную (puppet agent -t), но чаще он работает в фоне — раз в 30 минут сверяя систему с эталоном. И если что-то не так — исправляет. Молча, надёжно и по правилам.

Есть и режим просмотра — --noop: агент покажет, что бы он сделал, но ничего не тронет. Удобно, если хочется проверить эффект изменений до реального применения.

HAProxy — балансировщик на входе в кластер

Когда в системе тысячи агентов, каждый регулярно запрашивает конфигурации или сертификаты. Чтобы они не штурмовали один сервер, используется балансировка нагрузки. Именно этим занимается HAProxy — он направляет запросы к нужным нодам кластера и распределяет нагрузку между ними.

В нашей инфраструктуре работают два HAProxy-сервера, которые объединены с помощью Keepalived и доступны через единый виртуальный IP (VIP). Это означает, что даже если один из них выйдет из строя, второй тут же подхватит трафик.

Как это работает:

  • Запрос от puppet-agent (по портам 8140 или 8141) поступает на VIP.

  • HAProxy перенаправляет его на один из backend-серверов: сервер сертификации или компиляционную ноду.

  • Здоровье backend'ов отслеживается автоматически — если один из них упал, HAProxy исключит его из пула.

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

Сервер сертификации (Puppet CA)

Каждый puppet-agent, прежде чем получить конфигурацию, сначала должен доказать, что он — доверенное лицо. Для этого существует Puppet CA — отдельный компонент кластера, отвечающий за выдачу, подпись и проверку TLS-сертификатов.

В архитектуре он выделен в самостоятельную роль: CA работает независимо от компилятора и базы данных. Это упрощает обслуживание и снижает риски — даже если какой-то компонент выйдет из строя, авторизация хостов продолжит работать.

Чтобы избежать единой точки отказа, в системе предусмотрены две CA-ноды с репликацией. Основная обрабатывает запросы, резервная синхронизирует данные и автоматически подхватывает работу при сбое. 

Как это работает:

  1. puppet-agent подключается к VIP по порту 8141.

  2. HAProxy перенаправляет запрос на активную CA-ноду.

  3. Если у хоста уже есть сертификат — CA его проверяет.

  4. Если нет — создаёт и подписывает новый, при необходимости с ручным одобрением.

  5. Готовый сертификат синхронизируется на вторую CA-ноду, чтобы обе были в актуальном состоянии.

Такое устройство обеспечивает надёжную и масштабируемую систему аутентификации:

  • агенты проходят проверку быстро и безопасно;

  • сбой одного сервера не останавливает всю инфраструктуру;

  • зоны ответственности чётко разграничены: CA занимается только сертификацией и делает это стабильно.

Компиляционные ноды — фабрика конфигураций

Если CA пускает агента в систему, то именно компиляционные ноды говорят ему, что конкретно делать. Эти ноды — рабочие лошадки Puppet-кластера. Они получают запрос от агента, смотрят на факты о системе, и на основе кода окружения собирают индивидуальный каталог конфигурации.

Можно думать о них как о сборочном конвейере: каждому хосту — свой комплект инструкций.

Как это работает:

  1. Puppet-agent обращается к кластеру через HAProxy (порт 8140).

  2. Балансировщик направляет запрос по кругу: каждый следующий запрос отправляется на следующую свободную компиляционную ноду. Такой метод (round-robin) обеспечивает равномерную загрузку сервера.

  3. Нода собирает все необходимые инструкции: загружает код конфигурации (манифесты), подключает нужные модули, подтягивает переменные из системы управления данными в Puppet, и на основе этих данных формирует индивидуальный план действий для конкретного хоста

  4. Готовый каталог конфигурации возвращается агенту, и тот приступает к работе.

Каталог учитывает:

  • все известные факты о хосте (OS, IP, hostname, кастомные параметры);

  • выбранное окружение (test, pilot, prod);

  • активные Puppet-модули и их зависимости.

Что это даёт:

  • Горизонтальное масштабирование  

Хватает мощности — отлично. Не хватает — просто добавляем ещё одну компиляционную ноду в пул. Сейчас четыре ноды обрабатывают более 20 000 запросов в час.

  • Изоляция и отказоустойчивость  

Если одна из компиляционных нод падает, остальные продолжают обрабатывать запросы. Отказ одного элемента не влияет на всю систему.

  • Чёткое разделение окружений  

Поскольку запросы учитывают, из какой ветки пришёл код (test, pilot, prod), можно безопасно разносить конфигурации по группам хостов. Это позволяет разворачивать изменения поэтапно без риска задеть все хосты сразу.

PuppetDB — аналитическое ядро кластера

Применить конфигурацию — это только половина дела. Важно понимать, что именно произошло, на каких узлах, и почему. Для этого в экосистеме Puppet есть ключевой компонент — PuppetDB.

Это центральное хранилище, куда стекается вся «телеметрия» от агентов:

  • факты об узлах (ОС, IP, архитектура, кастомные параметры),

  • каталоги конфигураций (что именно должно быть применено),

  • отчёты о выполнении (что реально произошло и с каким результатом).

Как это работает:

  1. После выполнения манифестов агент отправляет отчёт на одну из компиляционных нод.

  • Та пересылает данные в PuppetDB — сервис, работающий на отказоустойчивом кластере PostgreSQL.

  • Данные индексируются и становятся доступны через API, а также через визуальный интерфейс Puppetboard.

Что это даёт:

  • Можно в любой момент узнать: какие узлы применили изменения, у кого были ошибки, а кто «выпал» из цикла.

  • Можно делать выборки: «покажи все хосты с CentOS 7», «кто не запускался последние 2 дня», «где установлен nginx».

  • Никаких внешних агентов, скриптов или обходов вручную — все данные уже есть в системе, в одной точке.

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

Puppetboard — простая визуализация для сложных систем

Когда у тебя сотни или тысячи узлов, JSON-ответы из API быстро перестают радовать. В такие моменты особенно ценится Puppetboard — веб-интерфейс поверх PuppetDB, который позволяет видеть состояние всей инфраструктуры вживую и сразу.

Это не «декоративная панель», а по-настоящему полезный инструмент. Мы открываем его каждый день, чтобы быстро понять, где что пошло не так, какие агенты выпали из цикла, и какие узлы вообще живы.

Что показывает Puppetboard:

  • Общее состояние всех узлов: успешно, с изменениями, с ошибками, недоступен;

  • Дату и время последнего запуска агента;

  • Количество обработанных и изменённых ресурсов;

  • Ошибки и предупреждения;

  • Информацию о фактах узла: ОС, IP, hostname, uptime и так далее.

Почему это удобно:

  • Всё собирается с PuppetDB, то есть без лишней нагрузки на серверы или агентов;

  • Интерфейс отзывчивый и быстрый, работает даже при большом объёме данных;

  • Есть поиск, фильтры, и можно быстро провалиться на конкретный узел.

Что это даёт в итоге

  • Быстрая диагностика — если что-то пошло не так после выката, Puppetboard покажет это в первую очередь;

  • Контроль отклонений — легко заметить, если какие-то машины «выпали»: не получили нужные настройки или не применили их до конца;

  • Наблюдение за обновлениями — можно увидеть, как ведёт себя пилотная группа во время раскатки обновлений: применились ли изменения, есть ли ошибки, всё ли прошло гладко;

  • Живая картина всей инфраструктуры — и не надо лезть в консоль или писать API-запросы.

Puppetboard — это тот случай, когда простое средство делает работу с масштабной системой в разы удобнее.

Результаты архитектурного подхода

Любая система, работающая в масштабе, должна быть не просто производительной, а спокойно переживающей сбои. Архитектура изначально строилась с расчётом на отказоустойчивость и масштабируемость — не как опцию, а как базовое требование.

Эта архитектура успешно работает в реальных условиях — с более чем 9000 хостами, тысячами запусков агентов каждый день и постоянными изменениями конфигураций. И что важно — система продолжает расти без потери стабильности.

Что мы получили на выходе:

  • Доступность: сбой одного сервера не влияет на остальную систему.

  • Масштабируемость: линейное расширение через HAProxy и PostgreSQL-кластер.

  • Производительность: никаких очередей агентов или таймаутов при генерации каталогов конфигураций.

  • Наблюдаемость: всё прозрачно — от уровня ресурсов до статистики отклонений.

  • Безопасность: централизованная выдача сертификатов, изолированные среды, защищённые ветки и доступы.

И самое главное — уверенность в каждом запуске. Мы точно знаем, что произойдёт, где, и как это откатить, если что-то пойдёт не так.

Такая архитектура стала надёжной основой для CI/CD — от постепенной раскатки обновлений на часть хостов до полностью автоматизированных деплоев с проверками. Как именно это устроено — расскажу дальше.

GitLab CI: Интеллектуальный дирижёр Puppet-инфраструктуры

В нашей экосистеме управления хостами GitLab CI/CD выступает не просто инструментом автоматизации, а центральной нервной системой, которая координирует доставку изменений, обеспечивает контроль качества и гарантирует предсказуемость. Это тот самый механизм, который превращает строки кода в реальные настройки на тысячах машин.

Почему GitLab CI — идеальный дирижёр для Puppet?

Из всех возможных вариантов CI/CD GitLab отлично вписался в связку с Puppet. Он обеспечивает и прозрачность, и контроль, и полный цикл автоматизации.

Единый источник истины

  • Вся инфраструктура хранится в GitLab: манифесты, модули, параметры — всё под контролем версий.

  • Каждый коммит — это след: кто, когда и зачем внёс изменения.

  • Все изменения сначала отправляются на проверку — через merge request, где их просматривают и тестируют, прежде чем они попадут в основное окружение.

Автоматизация от начала до конца

CI/CD-процесс построен так, что человеку не нужно заходить на серверы вручную. Всё работает по цепочке:

  1. Администратор делает коммит;

  2. GitLab сам запускает проверки — чтобы убедиться, что всё работает как надо;

  3. Если всё ОК — изменения автоматически доставляются на компиляционные ноды;

  4. Система мониторит результат и сообщает, как всё прошло.

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

Этот подход делает инфраструктурные изменения такими же управляемыми и предсказуемыми, как обновления обычного кода. И это именно то, что нужно в больших системах.

Механизм доставки изменений: r10k — надежный курьер

Когда в Git вносятся изменения в конфигурацию, их нужно как-то быстро и безопасно доставить на компиляционные ноды. Этим занимается r10k — надёжный механизм, который синхронизирует содержимое репозитория.

Как работает доставка через CI/CD:

  1. Изменение попадает в Git. Кто-то делает коммит или отправляет merge request в одну из рабочих веток:

  • test — код уходит в тестовое окружение;

  • pilot — начинается раскатка на небольшую группу хостов;

  • prod — после всех проверок изменения доходят до основной среды.

  1. GitLab запускает пайплайн. CI (Continuous Integration) определяет, в какую ветку пришёл коммит, и запускает соответствующие шаги. Один из таких шагов — вызов r10k.

  2. r10k синхронизирует окружение, запуская команду: 

  • r10k deploy environment ${CI_COMMIT_BRANCH} -p -v info.  Что делает эта команда:

    • Определяет, какие окружения нужно обновить;

    • Забирает свежий код из Git;

    • Подтягивает нужные версии всех Puppet-модулей из Puppetfile;

    • Обновляет соответствующую директорию с конфигурацией на компиляционных нодах.

Процесс полностью повторяемый и одинаковый для всех окружений — нет «особых правил для основной среды». Всё, что попадает в test, проходит тот же путь, что и prod, только с разным масштабом. Это снижает риск ошибок и делает доставку конфигураций стабильной и предсказуемой.

Пример CI/CD-конфигурации в .gitlab-ci.yml (с пояснениями):

stages:
  - check    # Этап проверки: проверяем синтаксис и стиль Puppet-кода
  - deploy   # Этап деплоя: развертывание кода на серверах

puppet_check:
  stage: check
  script:
    # Проверяем каждый Puppet-манифест (*.pp) на корректность синтаксиса
    - find manifests/ -name '*.pp' -exec puppet parser validate {} +
    # Проверяем стиль кода Puppet с помощью puppet-lint
    - find manifests/ -name '*.pp' -exec puppet-lint {} +
  tags:
    - puppet-runner  # Запускать этот job только на runner'ах с тегом puppet-runner

deploy_to_puppet_servers:
  stage: deploy
  tags:
    - puppet-runner  # Используем GitLab Runner с тегом puppet-runner для запуска деплоя
  script:
    # Запускаем r10k для развертывания окружения с именем ветки CI_COMMIT_BRANCH
    # Ключ -p означает обработку Puppetfile (зависимостей модулей)
    # -v info включает подробный лог
    # Путь к r10k может отличаться, в данном случае — стандартный путь Puppet Labs
    - /opt/puppetlabs/puppet/bin/r10k deploy environment ${CI_COMMIT_BRANCH} -p -v info
  parallel:
    matrix:
      # Параллельно запускаем деплой на 4 серверах
      # Для каждого сервера будет создана отдельная копия job, что ускоряет процесс
      - SERVERS: ['puppet-node01', 'puppet-node02', 'puppet-node03', 'puppet-node04']

Как устроена Puppet-среда: три ветки, один поток изменений

За основу мы взяли простой, но проверенный подход: все конфигурации описаны в центральном Git‑репозитории. Но магия начинается не с самих файлов, а с того, как они продвигаются от идеи до продуктивной среды.

У нас — три ветки. Каждая играет свою роль в CI/CD‑цикле:

  • test — лаборатория. Здесь появляются первые строки кода, тестируются идеи, даже рисковые. Эта ветка изолирована, и любой «эксперимент» безопасен.

  • pilot — буфер между тестом и боем. Сюда попадают только прошедшие проверку изменения. Они применяются к ограниченному числу хостов, где мы наблюдаем поведение вживую.

  • prod — финальная остановка. Только надёжный и проверенный код попадает сюда. Это стабильная ветка, которая управляет всей продуктивной инфраструктурой.

Как всё устроено на практике

  1. Тестовое внедрение  

Всё начинается в test. Это песочница, где допускаются даже спорные решения — главное, чтобы они не дошли до боевых машин без проверки.

  1. Синхронизация с реальностью  

Ветка test регулярно подтягивает изменения из prod, чтобы не застрять в прошлом. Мы всегда тестируем на фоне актуального состояния инфраструктуры.

  1. Переход в pilot  

После прохождения тестов и проверки изменения вручную переходят в pilot. Здесь они выкатываются на небольшую часть флота. Если система не подаёт тревожных сигналов, а количество ошибок не лезет в гору, продолжаем путь.

  1. Релиз в prod  

Всё стабильно? Значит, можно сливать pilot в prod. После этого обновления автоматически распространяются на все узлы.

Почему мы выбрали именно такой подход?

Автоматическое слияние напрямую из test в prod — слишком опасно, особенно при работе с тысячами машин. Наш подход даёт время на осознание, тестирование, наблюдение. Мы уверены, что каждое изменение контролируемо, прозрачно и готово к жизни.

Puppetfile и управление модулями: гибкость с контролем

Один из ключевых элементов Puppet-инфраструктуры — это модули. Именно через них осуществляется вся конфигурация хостов: от установки нужных приложений и настройки пользовательских доступов до приведения рабочих станций к корпоративному стандарту. Управление всеми этими модулями централизовано через Puppetfile.

Файл Puppetfile играет роль локального пакетного менеджера: он фиксирует, какие модули используются, откуда их брать, и, что особенно важно, какие именно версии или ветки подключать.

Как всё устроено у нас

  • Каждый модуль живёт в своём Git‑репозитории и имеет как минимум две ветки:

    • main — стабильная, продуктивная;

    • pilot — для проверки новых изменений.

  • Когда нужно протестировать новую функциональность модуля, его pilot‑ветка явно прописывается в Puppetfile, который подключён к окружению pilot. Таким образом только небольшая группа хостов начнёт использовать новую версию.

  • Чтобы не допустить случайного слияния pilot в main, сам Puppetfile защищён:

    • его изменения проходят ручную ревизию;

    • файл включён в .gitattributes как защищённый от merge‑конфликтов по умолчанию;

    • автослияние отключено — только ручной контроль.

  • Когда изменения проходят тесты и обкатку, происходит финальное оформление:

    • ветка pilot модуля сливается в main;

    • в Puppetfile обновляется ссылка с pilot обратно на main — теперь стабильная версия доступна всем окружениям.

Такой подход позволяет:

  • изолировать и управлять рисками на уровне отдельных модулей;

  • контролировать, где и когда применяется новая логика;

  • избежать ситуаций, когда неподготовленный код «утекает» в продуктовую среду.

И, что не менее важно, он прекрасно масштабируется. Даже если у вас десятки или сотни модулей, всё по-прежнему управляется централизованно и прозрачно.

Проверяем качество и держим всё под контролем

Когда управляем тысячами машин, самое важное — надёжность. Обновление должно устанавливаться одинаково на каждом хосте, ничего не сломать и быть незаметным для пользователей. Поэтому весь наш CI/CD‑конвейер вокруг Puppet построен на нескольких уровнях проверок и быстрых откатов.

Быстрые проверки кода

Каждое изменение Puppet-кода начинает путь с базовых проверок:

  • puppet-lint — ловит опечатки и «битый» синтаксис ещё до сборки.

  • puppet parser validate — следит за стилем: отступы, имена классов, порядок атрибутов.

Обе команды запускаются автоматически при каждом коммите, чтобы остановить ошибку на раннем этапе.

Интеграционные тесты и ручная проверка

Полноценное тестирование мы пока только планируем внедрить. Речь о acceptance‑тестах — когда модуль проверяется на реальной виртуалке, как будто это настоящий хост.

Для этого подойдут инструменты вроде Litmus или Beaker — они позволяют поднять тестовую машину, применить к ней конфигурацию и посмотреть, всё ли работает как нужно.

Это важно для модулей, которые затрагивают сетевые настройки или меняют политики безопасности на рабочих станциях.

Puppetboard и мониторинг дрейфа

Чтобы понимать, как применяются конфигурации, мы используем связку PuppetDB + Puppetboard. Это даёт нам удобный способ следить за состоянием всей инфраструктуры прямо из браузера - без логов, консоли и API-запросов.

Что можно увидеть:

  • какие хосты запускались недавно, и всё ли у них прошло успешно;

  • где возникли ошибки или предупреждения;

  • у каких узлов конфигурация не совпадает с заданной — это называется дрейф;

  • статистику по применённым ресурсам — помогает выявить нестабильные модули.

Если что-то пошло не так, мы узнаем об этом не через жалобу пользователя, а заранее — через дашборд.

Откаты и контроль изменений

Если после обновления что-то пошло не так, важно уметь быстро вернуть систему в стабильное состояние.

Для этого:

  • каждое изменение, попадающее в рабочее окружение, фиксируется с помощью тега в Git;

  • при необходимости возврата — используется команда git revert для отмены конкретного изменения, после чего запускается пайплайн повторно;

  • система автоматически разворачивает предыдущую версию конфигурации на всех нужных узлах.

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

PS.

Вся эта система — результат постепенной эволюции. Она началась не с полной автоматизации или масштабируемого контроля, а шла к этому шаг за шагом: от наблюдения — к предотвращению.

CI/CD-инфраструктура на базе Puppet и GitLab позволяет нам управлять флотом из тысяч машин, сохраняя при этом контроль, прозрачность и предсказуемость. И самое главное — не бояться изменений, потому что теперь у нас есть инструменты, чтобы их проверять, отслеживать и откатывать.

Комментарии (0)