Варіант розгортання Linux систем на базі Puppet 4. Частина III: установка Puppet Server (cfpuppetserver)

Коротко:
  1. cfpuppetserver — модуль автоматичного налаштування Puppet Server + PuppetDB + PostgreSQL + r10k + librarian-puppet
  2. Короткий вступ в Puppet
  3. Описується початкове розгортання з нуля

Тематичний цикл:
Трохи лірики. Здавалося б з цієї статті слід починати весь цикл, але все ж цільовою аудиторією є більш досвідчені користувачі Open Source продуктів Puppet Labs, яких не влаштовують окремі малоинтегрированные модулі з Puppet Forge. Як і з будь-яким випадком "library vs. framework", розплатою є дотримання світогляду автора інтегрованого рішення.

Трохи про принцип роботи Puppet
Puppet — це в першу чергу специфічний мова декларативного завдання кінцевого стану системи. Для порівняння вкрай підійде GNU Makefile, де крім безпосереднього опису залежностей є можливість начудуватися на повну котушку.

Абстракція Puppet приблизно наступназрив шаблонів — забудьте все, що ви знали про термінах в програмуванні!.

  • Вузол (node) — це сукупність конфігурації для конкретної цільової системи. На ділі це приватний випадок класу.
  • Клас (class) — це набір декларативною логіки, яка включається в конфігурацію вузла або інші класи. У класу немає ні примірників, ні методів, зате є параметри і змінні, визначені в межах логіки. Насправді, це швидше процедура, яка може успадковувати іншу процедуру банальним нарощуванням коду і не зовсім банальної областю видимості змінних.
  • Тип (type) — а ось це вже більше скидається на класичний клас — у нього передбачаються екземпляри з ім'ям і виразно заданими параметрами, але нічого більше. Конкретна реалізація типу може бути написана у вигляді Puppet скрипта через
    define
    , який створює екземпляри інших типів або ж у вигляді розширення на Ruby з польотом фантазії.
  • Ресурс (resource) — власне це і є іменовані примірники Типів. Ім'я кожного ресурсу унікально у рамках конкретного типу в межах конфігурації хоста (каталогу).
  • Змінні (variable) — ну, коротше це константи… До версії Puppet 4 з їх областю видимості було все ще гірше. Тепер вона адекватна: для використання ззовні визначення місця потрібно задавати повністю кваліфікований идентифиактор, за винятком випадку успадкування класів.
Puppet може використовуватися для локального без розгортання мережі та відповідної інфраструктури. Це може використовуватися для створення образів контейнерів. Є навіть цілий напрям виступають за відмову від централізованого сервера.

В ідеологічно правильному ключі, інфраструктура Puppet складається з агента — привілейованого сервісу на цільовій системі і сервера, роздає цінні вказівки у вигляді декларативних каталогів ресурсів за запитом від агентів. Безпека реалізована на рівні приватної інфраструктури публічного ключа (X. 509). Просто кажучи, тих же механізмів, що і HTTPS, але з власним CA і обов'язковою перевіркою клієнтського сертифіката.

