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"
}
No Comments