Puppet
Basics
/etc/puppet/puppet.conf в блоке [main]
(либо в [agent]
) должен иметь две важных директивы
certname=puppetclient # <- имя клиента которым он будет представляться мастеру
server=puppetserver # <- доменное имя мастера
Также клиенту можно например указать runinterval=20m
и он будет самостоятельно запускаться (без крона)
На мастере puppet.conf должен также иметь две важных директивы но уже в секции [master]
certname=puppetserver
server=puppetserver
(то же самое что и в [main]
)
Чтобы на мастере подписать сертификат нового клиента нужно сделать так
$ puppet cert list # сначала смотрим какие есть неподписанные
$ puppet cert sign hostname # hostname будет тот, который прописан у клиента в директиве certname
--all
- полезный ключ
Во время работы puppet, манифесты преобразуются в каталоги. Каталог - это список ресурсов и их взаимосвязей после обработки (компиляции) логики манифестов
Комментарии начинаются с решетки
Нода, ресурс
Конфигурация ноды начинается с ключевого слова node
за которым следует хостнэйм ноды или нод, или регулярка, или ключевое слово default
Далее в фигурных скобках описывается конфигурация
Имя ноды может совпадать сразу с несколькими описаниями, но паппет выберет только одно. Про приоритет выбора есть в доке
Конфигурация является перечислением ресурсов и их параметров (не может быть двух одинаковых ресурсов с одним именем)
Описание ресурса начинается с его типа, тип указывается в нижнем регистре. После типа ресурса в фигурных скобках пишется его имя, потом двоеточие, а дальше идет опциональное перечисление его параметров (параметры указываются как хэш-таблица в ruby)
node 'phobos.vandud.ru' {
file { "/var/www/html/test.html":
owner => "www-data",
group => "www-data",
content => "nigamazafaka, sosi zhopu",
}
}
Отступы в манифестах не являются обязательными, но приветствуются. Табы не используются, нужно использовать двойной пробел
Фигурные скобки отделяются пробелом, а двоеточие нет. Запятые нужны после каждого параметра, в том числе и после последнего. Каждый параметр на отдельной строке. Но если параметров нет или он всего один, то можно и в одну строку
resorce { 'title': param => value, }
Все стрелки у параметров должны быть на одном уровне
Корневая директория это директория с манифестами
Она может отличаться в зависимости от окружения (puppet окружения, т.е. production, etc), окружения обычно используются вместе с гитом
В новых версиях паппета стало обязательным использование окружений
В старых паппетах корневой директорией была /etc/puppet
, а в новых стала /etc/puppetlabs/code/ENV
В корневой директории должна быть папка manifests
Зависимости
Зависимости определяются стрелкой ->
node 'phobos.vandud.ru' {
file { "/var/www/html/test.html":
owner => "www-data",
group => "www-data",
content => "nigamazafaka, sosi zhopu",
}
-> resorce { 'title': param => value, }
}
Это означает, что ресурс 'title' будет обработан строго после файла 'test.html'
Также можно подписывать ресурсы на события других ресурсов (важно: не все ресурсы умеют обрабатывать такие события). Это делается также как описано выше, но через волнистую стрелку ~>
. Волнистая стрелка включает в себя прямую
Например ресурс 'service' описаный после волнистой стрелки, будет перезапущен если описаный перед ним ресурс будет изменен
Такая стрелка может быть заменена с помощью метапараметров subscribe
или notify
Ссылки на ресурсы как правило используются для указания зависимостей
Синтаксис ссылки: Название типа с большой буквы, если название типа составное (через двойные двоеточия), то с большой буквы пишется каждая часть. В квадратных скобках пишется имя ресурса
file { '/file1': ensure => present }
file { '/file2':
ensure => directory,
before => File['/file1'], # before означает что file2 будет выполнен перед file1, так как file1 зависит от file2
}
file { '/file3': ensure => absent }
File['/file1'] -> File['/file3'] # такая стрелка означает: сначала левый, потом правый, также может быть и волнистая
# она означает: сначала левый, и если он изменился, то сделать notify для правого
# может быть цепочка из более чем двух ресурсов
В этом примере (насколько я понял) сначала скопируется директория 2, потом создастся файл 1, а потом 3
Классы, переменные и дефайны
Для того чтобы не повторять одно и то же много раз (и чтобы было удобнее редактировать) - придумали сабж
Класс - это именованный блок паппет кода, классы нужны для переиспользования кода
class class_name {
...
}
Сам по себе он ни на что не влияет пока его не вызовут
Вызвать класс можно двумя способами
class { 'class_name': }
include class_name # import'ы выпилили с 4 версии
Можно вынести установку и настройку какого-либо сервиса в класс и заинклудить этот класс для нужных нод
import'ы нужны для импорта манифестов, а include'ы для классов
У классов могут быть параметры
Параметры класса - это переменные в пространстве имен класса, они задаются в заголовке класса и могут быть использованы как обычные переменные в теле класса
Значения параметров указываются в момент использования класса в манифесте (можно задать умолчание)
Если нет умолчания и в манифесте параметр не указан, то будет ошибка
Параметры указываются так
class class_name ( $param1, $param2 = 'zhopa2', ) {
...
}
node 'hostname' {
class { 'class_name':
param1 => 'zhopa1',
}
}
То есть это выглядит как параметры ресурса
Можно явно указывать типы параметров (тип данных), и если при вызове класса ему переданы параметры неверного типа, то произойдет ошибка
class class_name (
String $param1,
Integer $param2 = 3,
...
) {
...
}
Классы могут наследоваться друг от друга и переопределять друг друга
class passwd {
file { "/etc/passwd":
owner => "root",
group => "root",
}
}
class passwd-bsd inherits passwd {
File["/etc/passwd"] { group => "wheel" }
}
Можно описать какой-то базовый класс с базовыми настройками (настройки доступа, безопасности и прочее) и наследоваться от него в зависимости от назначения ноды (base+web или base+db)
Дефайн похож на класс, но: каждый дефайн является типом ресурса, а не ресурсом, а также он имеет неявный параметр $title
в который попадает имя ресурса при его объявлении
define zhopa::piska (
$param1 = $title,
$param2 = 'param',
...
) {
... # а тут например описывается логика установки и копирования/создания конфигов
}
node host_name {
zhopa::piska { 'package1': }
zhopa::piska { 'package2': }
zhopa::piska { 'package3': param2 => 'param-zhopa', }
}
Дефайн нужен например для описанного выше случая (когда мы описали свой ресурс и хотим многократно его использовать в рамках одной ноды)
Класс такого не позвляет, так как у класса нет чего-то вроде $title
Переменные в puppet неизменяемые и обращаться к ним можно строго после их объявления
В паппете есть пространства имен и области видимости
Например: пространство класса, пространство ноды, глобальное пространство
Чтобы избежать неоднозначности можно явно указывать нужное пространство
$var
$::var
$class_name::var
$::class_name::var
Условные операторы и селекторы
if
if EXPR1 {
...
} elseif EXPR2 {
...
} else {
...
}
unless
unless - это if наоборот (блок кода будет выполнен если выражение ложно)
unless EXPR {
...
}
case
case EXPR {
VALUE1: { ... } # в качестве значений можно использовать обычные значения, а также регулярки и типы данных
VALUE2, VALUE3: { ... }
default: { ... }
}
Пример:
case $operatingsystem {
redhat: { service { "httpd": ensure => running }}
debian: { service { "apache": ensure => running }}
default: { service { "apache2": ensure => running }}
}
Селекторы
Селектор это как case
, только вместо выполнения кода она возвращает значение
$var = $var2 ? { 'val1' => 1, 'val2' => 2, default => 3, }
То есть var
будет равна единице если var2
равна строке 'val1'
Еще пример с селектором
file { "/etc/passwd":
owner => "root",
group => $kernel ? {
Linux => "root",
FreeBSD => "wheel",
},
}
Модули
Модуль это набор классов, дефайнов и прочих сущностей вынесенных в отдельную директорию. То есть это независимый кусок логики, который например нужен для работы с nginx
Есть открытый репозиторий модулей https://forge.puppet.com
На паппет-сервере модули лежат в папке modules относительно корневой директории
Внутри каждого модуля стандартная схема директорий: manifests, files, templates, lib, etc
Существует прямое соответствие между именами ресурсов и именами файлов в которых паппет будет их искать (поэтому нельзя называть ресурсы как попало)
Правила:
- Все ресурсы модуля должны быть в неймспейсе модуля (если модуль называется
foo
, то ресурсы -foo::name
) - Ресурс с названием модуля должен быть в файле
init.pp
- Схема именования файлов для остальных ресурсов:
- Префикс с именем модуля отбрасывается
- Двойные двоеточия заменяются на слэши
- Дописывается
.pp
Например модуль nginx:
- Класс nginx описан в init.pp
- Класс nginx::service описан в service.pp
- Дефайн nginx::server описан в server.pp
- Дефайн nginx::server::location описан в server/location.pp
Шаблоны
Шаблоны можно раскрывать с помощью функции template()
, например для ресурса file
В template
путь вида <modulename>/<filename> подразумевает под собой путь <rootdir>/modules/<modulename>/templates/<filename>
Также существует функция inline_template которая принимает сам текст шаблона, а не путь к файлу
Внутри шаблонов можно использовать переменные в рамках области видимости
ERB
Управляющие конструкции:
-
<%= EXPR %>
- вставить значение выражения -
<% EXPR %>
- вычислить значение не вставляя его (для условий, циклов, etc) -
<%# COMMENT %>
- комментарий
Выражения пишутся на Ruby
Для доступа к переменным из манифеста нужно дописывать @
перед именем переменной
Чтобы убрать перевод строки, который создается закрывающим тэгом, нужно использовать закрывающий тэг с минусом -%>
В качестве примера использования можно представить класс, который кладет конфиг из шаблона и наполняет его переменными, а переменные у каждой ноды свои
class module::configure (
$var1,
... # много переменных которые используются в шаблоне
) {
file { '/etc/config':
ensure => present,
content => template('config.erb'),
}
}
Факты и встроенные переменные
Факты это информация о ноде доступная в виде переменных в глобальном пространстве
Во время работы паппет-агент сначала копирует с сервера все доступные сборщики фактов (а они бывают разные и могут быть кастомными), далее запускает их и шлет собранные факты на сервер, после этого сервер начинает компиляцию каталога
Обращаться к фактам можно:
- Через словарь $facts -
$facts['fqdn'];
- Используя имя факта как имя переменной -
$fqdn
Лучше использовать словарь (а еще лучше с глобольным неймспейсом - $::facts['aoeuaeu']
Кроме фактов о клиенте есть еще некоторые переменные которые можно использовать
- Переменные из сертификата: название серта, имя хоста, итд
- Факты о сервере
- Переменные добавляемые агентом а не фактером (что-то о серте, версия агента, версия паппета, итд)
- Переменные компилятора, которые различаются в каждой области видимости (имя текущего модуля и тд)
fileserver
Для доступа клиентам к файлам в паппете предусмотрен файлсервер
В файле /etc/puppet/fileserver.conf описываются его настройки
[files]
path /etc/puppet/files
allow *.vandud.ru
И далее в манифестах можно вызывать файлы используя путь до этого файлсервера
file { "/super/file":
source => "puppet:///files/super-file"
}
Skills
Выключен ли puppet
Следующей командой получить директорию временных файлов puppet'a:
puppet config print vardir
Далее в полученной директории посмотреть файл state/agent_disabled.lock, то есть полный путь (обычно) будет выглядеть так:
/var/lib/puppet/state/agent_disabled.lock
Внутри этого файла будет сообщение (которое было указано при отключении паппета puppet agent --disable 'message'
)
Если файла нет, значит паппет не выключен
Также есть более простой способ, но он не так надежен как предыдущий
Можно просто посмотреть в /var/log/daemon.log и там будут записи от попыток запуска паппета. Там будут либо успешные записи с результатом работы, либо записи о том что паппет выключен. Но это не сработает если паппет был выключен недавно и он еще не запускался после выключения
Список файлов под паппетом
На каждом хосте есть специальный файл в котором задекларированно состояние сервера
Его можно вывести вот так
sudo cat `sudo puppet config print statedir`/resources.txt
Применение манифестов без сервера
Можно применять манифесты на клиенте без использования сервера
$ puppet apply manifest.pp
Дефолтные конфиги
Можно сгенерировать дефолтные конфиги чтобы посмотреть что там к чему и что вообще есть (как для клиента, так и для сервера)
$ puppet master --genconfig > puppetd.conf.default
$ puppet agent --genconfig > puppet-agent.conf.default
Установка
Версия 7.0 6
1. Подключение репозитория
https://apt.puppet.com/ - вот тут найти нужный пакет и установить руками через dpkg
Автоматом добавится нужный репозиторий
root@phobos:~# wget https://apt.puppet.com/puppet7-release-buster.deb
--2020-12-26 03:32:57-- https://apt.puppet.com/puppet7-release-buster.deb
Resolving apt.puppet.com (apt.puppet.com)... 13.32.240.20, 13.32.240.14, 13.32.240.53, ...
Connecting to apt.puppet.com (apt.puppet.com)|13.32.240.20|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11748 (11K) [application/x-debian-package]
Saving to: ‘puppet7-release-buster.deb’
puppet7-release-buster.deb 100%[========================================================================>] 11.47K --.-KB/s in 0s
2020-12-26 03:32:57 (230 MB/s) - ‘puppet7-release-buster.deb’ saved [11748/11748]
root@phobos:~# dpkg -i puppet7-release-buster.deb
Selecting previously unselected package puppet7-release.
(Reading database ... 32694 files and directories currently installed.)
Preparing to unpack puppet7-release-buster.deb ...
Unpacking puppet7-release (7.0.0-1buster) ...
Setting up puppet7-release (7.0.0-1buster) ...
root@phobos:~# apt update
Hit:1 http://security.debian.org/debian-security buster/updates InRelease
Hit:2 http://mirror.yandex.ru/debian buster InRelease
Get:3 http://apt.puppetlabs.com buster InRelease [99.2 kB]
Get:4 http://apt.puppetlabs.com buster/puppet7 amd64 Packages [8,108 B]
Get:5 http://apt.puppetlabs.com buster/puppet7 all Packages [2,328 B]
Fetched 110 kB in 1s (123 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
All packages are up to date.
root@phobos:~#
Суть этого пакета вот в чем
root@two:~/puppet6# dpkg -c puppet6-release-buster.deb
drwxr-xr-x root/root 0 2021-02-04 22:48 ./
drwxr-xr-x root/root 0 2021-02-04 22:48 ./etc/
drwxr-xr-x root/root 0 2021-02-04 22:48 ./etc/apt/
drwxr-xr-x root/root 0 2021-02-04 22:48 ./etc/apt/sources.list.d/
-rw-r--r-- root/root 74 2021-02-04 22:48 ./etc/apt/sources.list.d/puppet6.list
drwxr-xr-x root/root 0 2021-02-04 22:48 ./etc/apt/trusted.gpg.d/
-rw-r--r-- root/root 10352 2021-02-04 22:48 ./etc/apt/trusted.gpg.d/puppet6-keyring.gpg
drwxr-xr-x root/root 0 2021-02-04 22:48 ./usr/
drwxr-xr-x root/root 0 2021-02-04 22:48 ./usr/share/
drwxr-xr-x root/root 0 2021-02-04 22:48 ./usr/share/doc/
drwxr-xr-x root/root 0 2021-02-04 22:48 ./usr/share/doc/puppet6-release/
-rw-r--r-- root/root 44 2021-02-04 22:48 ./usr/share/doc/puppet6-release/bill-of-materials
-rw-r--r-- root/root 147 2021-02-04 22:48 ./usr/share/doc/puppet6-release/changelog.Debian.gz
Установка сервера
apt install puppetserver
Автоматом подтянутся нужные java-пакеты
systemctl start/enable puppetserver
Может не стартануть, смотри ниже про память
$ cat /var/log/puppetlabs/puppetserver/puppetserver_err_pid24969.log
...
There is insufficient memory for the Java Runtime Environment to continue
...
Конфигурирование JVM для puppetserver
Так как паппет на джаве, то нужно обязательно изменить настройки потребления памяти для него (а то не запустится на слабой машине, а на мощной отберет неоправданно много ресурсов)
Настройки джавы указываются в /etc/default/puppetserver
Меняем
JAVA_ARGS="-Xms2g -Xmx2g -Djruby.logger.class=com.puppetlabs.jruby_utils.jruby.Slf4jLogger"
На
JAVA_ARGS="-Xms256m -Xmx256m -Djruby.logger.class=com.puppetlabs.jruby_utils.jruby.Slf4jLogger"
Установка агента
apt install puppet-agent
Следом за установкой предлагается выполнить такую команду
root@phobos:~# sudo /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
Notice: /Service[puppet]/ensure: ensure changed 'stopped' to 'running'
service { 'puppet':
ensure => 'running',
enable => 'true',
provider => 'systemd',
}
Конфигурирование PATH
При установке добавляется скрипт /etc/profile.d/puppet-agent.sh
, он автоматом правит PATH при логине
Но можно и руками добавить export PATH=/opt/puppetlabs/bin:$PATH
в какой-нибудь .bashrc
Конфигурирование агента
Изменить конфигурацию агента можно изменив файл /etc/puppetlabs/puppet/puppet.conf
Или можно воспользоваться командой puppet config set
puppet config set server puppet.vandud.ru --section main
puppet config set dns_alt_names phobos.vandud.ru --section main
Подключение агента к серверу и подпись сертификатов
На клиенте с настроенным конфигом выполнить
puppet ssl bootstrap
На сервере подписать сертификат
sudo puppetserver ca sign --certname <name>
И еще раз на клиенте
puppet ssl bootstrap
root@phobos:/opt/puppetlabs/bin# ls -lh
total 0
lrwxrwxrwx 1 root root 24 Dec 14 11:35 facter -> ../puppet/bin/wrapper.sh
lrwxrwxrwx 1 root root 24 Dec 14 11:35 hiera -> ../puppet/bin/wrapper.sh
lrwxrwxrwx 1 root root 24 Dec 14 11:35 puppet -> ../puppet/bin/wrapper.sh
lrwxrwxrwx 1 root root 44 Dec 12 06:50 puppetserver -> ../server/apps/puppetserver/bin/puppetserver
Конфигурирование
Все настройки в /etc/puppetlabs/puppet/puppet.conf