У спрощеному вигляді процедура розгортання виглядає приблизно так:

  1. Обробка за TLS і X. 509 (установка з'єднання, оновлення CRL, перевірка обмежень сертифіката тощо)
  2. Агент отримує генератори фактів з сервера з кешуванням і всіма справами (точніше витягується все з папок lib/ в модулях). Не складає ніяких труднощів додати свій Ruby скрипт для збору необхідної інформації.
  3. Агент збирає факти про цільовий системі і відправляє на сервер. Всі факти легко переглянути вручну через виклик
    puppet facts
    . Ці факти доступні в якості глобальних змінних.
  4. Сервер складає каталог ресурсів і надсилає агенту. Під цим ховається цілий пласт різних концепцій.
  5. Агент витягує все необхідне з сервера і приводить систему до зазначеному виду. Сам агент при цьому не знає, як чинити з ресурсами, він покладається на реалізацію provider'ів (смисловий переклад буде "втілювач", а не постачальник) конкретних типів ресурсів. Частина provider'ів є стандартними і входять в пакети Puppet, а решта витягуються з модулів.
Для куштування всіх принад, існує додаткові плюшки у вигляді:

  • Модуль — сукупність декларативних скриптів Puppet, Ruby розширень для Puppet, файлів, шаблонів файлів, Hiera даних і багато чого іншого. Більш правильний термін був би "пакет".
  • Середовище (Environment) — сукупність скриптів, модулів і Hiera даних. З ускладненням інфраструктури неминуче треба було розділяти конфігурацію далі стандартного розподілу по вузлам. В основному, це потрібно для пілотних нововведень і банального контролю доступу (коли не всі адміни мають доступ до всіх вузлів IT інфраструктури).
  • Hiera — ієрархічна база даних. Таке формулювання може сильно відлякувати. Ймовірно тому її і поміняли в документації більш пізніх версій. На ділі це вкрай простий і зручний механізм витягати конфігурацію з YAML або JSON файлів. Ієрархія полягає в можливості задати порядок читання безлічі конфігураційних файлів — тобто ієрархію/пріоритет цих файлів.
    • Крім витягування даних викликом функції, Puppet витягає параметри класів за замовчуванням, що є головною родзинкою.
    • Зрозуміло, Hiera підтримує інтерполяцію фактів і навіть виклик спеціальних функцій.
    • Puppet 4.3 реалізували цей же функціонал ще раз для підтримки не тільки глобальної бази даних, але і для локальної Середовища і Модуля, щоправда автор вже знайшов кілька проблем у їх реалізації (PUP-5983, PUP-5952 і PUP-5899), які були моментально виправлені Puppet Labs.
    • Підтримуються кілька стратегій витягування значення всіх файлів по ієрархії:
      • first
        — видається першу-ліпшу за пріоритетом значення

      • unique
        — збирає всі значення в одновимірний масив і прибирає дублікати
      • hash
        — об'єднує всі знайдені YAML Hash. Дублікати ключів вибираються по пріоритету.
      • deep
        — по суті рекурсивний варіант hash
    • Принадність у тому, що стратегія вибірки може задаватися як при виклику функції
      lookup()
      , т. к. і в будь-якому файлі ієрархії через спеціальний ключ lookup_options, що активно використовується в модулі cfnetwork.
  • PuppetDB — по суті шар бізнес логіки навколо реляційної бази даних PostgreSQL), який дозволяє зберігати звіти про факти і виконаних розгортання і експортувати ресурси для подальшого імпорту в каталоги на інших вузлах або вибірки через спеціальні функції. Ще є і веб-морда у вигляді Puppet Dashboard.
  • X. 509 PKI — вже згадана інфраструктура сертифікатів, яку дуже зручно використовувати для інших сервісів без необхідності управління окремою інфраструктурою.
  • MCollective — начебто корисна річ для подієвого запуску завдань на серверній фермі, але у автора є певна недовіра до безпеки конкретного рішення.
  • Puppet Forge — відкрита майданчик для публікації та завантаження Модулів.
  • деякі інші фічі у вигляді управління зовнішніми пристроями типу обладнання Cisco і розгортання на голому залозі, але це вже окрема історія
Нотатки з безпеки і доступності
Потрібно розуміти, що Puppet Server стає вразливим місцем всієї IT-інфраструктури, т.к. визначає кінцеву конфігурацію всіх систем. В особливих випадках має сенс робити поділ — окремий сервер для критичних елементів інфраструктури з вкрай обмеженим доступів і ручним оновленням і другий для всього іншого.

Доступність Puppet Server визначає можливість управління всією інфраструктурою. Має сенс розміщувати Puppet Server на виртуалке в більш надійному і швидко восстанавливаемом сторонньому хмарі, ніж власні можливості. Або ж слід встановлювати кілька серверів.

У будь-якому випадку, не слід встановлювати інші сервіси на системі, де буде розгорнуто Puppet Server з прибамбасами. Віртуалізація і контейнеризація вам в допомогу.

