Info
Content

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
Back to top