Puppet+Hiera. Выжимаем максимум

vqz-bjm4yx2wvhzcf-frffyuh04.png

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

Написать эту статью меня побудило то, что в интернете я особо не находил хороших, реально рабочих примеров того, как можно работать с hiera и для чего она нужна. В основном, это туториалы с примерами для того, чтобы въехать в тему. Но реальное практическое применение hiera там не написано. Возможно, я плохо искал, но вот вам реальный пример, который, возможно, вам поможет расставить все точки над i, как и мне когда-то.


Для кого была бы полезна данная статья

Если:


  • Вы знаете, что такое Puppet и Hiera, но особо не использует их в связке, потому что непонятно, как это делать и зачем
  • У вас в компании есть множество команд и вам надо как-то разграничивать конфигурацию серверов на уровне команд
  • Вы используете паппет, и нодные файлы у вас разрослись до неимоверных размеров
  • Вам нравится читать конфигурацию серверов в божественном yaml формате:)
  • Вы в принципе интересуетесь темой Configuration Management и системным администрированием

Эта статья для вас.


Прежде, чем начать

Предупрежу сразу, статья получилась длинной, но, я надеюсь, полезной. Кроме того, подразумевается, что у вас уже подключена hiera в puppet, и вы хоть как-то, но знакомы с puppet. Если hiera не подключена, это не сложно сделать.


Вводные данные


  • У нас в SEMrush есть около 30 команд разработки, каждая из которых имеет свои сервера
  • Каждая команда работает со своим набором технологий (ЯП, СУБД и т.д.)
  • Команды могут и должны (в идеале) использовать общую конфигурацию для каких-то конкретных проектов (code reuse)
  • Команды сами управляют деплоем приложений на свои сервера (это делается не через паппет)


Немного истории

Изначально у нас все было в паппете версии 3, потом решили внедрить 4-й паппет, и все новые сервера начали размещать в нем, а старые потихоньку портировать в 4й.

В третьем паппете у нас раньше использовалась классическая система нодных файлов и модулей. Модули создавали в специальной группе проектов в Gitlab, клонировали их на паппет-сервер (с помощью r10k), дальше паппет агенты приходили к мастеру и получали каталог, чтобы применить его на сервере.

Потом начали стараться так не делать и не использовать локальные модули, а помещать ссылки на нужные модули и их репозитории в Puppetfile. Почему? Потому что те модули постоянно поддерживаются и улучшаются (ну, в идеале) сообществом и разработчиками, а наши локальные — нет. Позже внедрили hiera и перешли полностью на нее, а нодные файлы (типа nodes.pp) канули в лету.

В четвертом паппете мы постарались полностью отказаться от локальных модулей и использовать только remote модули. К сожалению, тут снова следует вставить оговорку, так как «полностью» не получилось, иногда все равно приходится что-то склонировать и доделать самим. Конечно, здесь только hiera и никаких нодных файлов.

Когда у вас 30 команд с зоопарком технологий, проблема того, как содержать этот зверинец с >1000 серверов становится особенно остро. Дальше я расскажу, как в этом нам помогает hiera.


Иерархия

У hiera (собственно, от чего она и получила свое название) настраивается иерархия. У нас она выглядит следующим образом:

---
:hierarchy:
 - "nodes/%{::fqdn}"
 - "teams/%{::team}_team/nodes/%{::fqdn}"
 - "teams/%{::team}_team/projects/%{::project}/tiers/%{::tier}"
 - "teams/%{::team}_team/projects/%{::project}/%{::role}"
 - "teams/%{::team}_team/projects/%{::project}"
 - "teams/%{::team}_team/roles/%{::role}"
 - "teams/%{::team}_team/%{::team}"
 - "projects/%{::project}/tiers/%{::tier}/%{::role}"
 - "projects/%{::project}/tiers/%{::tier}"
 - "projects/%{::project}/%{::role}"
 - "projects/%{::project}"
 - "tiers/%{::tier}"
 - "virtual/%{::virtual}"
 - "os/%{::operatingsystem}/%{::operatingsystemmajrelease}"
 - "os/%{::operatingsystem}"
 - users
 - common

Сначала разберемся с непонятными переменными (фактами).

Каждый сервер в SEMrush в идеале должен иметь 4 выставленных, специальных факта, описывающих его принадлежность:


  • факт team — к какой команде он относится
  • факт project — к какому проекту он относится
  • факт role — какую роль в этом проекте имеет
  • факт tier — какой у него стейджинг (prod, test, dev)

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