Мульти-майстер (кілька відокремлених Puppet Server)
  • В даному випадку тільки один сервер виступає в ролі CA (Certificate Authority) — його недоступність означає неможливість додати нові вузли.
    • Puppet допускає використовувати сторонню інфраструктуру X. 509, якщо вбудована не влаштовує.
  • Вся конфігурація (Середа) повинна зберігатись у системі контролю версій і розгортатися на кожному сервері одночасно.
  • Єдине спільне — це база PostgreSQL, організація високої доступності якої виходить за рамки даної статті.
  • Модуль cfpuppetserver підтримує встановлення в якості основного (CA) і в якості другорядного сервера.
Що значуще змінилося з більш старих версій
Повний опис є у виробника.

  • Всі сервіси переїхали на JVM, JRuby і Jetty. За очевидними плюсами інтегрованості є і мінуси по витраті пам'яті.
  • Додалися лямбда-функції для обробки колекцій — тепер немає необхідності пиляти милиці на Ruby або перекручуватися через create_resources()
  • З'явився інструмент обробки шаблонів EPP — по суті той же ERB, але з Puppet DSL замість Ruby,
  • Сильно помінялася структура каталогів конфігураційних файлів за умовчанням
  • З'явилася підтримка Data Providers для Середовищ і модулі більше не потрібні хакі).
  • Приниження ролі глобальної Hiera. Нова пов'язана з цим команда
    puppet lookup
    .
Установка
Даний процес досить примітивний, але вимагає дотримання певної послідовності кроків. Оскільки робити це вручну невдячне заняття, автор поганому навчить, а саме скачувати незрозумілі скрипти з інтернету і запускати під root'ом на своїй системі.

Три основних компоненти сервера — це сам Puppet Server, PuppetDB і PostgreSQL. Їх усіх можна запхати на один вузол або ж розбити на дві-три системи. Puppet Server і Puppet DB можуть бути запущені безліч разів, а ось PostgeSQL є єдиним вузлом відмови. Є різноманітні підхід до реплікації і кластеризації PostgeSQL.Зручний підхід у випадку основного та другорядного серверів буде Master + Read-Only Slave, що підтримується в самому PuppetDB як основний і read-only вузол бази даних, але автоматизація такої установки вимагає часу і тому поки що не входить в модуль
cfpuppetserver
.

Безпосередньо конфігурацію можна просто зберігати хоч на файловій системі разом з Puppet Server, але це як писати скрипти на бойовому веб-сервері. Саме відповідне рішення — це git репозиторій. Утиліта r10k уміє витягувати всі гілки репозиторію і розгортати їх на Puppet Server як окремі Середовища. У
r10k
досить погано з витягуванням залежностей, тому поверх використовується librarian-puppet. Варто відразу зауважити, що основний канонічної Середовищем Puppet є "production". Тому в репозиторії конфігурації слід використовувати гілку з назвою "production", а не "master".

Системні вимоги
По залізу описано самим виробником. Модуль
cfpuppetserver
поки підтримує тільки Debian Jessie+ і Ubuntu Вірного+.

Конфігурація в Git
Для самого r10k розміщення сховища не має великого значення — головне його доступність. Наприклад, в цілях тестування репозиторій можна розмістити на тій же системі з доступом через
file://
. Хорошим стартом буде приклад конфігурації codingfuture/puppet-exampleenv.

  1. Клонируем репозиторій:
    git clone https://github.com/codingfuture/puppet-exampleenv my-puppet-conf && cd my-puppet-conf
  2. Встановлюємо загальні налаштування админского доступу, використовуючи підказки в коментарях:
    • $data EDITOR/common.yaml

  3. Створимо конфігурацію вузлів:
    • $MY_DOMAIN
      — кореневе доменне ім'я (наприклад, example.org)

    • $HOST_NAME
      — ім'я клієнтського сайту без домену
    • mkdir data/$MY_DOMAIN
    • cp data/example.com/puppet.yaml data/${MY_DOMAIN}/puppet.yaml
    • $EDITOR nano -w data/${MY_DOMAIN}/puppet.yaml
      — налаштування вузла з Puppet Server за підказками у коментарях
    • cp data/example.com/host.yaml data/${MY_DOMAIN}/${HOST_NAME}.yaml
    • $EDITOR nano -w data/${MY_DOMAIN}/${HOST_NAME}.yaml
      — настройка довільного вузла за підказками у коментарях
  4. Пушаем на власний Git сервер або ж робимо доступним локально на сайті з Puppet Server через rsync або scp. Локальний репозиторій зручний як проміжний крок поки Git сервер не розгорнуть з самого ж Puppet. У якомусь сенсі це нагадує збірку компілятора в кілька етапів.
