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

Puppet 2.7 для 30 Linux-серверов: манифесты вместо SSH-обхода

Переводим конфигурацию 30 Linux-серверов под управление Puppet 2.7: nginx, PostgreSQL, rsyslog. Изменение конфига - это теперь коммит, а не ручной SSH-обход.

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

Puppet 2.7 и Chef 0.10 активно внедряются в 2011 как инструменты управления конфигурацией Linux-серверов в стиле Infrastructure as Code

Начали разворачивать Puppet на парке из 30 Linux-серверов у одного из клиентов. Не потому что модно, а потому что надоело: конфигурация nginx на шести серверах разъехалась в трёх направлениях, rsyslog на части машин был версии из дефолтного репозитория, на части - самосборный с патчами, которые никто уже не помнил зачем накладывал. Типичная история для инфраструктуры, которая росла органически последние три года.

Puppet или Chef - как выбирали

Оба инструмента активно развиваются прямо сейчас. Puppet 2.7 вышел в мае, Chef 0.10 - чуть позже. По сути решают одну задачу: описываешь желаемое состояние системы в коде, инструмент приводит реальные машины к этому состоянию.

Выбрали Puppet по нескольким причинам.

Во-первых - декларативный DSL. Описываешь что должно быть, а не как этого добиться. Для управления конфигурацией это понятнее, чем Chef с его Ruby-кулинарными книгами - особенно когда код читает не только тот, кто его писал.

Во-вторых - агентная модель с pull. На каждом сервере стоит puppet agent, который каждые 30 минут сам идёт к puppet master и забирает актуальный каталог. Не нужно дёргать машины снаружи - это удобно, когда часть серверов за NAT или firewall с ограниченным входящим доступом.

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

Что уже в Puppet

За первые две недели перевели три основных слоя.

nginx. Манифест описывает: пакет установлен, конфиг-файл такой-то из шаблона, сервис запущен и включён в автозапуск. Шаблоны используют ERB - это Ruby-шаблонизатор, который умеет подставлять переменные из Puppet. Одно описание, разные значения для разных ролей серверов через $hostname и $server_role.

class nginx {
  package { 'nginx':
    ensure => '1.0.6-1',
  }

  file { '/etc/nginx/nginx.conf':
    ensure  => file,
    content => template('nginx/nginx.conf.erb'),
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    notify  => Service['nginx'],
    require => Package['nginx'],
  }

  service { 'nginx':
    ensure => running,
    enable => true,
  }
}

notify => Service['nginx'] - это связь: если конфиг изменился, nginx получает reload. Puppet сам разбирается с порядком применения зависимостей.

PostgreSQL. Здесь посложнее: кроме самого пакета нужно управлять pg_hba.conf и postgresql.conf. Шаблоны разделены по роли - у мастера одни настройки, у реплики другие. pg_hba.conf собирается из кусков через concat - это модуль из Puppet Forge, который позволяет нескольким частям манифеста добавлять строки в один файл. Полезная штука, когда разные классы должны добавить своё правило доступа.

rsyslog. Именно из-за него всё и затевалось. Теперь на всех серверах одна версия пакета, один базовый шаблон конфига с форвардингом на центральный сервер логов. Отличия между серверами - только через переменные Puppet.

Организация кода

Манифесты лежат в git-репозитории. Puppet master подтягивает изменения через хук - запушил в master, через минуту агенты на серверах получат новый каталог.

Структура простая: modules/ с модулями для каждого сервиса, manifests/ с описанием ролей (web-сервер, db-сервер, логгер), hiera/ для данных - паролей и специфичных для окружения значений. Hiera позволяет хранить данные отдельно от кода: один манифест, разные значения для prod и staging.

Изменение конфигурации теперь выглядит так: открыл файл в редакторе, поправил, закоммитил, запушил. Puppet agent сам применит на всех нужных серверах. Если что-то пошло не так - git revert, и через 30 минут откат на всём парке.

До этого изменение nginx.conf выглядело как: зашёл по SSH на первый сервер, поправил, nginx -t, перезапустил. Зашёл на второй. Зашёл на третий. На пятом забыл что именно менял. На шестом оказалось, что там другая версия конфига и правка не совместима.

Где споткнулись

Идемпотентность не бесплатная. Puppet декларирует, что его операции идемпотентны - применяй манифест хоть сто раз, результат одинаковый. Это правда, но только если манифест написан аккуратно. exec { 'init-db': command => '/usr/bin/initdb /var/lib/pgsql/data' } - если не добавить creates => '/var/lib/pgsql/data' или unless, команда будет выполняться при каждом прогоне. Потратили время на то, чтобы проаудировать все exec-ресурсы в манифестах.

Puppet master - точка отказа. Все агенты ходят к мастеру. Если мастер упал - серверы работают на последнем полученном каталоге, ничего не падает, но новые изменения не применяются. Для парка из 30 машин это терпимо, но надо держать в голове.

Время применения. 30 минут до следующего прогона агента - это нормально для плановых изменений. Для срочных - puppet agent можно запустить вручную или через puppet kick. Но это уже ручное вмешательство, что немного противоречит концепции.

Секреты в hiera открытым текстом. Пароли к базам данных в YAML-файлах в git - это некрасиво. Hiera-gpg существует, но ещё сыровато. Пока закрыли отдельным репозиторием с ограниченным доступом, но задача не решена по-хорошему.

Текущее состояние

30 серверов под управлением Puppet. Конфигурация nginx, PostgreSQL и rsyslog синхронизирована впервые за, пожалуй, два года. Разъехавшиеся конфиги на нескольких машинах обнаружились сами, в процессе - Puppet просто перезаписал их тем, что описано в манифестах.

Для клиентов на сопровождении инфраструктуры это меняет способ работы: задокументированное состояние конфигурации - не вики-страница, которую никто не обновляет, а git-репозиторий, который отражает реальность. История изменений - это git log, а не попытка вспомнить кто и когда заходил на сервер.

Открытый вопрос - тестирование манифестов перед применением на prod. Puppet умеет делать --noop, то есть прогон без реальных изменений с показом того, что было бы сделано. Это помогает, но не заменяет полноценного тестирования на тестовом окружении. Пока работаем через --noop на одном сервере перед раскаткой на остальные, что грубовато. Смотрим в сторону vagrant для тестовых прогонов, но пока не дошли до нормального процесса.

Контакт

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

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