При сетапе сервера админы связываются с разработчиками и уточняют данные параметры (часто даже наоборот, знающие люди сами связываются с админами), чтобы в дальнейшем построить иерархию в 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}». Дальше следует файл ноды, но уже на уровне команды. Ниже всего находится блок, описывающий другие, более общие факты:

 - "virtual/%{::virtual}"
 - "os/%{::operatingsystem}/%{::operatingsystemmajrelease}"
 - "os/%{::operatingsystem}"
 - users
 - common

Соответственно, в файле common.yaml у нас содержится конфигурация, которая точно должна приезжать на все сервера, в файле users.yaml описаны все юзеры (но не все они создаются на серверах, конечно же), в os/%{::operatingsystem} общая конфигурация, свойственная серверам с определенной ОС (используется факт ::operatingsystem) и так далее.

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


Профили

Важным моментом в конфигурировании серверов с помощью модулей является использование профилей. Они располагаются по пути site/profiles и являются точками входа в модули. Благодаря им можно более тонко настраивать навешиваемые модули на сервера и создавать нужные ресурсы.

Рассмотрим простой пример. Есть модуль, устанавливающий и настраивающий redis. И мы хотим также при подключении данного модуля установить sysctl параметр vm.overcommit_memory в значение 1, потому что вот. Тогда пишем небольшой профиль, обеспечивающий этот функционал:

# standalone redis server 
class profiles::db::redis (
  Hash $config = {}, 
  String $output_buffer_limit_slave = '256mb 64mb 60',
) {
  # https://redis.io/topics/faq#background-saving-fails-with-a-fork-error-under-linux-even-if-i-have-a-lot-of-free-ram
  sysctl { 'vm.overcommit_memory':
    ensure => present,
    value  => '1',
  }

  class { '::redis':
    * => $config,
  }
}

Как было сказано выше, профили являются инструментом, позволяющим менять/улучшать поведение модуля, а также уменьшать количество конфигурации в hiera. Если вы используете удаленные модули, то часто можете столкнуться с проблемой, что «одобренные» модули часто не обладают нужным вам функционалом, или имеют какие-то баги/недоработки. Тогда в принципе можно склонировать этот модуль и поправить/добавить функционал. Но правильным решением будет, если это возможно, написать хороший профиль, который способен «приготовить» модуль нужным вам образом. Ниже будут представлены несколько примеров профилей, и можно будет лучше понять, для чего они нужны.


Сокрытие секретов в hiera

Одним из важных преимуществ hiera по сравнению с «голым» паппетом является ее способность хранить sensitive data в конфигурационных файлах в зашифрованном виде в репозитории. Ваши пароли будут в безопасности.

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

На клиенте (рабочем компьютере) тулза ставится просто, можно через gem install hiera-eyaml. Дальше с помощью команды вида eyaml encrypt --pkcs7-public-key=/path/to/public_key.pkcs7.pem -s 'hello' можно шифровать данные и вставлять в файл с расширением eyaml или просто yaml в зависимости от того, как вы настроите, а дальше паппет сам разберется. Получится что-то вроде:

roles::postrgresql::password: 'ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAbIz1ihQlThMWa9T+Lq194Y6QdElMD1XTev5y+VPSHtkPTu6Al6TJaSrXF+7phJIjue+NF4ZVtJCLkHxUR6nJJqks0fcGS1vF2+6mmM9cy69sIU1A3HqpOHZLuqHAc7jUqljYxpwWSIGOK6I2FygdAp5FfOTewqfcVVmXj97EJdcv3DKrbAlSrIMO2iZRYwQvyv+qnptnZ7pilR2veOCPW2UMm6zagDLutX9Ft5vERbdaiCiEfTOpVa9Qx0GqveNRVJLV/5lfcL5ajdNBJXkvKqDbx8d3ZBtEVAAqeKlw0LqzScgmCbWQx2kUzukX5LSxbTpT0Th984Vp1sl7iPk7UTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCp5GcwidcEMA+0wjAMblkKgBCR/f9KGXUgLh3/Ok60OIT5]'

Или многострочной строкой:

roles::postgresql::password: >
    ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEw
    DQYJKoZIhvcNAQEBBQAEggEAbIz1ihQlThMWa9T+Lq194Y6QdElMD1XTev5y
    +VPSHtkPTu6Al6TJaSrXF+7phJIjue+NF4ZVtJCLkHxUR6nJJqks0fcGS1vF
    2+6mmM9cy69sIU1A3HqpOHZLuqHAc7jUqljYxpwWSIGOK6I2FygdAp5FfOTe
    wqfcVVmXj97EJdcv3DKrbAlSrIMO2iZRYwQvyv+qnptnZ7pilR2veOCPW2UM
    m6zagDLutX9Ft5vERbdaiCiEfTOpVa9Qx0GqveNRVJLV/5lfcL5ajdNBJXkv
    KqDbx8d3ZBtEVAAqeKlw0LqzScgmCbWQx2kUzukX5LSxbTpT0Th984Vp1sl7
    iPk7UTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCp5GcwidcEMA+0wjAM
    blkKgBCR/f9KGXUgLh3/Ok60OIT5]