Ставимо з нуля на чистій системі
Модуль
cfpuppetserver
дозволяє встановити всі засобами самого ж Puppet, але для початкового встановлення базові операції продубльовані скриптом Bash.

На цільовій системі:

  1. Завантажуємо скрипт установки:
    wget https://raw.githubusercontent.com/codingfuture/puppet-cfpuppetserver/master/setup_puppetserver.sh
  2. Переглядаємо скрипт та похмуре бровки:
    less setup_puppetserver.sh
  3. Запускаємо:
    bash setup_puppetserver.sh <repo_uri> puppet.${MY_DOMAIN}
    .
    • Приклад з віддаленим сховищем:
      bash setup_puppetserver.sh ssh://git@git.example.com/puppet-conf
    • Приклад з локальним:
      bash setup_puppetserver.sh file:///root/puppetconf/
  4. Дивимося як пижиться система і не дуже швидко всі встановлює.
  5. Якщо віддалений репозиторій:
    • Створюємо ключ SSH у root'а:
      ssh-keygen -t rsa -b 2048

    • Прописуємо публічний ключ
      /root/.ssh/id_rsa.pub
      на віддаленому сервері Git...
    • … і там же настриваем Git hook з викликом наступної команди:
      /usr/bin/ssh -T deploypuppet@puppet.${MY_DOMAIN} ./puppetdeploy.sh
  6. Запускаємо розгортання конфігурації вручну:
    /etc/puppetlabs/deploy.sh
  7. Пробуємо як працює на сервері:
    /opt/puppetlabs/bin/puppet agent --test
  8. Перевірте налаштування мережі, мережевого фільтра і SSH-доступу