Кажется, с подготовкой закончили, теперь можно рассмотреть пример.


Пример на пальцах

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

Давайте теперь рассмотрим пример, как можно конфигурировать сервера с помощью hiera в puppet4. Я не буду публиковать код всех профилей, потому что иначе пост получится довольно больших размеров. Основной акцент я сделаю на иерархии и конфигурации hiera.

Задача такая: нам нужно развернуть:


  • Два идентичных бд-сервера, на которых развернут postgresql
  • Еще два сервера — frontend с nginx
  • Пятый и шестой сервера — бэкэнды на python в докере
  • Все то же самое и на dev-окружении, за исключением некоторой конфигурации серверов

Будем создавать нашу иерархию по порядку и начнем мы с проектного файла.


Проект

Создаем файл проекта projects/kicker.yaml. Поместим в него то, что общее у всех серверов: нам нужны некоторые репозитории и папки для деплоя, а также сам пользователь deploy.

---
classes:
  - apt::debian::semrush

files:
  "/srv/data":
    ensure: 'directory'
    owner:  'deploy'
    group:  'www-data'
    mode:   '0755'
  '/srv/data/shared_temp':
    ensure: 'directory'
    owner:  'deploy'
    group:  'www-data'
    mode:   '0775'

user_management::present:
  - deploy


Роль db

Создаем файл роли для БД-серверов projects/kicker/db.yaml. Пока что обойдемся без разделения серверов на окружения:

---
classes:
  - profiles::db::postgresql

profiles::db::postgresql::globals:
  manage_package_repo: true
  version: '10'
profiles::db::postgresql::db_configs:
  'listen_addresses':
    value: '*' 

profiles::db::postgresql::databases:
  kicker: {}

profiles::db::postgresql::hba_rules:
  'local connect to kicker':
    type: 'local'
    database: 'kicker'
    user: 'kicker'
    auth_method: 'md5'
    order: '001'
  'allow connect from 192.168.1.100':
    type: 'host'
    database: 'kicker'
    user: 'kicker'
    auth_method: 'md5'
    address: '192.168.1.100/32'
    order: '002'

Здесь мы подключаем один профиль, написанный для общего использования всеми, кто захочет установить postgres себе на сервера. Профиль конфигурируем и позволяет гибко настроить модуль перед его применением.

Для самых любопытных ниже под катом код этого профиля:


Профиль profiles: db: postgresql
class profiles::db::postgresql (
  Hash $globals = {},
  Hash $params = {},
  Hash $recovery = {},
  Hash[String, Hash[String, Variant[String, Boolean, Integer]]] $roles = {},
  Hash[String, Hash[String, Variant[String, Boolean]]] $db_configs = {},
  Hash[String, Hash[String, Variant[String, Boolean]]] $databases = {},
  Hash[String, String] $db_grants = {},
  Hash[String, Hash[String, String]] $extensions = {},
  Hash[String, String] $table_grants = {},
  Hash[String, Hash[String, String]] $hba_rules = {},
  Hash[String, String] $indent_rules = {},
  Optional[String] $role = undef, # 'master', 'slave'
  Optional[String] $master_host = undef,
  Optional[String] $replication_password = undef,
  Integer $master_port = 5432,
  String $replication_user = 'repl',
  String $trigger_file = '/tmp/pg_trigger.file',
){

  case $role {
    'slave': {
      $_params = {
        manage_recovery_conf => true,
      }

      if $globals['datadir'] {
        file { "${globals['datadir']}/recovery.done":
          ensure => absent,
        }
      }

      $_recovery = {
        'recovery config' => {
          standby_mode     => 'on',
          primary_conninfo => "host=${master_host} port=${master_port} user=${replication_user} password=${replication_password}",
          trigger_file     => $trigger_file,
        }
      }

      $_conf = {
        'hot_standby' => {
          value => 'on',
        },
      }

      file { $trigger_file:
        ensure => absent,
      }

    }
    'master': {
      $_conf = {
        'wal_level' => {
          value => 'replica',
        },
        'max_wal_senders' => {
          value => 5,
        },
        'wal_keep_segments' => {
          value => 32,
        },
      }

      file { $trigger_file:
        ensure => present,
      }
    }
    default: {
      $_params = {}
      $_recovery = {}
      $_conf = {}
    }
  }

  class { '::postgresql::globals':
    * => $globals,
  }

  class { '::postgresql::server':
    * => deep_merge($_params, $params),
  }

  create_resources('::postgresql::server::config_entry', deep_merge($_conf, $db_configs))
  create_resources('::postgresql::server::role', $roles)
  create_resources('::postgresql::server::database', $databases)
  create_resources('::postgresql::server::database_grant', $db_grants)
  create_resources('::postgresql::server::extension', $extensions)
  create_resources('::postgresql::server::table_grant', $table_grants)
  create_resources('::postgresql::server::pg_hba_rule', $hba_rules)
  create_resources('::postgresql::server::pg_indent_rule', $indent_rules)
  create_resources('::postgresql::server::recovery', deep_merge($_recovery, $recovery))
}

Таким образом, мы одним махом устанавливаем Postgresql 10, настраиваем конфиг (listen), создаем БД kicker, а также записываем в pg_hba.conf два правила для доступа к этой базе. Круто!


Роль frontend

Беремся за frontend. Создаем файл projects/kicker/frontend.yaml следующего содержания:

---
classes:
  - profiles::webserver::nginx

profiles::webserver::nginx::servers:
  'kicker.semrush.com':
    use_default_location: false
    listen_port: 80
    server_name:
      - 'kicker.semrush.com'

profiles::webserver::nginx::locations:
  'kicker-root':
    location: '/' 
    server: 'kicker.semrush.com'
    proxy: 'http://kicker-backend.semrush.com:8080'
    proxy_set_header:
      - 'X-Real-IP $remote_addr'
      - 'X-Forwarded-for $remote_addr'
      - 'Host kicker.semrush.com'
    location_cfg_append:
      'proxy_next_upstream': 'error timeout invalid_header http_500 http_502 http_503 http_504'
    proxy_connect_timeout: '5' 

Здесь все просто. Мы подключаем профиль profiles::webserver::nginx, который подготавливает вход в модуль nginx, а также определяем переменные, а конкретно server и location для этого сайта.

Внимательный читатель заметит, что правильнее будет поместить описание сайта выше по иерархии, ведь у нас будет еще dev-окружение, и там будут использоваться другие переменные (server_name, proxy), но это не слишком важно. Описывая роль таким образом, мы сможем увидеть, как переопределяются эти переменные только лишь иерархией.


Роль docker

Осталась роль docker projects/kicker/docker.yaml:

---
classes:
  - profiles::docker

profiles::docker::params:
  version: '17.05.0~ce-0~debian-stretch'

packages:
  'python3-pip':
    provider: apt
  'Fabric3':
    provider: pip3
    ensure:   1.12.post1

user_management::users:
  deploy:
    groups:
      - docker

Профиль profiles/docker.pp очень прост и изящен. Приведу его код:


Профиль profiles: docker
class profiles::docker (
  Hash $params = {}, 
  Boolean $install_kernel = false,
){

  class { 'docker':
    * => $params,
  }

  if ($install_kernel) {
    include profiles::docker::kernel
  }
}

Все готово. Этого уже достаточно, чтобы развернуть нужный нам продукт на множестве серверов, просто назначив им определенные проект и роль (например, положив файлик в нужном формате в директорию facts.d, местоположение которой зависит от способа установки puppet).

Сейчас мы имеем следующую структуру файлов:

.
├── kicker
│   ├── db.yaml
│   ├── docker.yaml
│   └── frontend.yaml
└── kicker.yaml

1 directory, 4 files

Разберемся теперь с окружениями и определением конфигурации, уникальной для роли на конкретной площадке.


Окружения и override

Создадим общую конфигурацию для всего прода. Файл projects/kicker/tiers/prod.yaml содержит указание, что нам нужно подключить класс с файрволом на это окружение (ну, прод же все-таки), а также некий класс, обеспечивающий повышенный уровень безопасности:

---
classes:
  - semrush_firewall
  - strict_security_level

Для dev-окружения, если нам нужно описать что-то специфичное, создается такой же файл, и в него вносится нужная конфигурация.

Далее нужно все-таки переопределить переменные для nginx-конфига роли frontend в dev-окружении. Для этого понадобится создать файл projects/kicker/tiers/dev/frontend.yaml. Обратите внимание на новый уровень иерархии.