Додаємо керовані вузли
  1. Повне ім'я Puppet Server повинно бути доступно через DNS на керованому сайті або "зашити" в /etc/hosts.
    • Приклад:
      echo "128.1.1.1 puppet.example.com" >> /etc/hosts

  2. На сайті з Puppet Server запускаємо наступний скрипт
    /root/genclientinit.sh ${HOST_NAME}.${MY_DOMAIN}
    .
  3. Результат копіюємо цілком і вставляємо в командний рядок на цільовій системі.
  4. Чекаємо завершення виконання і запускаємо
    /opt/puppetlabs/bin/puppet agent --test
    . При першому запуску буде згенерований запит на підпис сертифіката.
  5. Йдемо на сайт Puppet Server щоб підписати сертифікат.
    • puppet cert list
      — звіряємо сигнатуру сертифіката для більшої параноїдальності.

    • puppet cert sign ${HOST_NAME}.${MY_DOMAIN}
      — власне, підписуємо сертифікат.
  6. Повертаємося на керований вузол і запускаємо: /opt/puppetlabs/bin/puppet agent --test` ще раз. Це примусово запустить процедуру розгортання.
  7. Чекаємо поки закінчиться виконання розгортання через Puppet Agent.
  8. Все, у вас готова мінімальна інфраструктура Puppet!
Приклад виводу /root/genclientinit.sh
bash <<EOT
#!/bin/bash

http_proxy=

if test "\$(id -un)" != 'root'; then
echo 'This script must run as root'
exit 1
fi

if test ! -z ""; then
echo -n >/etc/cflocation
fi
if test ! -z ""; then
echo -n >/etc/cflocationpool
fi

if test ! -z "\$http_proxy"; then
export http_proxy
export https_proxy="\$http_proxy"
export HTTP_PROXY="\$http_proxy"
export HTTPS_PROXY="\$http_proxy"
fi

echo host.example.com > /etc/hostname
hostname host.example.com

if ! which lsb-release | read; then
apt-get install lsb-release
fi

codename=\$(lsb_release -cs)

if test -z "\$codename"; then
echo "Failed to detect correct codename"
exit 1
fi

wget https://apt.puppetlabs.com/puppetlabs-release-pc1-\${codename}.deb
dpkg -i puppetlabs-release-pc1-\${codename}.deb

mkdir -p /etc/puppetlabs/puppet

cat > /etc/puppetlabs/puppet/puppet.conf <<EOF
[main]
certname = host.example.com
server = puppet.example.com
ca_server = puppet.example.com
environment = production
EOF

apt-get update &&
apt-get install puppet-agent

while ! /opt/puppetlabs/bin/puppet agent --test --wairforcert 120; do
echo "Please go to puppetserver and exec the following command when we wait for key"
echo "> puppet cert sign host.example.com"
echo "Use CTRL+C to stop cycle, fails if due to different reasons"
sleep 5
done
EOT


Опис модуля
Повний список параметрів Bash скрипта початкової установки
~# ./setup_puppetserver.sh
Usage: ./setup_puppetserver.sh <r10k_repo_url> [<certname=hostname> [<cflocation> [<cflocationpool> [<http_proxy>] ] ] ]

  • r10k_repo_url
    — URI Git репозиторію
  • certname
    — повне доменне ім'я сайту
  • cflocation
    — ініціалізація факту cf_location
  • cflocationpool
    — ініціалізація факту cf_location_pool
  • http_proxy
    — проксі сервера для HTTP та HTTPS запитів
Повний список параметрів Bash скрипта ініціалізації клієнта Puppet
~# /root/genclientinit.sh 
Usage: ./genclientinit.sh <certname> [<cflocation> [<cflocationpool> [<http_proxy>]]]

Значення параметрів таке ж, як у попереднього сценарію.

клас
cfpuppetserver

  • deployuser = 'deploypuppet'
    — ім'я користувача для автоматичного розгортання оновлень конфігурації
  • deployuser_auth_keys = undef
    — список ключів для $deployuser
  • repo_url = undef
    — URI репозиторію (приклад: ssh://user@host/repo або file:///some/path)
  • puppetserver = true
    — встановлювати компонент Puppet Server на даний вузол
  • puppetdb = true
    — встановлювати компонент PuppetDB на даний вузол
  • puppetdb_port = 8081
    — порт для PuppetDB
  • setup_postgresql = true
    — встановлювати компонент PostgreSQL на цей сайт (тільки якщо включена установка PuppetDB)
  • service_face = 'any'
    — назва ресурсу
    cfnetwork::iface
    для прийняття вхідних з'єднань
  • puppetserver_mem = auto
    — оперативна пам'ять під Puppet Server мегайбатах (мінімум 192MB)
  • puppetdb_mem = auto
    — оперативна пам'ять під PuppetDB в мегайбатах (мінімум 192MB)
  • postgresql_mem = auto
    — оперативна пам'ять під PostgreSQL в мегайбатах (мінімум 128MB)
клас
cfpuppetserver::puppetdb

  • postgresql_host = 'localhost'
    — адреса бази даних
  • postgresql_listen = $postgresql_host
    — значення йде прямо в директиву
    listen_addresses
    PostgreSQL
  • postgresql_port = 5432
    — порт бази даних
  • postgresql_user = 'puppetdb'
    — користувач PuppetDB в базі даних
  • postgresql_pass = 'puppetdb'
    — пароль користувача PuppetDB в базі даних
  • postgresql_ssl = false
    — включення шифрування з'єднання на основі сертифікатів Puppet PKI
клас
cfpuppetserver::puppetserver

  • autosign = false
    — НЕ ВАРТО використовувати в бойовій середовищі, хіба що в DMZ. Існує виключно для автоматизації тестування.
  • global_hiera_config = 'cfpuppetserver/hiera.yaml'
    — шлях до файлу конфігурації Hiera за замовчуванням за канонами Puppet (перший компонент — назва модуля, решта — шлях під папкою
    files/
    в модулі)


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.