---
profiles::webserver::nginx::servers:
  'kicker-dev.semrush.com':
    use_default_location: false
    listen_port: 80
    server_name:
      - 'kicker-dev.semrush.com'

profiles::webserver::nginx::locations:
  'kicker-root':
    location: '/' 
    server: ‘kicker-dev.semrush.com'
    proxy: 'http://kicker-backend-dev.semrush.com:8080'
    proxy_set_header:
      - 'X-Real-IP $remote_addr'
      - 'X-Forwarded-for $remote_addr'
      - 'Host kicker-dev.semrush.com'
    location_cfg_append:
      'proxy_next_upstream': 'error timeout invalid_header http_500 http_502 http_503 http_504'
    proxy_connect_timeout: '5' 

Класс указывать уже не надо, он наследуется с предыдущих уровней иерархии. Здесь мы изменили server_name и proxy_pass. Сервер, у которого будут факты role=frontend и tier=dev, сначала найдет для себя файл projects/kicker/frontend.yaml, но потом переменные из этого файла будут переопределены файлом с бОльшим приоритетом projects/kicker/tiers/dev/frontend.yaml.


Сокрытие пароля для PostgreSQL

И таким образом у нас остается последний пункт на повестке дня — это задать пароли для PostgreSQL.

Пароли должны различаться в окружениях. Будем использовать eyaml для безопасного хранения паролей. Создадим пароли:

eyaml encrypt -s 'verysecretpassword'
eyaml encrypt -s 'testpassword'

Вставляем полученные строки в файлы **projects/kicker/tiers/prod/db.yaml** и **projects/kicker/tiers/dev/db.yaml** (или можно использовать расширение eyaml, это настраиваемо) соответственно. Вот пример:

---
profiles::db::postgresql::roles:
  'kicker':
    password_hash: >  'ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAsdpb2P0axUJzyWr2duRKAjh0WooGYUmoQ5gw0nO9Ym5ftv6uZXv25DRMKh7vsbzrrOR5/lLesx/pAVmcs2qbhd/y0Vr1oc2ohHlZBBKtCSEYwem5VN+kTMhWPvlt93x/S9ERoBp8LrrsIvicSYZByNfpS2DXCFbogSXCfEPxTTmCOtlOnxdjidIc9Q1vfAXv7FRQanYIspr2UytScm56H/ueeAc/8RYK51/nXDMtdPOiAP5VARioUKyTDSk8FqNvdUZRqA3cl+hA+xD5PiBHn5T09pnH8HyE/39q09gE0pXRe5+mOnU/4qfqFPc/EvAgAq5mVawlCR6c/cCKln5wJTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBDNKijGHBLPCth0sfwAjfl/gBAaPsfvzZQ/Umgjy1n+im0s]'

Далее пароль для роли kicker приедет, расшифруется и применится на БД-сервере в PostgreSQL.

На этом, собственно, и все. Да, пример получился массивным, но, надеюсь, функциональным, не оставляющим вопросов, понятным и полезным. Итоговая иерархия в hiera получилась такая:

.
├── db.yaml
├── docker.yaml
├── frontend.yaml
└── tiers
    ├── dev
    │   ├── db.yaml
    │   └── frontend.yaml
    ├── prod
    │   └── db.yaml
    └── prod.yaml

3 directories, 7 files

Вы можете посмотреть эти файлы «вживую», склонировав специально созданный репозиторий


Заключение

Puppet хорош и удобен в связке с hiera. Я бы не назвал его идеальным инструментом конфигурации в современном мире, вовсе нет, но он заслуживает внимания. С некоторыми задачами он справляется очень хорошо, а его «философия» поддержки постоянно одинакового состояния ресурсов и конфигурации может играть немаловажную роль в обеспечении безопасности и единообразия конфигураций.

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

Наша цель как админов в итоге — ничего не конфигурировать самим. Все это в идеале должны делать сами команды. А мы им должны дать инструмент или продукт, позволяющий это делать безопасно, легко и, главное, с точным результатом. Ну, и помогать решать архитектурные и более серьезные задачи, чем «Нужно установить PostgreSQL на сервер и создать пользователя». Камон, 2018-й год на дворе! Поэтому выкидывайте puppet и ansible и двигайтесь в serverless future.

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


Credits

Спасибо:


  • Дмитрию Тупицину, Дмитрию Логинову, Степану Федорову и всей команде системных администраторов за помощь в подготовке этой статьи
  • Владимиру Легкоступову за картинку
  • Яне Табаковой за организацию этого всего и помощь в прохождении всех pre-publishing этапов
  • Никите Захарову за помощь в делах лицензирования

© Habrahabr.ru