Puppet ir konfigurācijas pārvaldības sistēma. To izmanto, lai nogādātu saimniekus vēlamajā stāvoklī un uzturētu šo stāvokli.
Es strādāju ar Puppet jau vairāk nekā piecus gadus. Šis teksts būtībā ir tulkots un pārkārtots galveno punktu apkopojums no oficiālās dokumentācijas, kas ļaus iesācējiem ātri izprast Lelles būtību.
Pamatinformācija
Puppet operētājsistēma ir klients-serveris, lai gan tā atbalsta arī bezservera darbību ar ierobežotu funkcionalitāti.
Tiek izmantots vilkšanas darbības modelis: pēc noklusējuma klienti reizi pusstundā sazinās ar serveri, lai iegūtu konfigurāciju un to lietotu. Ja esat strādājis ar Ansible, tad viņi izmanto citu push modeli: administrators iniciē konfigurācijas pielietošanas procesu, paši klienti neko nelietos.
Tīkla komunikācijas laikā tiek izmantota divvirzienu TLS šifrēšana: serverim un klientam ir savas privātās atslēgas un atbilstošie sertifikāti. Parasti serveris klientiem izsniedz sertifikātus, bet principā ir iespējams izmantot ārēju CA.
Ievads manifestos
Leļļu terminoloģijā uz leļļu serveri savienot mezgli (mezgli). Mezglu konfigurācija ir uzrakstīta manifestos īpašā programmēšanas valodā - Puppet DSL.
Leļļu DSL ir deklaratīva valoda. Tas apraksta vēlamo mezgla stāvokli atsevišķu resursu deklarāciju veidā, piemēram:
- Fails pastāv, un tam ir noteikts saturs.
- Pakete ir instalēta.
- Pakalpojums ir sācies.
Resursi var būt savstarpēji saistīti:
- Ir atkarības, tās ietekmē resursu izmantošanas kārtību.
Piemēram, “vispirms instalējiet pakotni, pēc tam rediģējiet konfigurācijas failu un pēc tam sāciet pakalpojumu”. - Ir paziņojumi – ja kāds resurss ir mainījies, tas nosūta paziņojumus uz tā abonētajiem resursiem.
Piemēram, ja mainās konfigurācijas fails, varat automātiski restartēt pakalpojumu.
Turklāt Puppet DSL ir funkcijas un mainīgie, kā arī nosacījuma priekšraksti un atlasītāji. Tiek atbalstīti arī dažādi šablonu mehānismi – EPP un ERB.
Lelle ir rakstīta rubīnā, tāpēc daudzas konstrukcijas un termini ir ņemti no turienes. Rubīns ļauj paplašināt Puppet - pievienot sarežģītu loģiku, jaunus resursu veidus, funkcijas.
Kamēr darbojas Puppet, katra konkrētā servera mezgla manifesti tiek apkopoti direktorijā. Katalogs ir resursu un to attiecību saraksts pēc funkciju, mainīgo vērtību aprēķināšanas un nosacījumu priekšrakstu paplašināšanas.
Sintakse un koda stils
Šeit ir oficiālās dokumentācijas sadaļas, kas palīdzēs izprast sintaksi, ja ar sniegtajiem piemēriem nepietiek:
Šeit ir piemērs, kā izskatās manifests:
# Комментарии пишутся, как и много где, после решётки.
#
# Описание конфигурации ноды начинается с ключевого слова node,
# за которым следует селектор ноды — хостнейм (с доменом или без)
# или регулярное выражение для хостнеймов, или ключевое слово default.
#
# После этого в фигурных скобках описывается собственно конфигурация ноды.
#
# Одна и та же нода может попасть под несколько селекторов. Про приоритет
# селекторов написано в статье про синтаксис описания нод.
node 'hostname', 'f.q.d.n', /regexp/ {
# Конфигурация по сути является перечислением ресурсов и их параметров.
#
# У каждого ресурса есть тип и название.
#
# Внимание: не может быть двух ресурсов одного типа с одинаковыми названиями!
#
# Описание ресурса начинается с его типа. Тип пишется в нижнем регистре.
# Про разные типы ресурсов написано ниже.
#
# После типа в фигурных скобках пишется название ресурса, потом двоеточие,
# дальше идёт опциональное перечисление параметров ресурса и их значений.
# Значения параметров указываются через т.н. hash rocket (=>).
resource { 'title':
param1 => value1,
param2 => value2,
param3 => value3,
}
}
Atkāpes un rindiņu pārtraukumi nav obligāta manifesta daļa, taču ir ieteicama
- Divu atstarpju atkāpes, tabulēšanas zīmes netiek izmantotas.
- Cirtainās breketes ir atdalītas ar atstarpi; kolus neatdala ar atstarpi.
- Komati aiz katra parametra, ieskaitot pēdējo. Katrs parametrs ir atsevišķā rindā. Izņēmums ir gadījumam bez parametriem un viena parametra: var rakstīt vienā rindā un bez komata (t.i.
resource { 'title': }
иresource { 'title': param => value }
). - Bultiņām uz parametriem jābūt vienā līmenī.
- To priekšā ir uzrakstītas resursu attiecību bultiņas.
Failu atrašanās vieta pappetserverā
Lai iegūtu sīkāku skaidrojumu, es iepazīstināšu ar jēdzienu “saknes direktorijs”. Saknes direktorijs ir direktorijs, kurā ir noteikta mezgla leļļu konfigurācija.
Saknes direktorijs atšķiras atkarībā no Puppet versijas un izmantotajām vidēm. Vides ir neatkarīgas konfigurācijas kopas, kas tiek glabātas atsevišķos direktorijos. Parasti lieto kopā ar git, tādā gadījumā vides tiek veidotas no git zariem. Attiecīgi katrs mezgls atrodas vienā vai otrā vidē. To var konfigurēt pašā mezglā vai ENC, par ko es runāšu nākamajā rakstā.
- Trešajā versijā ("vecā lelle") bija bāzes direktorijs
/etc/puppet
. Vides izmantošana nav obligāta - piemēram, mēs tās neizmantojam ar veco Puppet. Ja tiek izmantotas vides, tās parasti tiek glabātas/etc/puppet/environments
, saknes direktorijs būs vides direktorijs. Ja vides netiek izmantotas, saknes direktorijs būs bāzes direktorijs. - Sākot ar ceturto versiju (“jaunā lelle”), vides izmantošana kļuva obligāta, un bāzes direktorijs tika pārvietots uz
/etc/puppetlabs/code
. Attiecīgi vides tiek glabātas/etc/puppetlabs/code/environments
, saknes direktorijs ir vides direktorijs.
Saknes direktorijā ir jābūt apakšdirektorijam manifests
, kurā ir viens vai vairāki manifesti, kas apraksta mezglus. Turklāt ir jābūt apakšdirektorijam modules
, kurā ir moduļi. Es jums pastāstīšu, kādi moduļi ir nedaudz vēlāk. Turklāt vecajam Puppet var būt arī apakšdirektorijs files
, kurā ir dažādi faili, kurus kopējam uz mezgliem. Jaunajā Puppet visi faili ir ievietoti moduļos.
Manifesta failiem ir paplašinājums .pp
.
Pāris kaujas piemēri
Mezgla apraksts un tajā esošais resurss
Uz mezgla server1.testdomain
ir jāizveido fails /etc/issue
ar saturu Debian GNU/Linux n l
. Failam ir jābūt lietotājam un grupai root
, piekļuves tiesībām jābūt 644
.
Mēs rakstām manifestu:
node 'server1.testdomain' { # блок конфигурации, относящийся к ноде server1.testdomain
file { '/etc/issue': # описываем файл /etc/issue
ensure => present, # этот файл должен существовать
content => 'Debian GNU/Linux n l', # у него должно быть такое содержимое
owner => root, # пользователь-владелец
group => root, # группа-владелец
mode => '0644', # права на файл. Они заданы в виде строки (в кавычках), потому что иначе число с 0 в начале будет воспринято как записанное в восьмеричной системе, и всё пойдёт не так, как задумано
}
}
Attiecības starp resursiem mezglā
Uz mezgla server2.testdomain
nginx ir jādarbojas, strādājot ar iepriekš sagatavotu konfigurāciju.
Sadalīsim problēmu:
- Ir nepieciešams instalēt pakotni
nginx
. - Konfigurācijas faili ir jāpārkopē no servera.
- Pakalpojumam ir jādarbojas
nginx
. - Ja konfigurācija tiek atjaunināta, pakalpojums ir jārestartē.
Mēs rakstām manifestu:
node 'server2.testdomain' { # блок конфигурации, относящийся к ноде server2.testdomain
package { 'nginx': # описываем пакет nginx
ensure => installed, # он должен быть установлен
}
# Прямая стрелка (->) говорит о том, что ресурс ниже должен
# создаваться после ресурса, описанного выше.
# Такие зависимости транзитивны.
-> file { '/etc/nginx': # описываем файл /etc/nginx
ensure => directory, # это должна быть директория
source => 'puppet:///modules/example/nginx-conf', # её содержимое нужно брать с паппет-сервера по указанному адресу
recurse => true, # копировать файлы рекурсивно
purge => true, # нужно удалять лишние файлы (те, которых нет в источнике)
force => true, # удалять лишние директории
}
# Волнистая стрелка (~>) говорит о том, что ресурс ниже должен
# подписаться на изменения ресурса, описанного выше.
# Волнистая стрелка включает в себя прямую (->).
~> service { 'nginx': # описываем сервис nginx
ensure => running, # он должен быть запущен
enable => true, # его нужно запускать автоматически при старте системы
}
# Когда ресурс типа service получает уведомление,
# соответствующий сервис перезапускается.
}
Lai tas darbotos, leļļu serverī ir nepieciešama aptuveni šāda faila atrašanās vieta:
/etc/puppetlabs/code/environments/production/ # (это для нового Паппета, для старого корневой директорией будет /etc/puppet)
├── manifests/
│ └── site.pp
└── modules/
└── example/
└── files/
└── nginx-conf/
├── nginx.conf
├── mime.types
└── conf.d/
└── some.conf
Resursu veidi
Pilns atbalstīto resursu veidu saraksts ir atrodams šeit
fails
Pārvalda failus, direktorijus, simboliskās saites, to saturu un piekļuves tiesības.
opcijas:
- resursa nosaukums — ceļš uz failu (pēc izvēles)
- taka - ceļš uz failu (ja tas nav norādīts nosaukumā)
- nodrošināt - faila tips:
absent
- izdzēst failupresent
— jābūt jebkura veida failam (ja faila nav, tiks izveidots parasts fails)file
- parastais failsdirectory
- direktorijslink
- simboliskā saite
- saturs — faila saturs (piemērots tikai parastajiem failiem, nevar izmantot kopā ar avots vai mērķis)
- avots — saite uz ceļu, no kura vēlaties kopēt faila saturu (nevar izmantot kopā ar saturs vai mērķis). Var norādīt kā URI ar shēmu
puppet:
(tad tiks izmantoti faili no leļļu servera), un ar shēmuhttp:
(Es ceru, ka ir skaidrs, kas notiks šajā gadījumā), un pat ar diagrammufile:
vai kā absolūts ceļš bez shēmas (tad tiks izmantots fails no mezgla vietējā FS) - mērķis — kur jānorāda simboliskā saite (nevar izmantot kopā ar saturs vai avots)
- īpašnieks — lietotājs, kuram vajadzētu piederēt failam
- grupa — grupa, kurai failam vajadzētu piederēt
- mode - faila atļaujas (kā virkne)
- atkārtot - nodrošina rekursīvu direktoriju apstrādi
- caurejas līdzeklis - ļauj dzēst failus, kas nav aprakstīti sadaļā Puppet
- piespiest - ļauj dzēst direktorijus, kas nav aprakstīti Puppet
pakete
Instalē un noņem pakotnes. Spēj apstrādāt paziņojumus - pārinstalē pakotni, ja parametrs ir norādīts reinstall_on_refresh.
opcijas:
- resursa nosaukums — pakotnes nosaukums (pēc izvēles)
- nosaukums — pakotnes nosaukums (ja nosaukumā nav norādīts)
- sniedzējs — izmantot pakotņu pārvaldnieku
- nodrošināt — vēlamais iepakojuma stāvoklis:
present
,installed
- jebkura instalēta versijalatest
- instalēta jaunākā versijaabsent
- dzēsts (apt-get remove
)purged
— dzēsts kopā ar konfigurācijas failiem (apt-get purge
)held
- pakotnes versija ir bloķēta (apt-mark hold
)любая другая строка
— ir instalēta norādītā versija
- reinstall_on_refresh - ja
true
, tad pēc paziņojuma saņemšanas pakotne tiks atkārtoti instalēta. Noderīga uz avotu balstītiem izplatījumiem, kur, mainot būvēšanas parametrus, var būt nepieciešama pakotņu atjaunošana. Noklusējumsfalse
.
apkalpošana
Pārvalda pakalpojumus. Var apstrādāt paziņojumus - restartē pakalpojumu.
opcijas:
- resursa nosaukums — pārvaldāmais pakalpojums (pēc izvēles)
- nosaukums — pakalpojums, kas jāpārvalda (ja nav norādīts nosaukumā)
- nodrošināt — vēlamais pakalpojuma stāvoklis:
running
- palaistsstopped
- apstājās
- dot iespēju — kontrolē iespēju palaist pakalpojumu:
true
— ir iespējota automātiskā palaišana (systemctl enable
)mask
- maskēts (systemctl mask
)false
— automātiskā palaišana ir atspējota (systemctl disable
)
- restart - komanda restartēt pakalpojumu
- stāvoklis — komanda pakalpojuma statusa pārbaudei
- ir restartēt — norāda, vai pakalpojuma sākumskripts atbalsta restartēšanu. Ja
false
un parametrs ir norādīts restart — tiek izmantota šī parametra vērtība. Jafalse
un parametrs restart nav norādīts - pakalpojums tiek apturēts un sākts restartēt (bet systemd izmanto komandusystemctl restart
). - hasstatus — norāda, vai pakalpojuma sākumskripts atbalsta komandu
status
. Jafalse
, tad tiek izmantota parametra vērtība stāvoklis. Noklusējumstrue
.
exec
Palaiž ārējās komandas. Ja nenorādīsiet parametrus rada, tikai ja, ja vien vai atsvaidzinoši, komanda tiks izpildīta katru reizi, kad tiks palaists Puppet. Spēj apstrādāt paziņojumus - izpilda komandu.
opcijas:
- resursa nosaukums — izpildāmā komanda (pēc izvēles)
- komanda — izpildāmā komanda (ja tā nav norādīta nosaukumā)
- taka — ceļi, kuros meklēt izpildāmo failu
- tikai ja — ja šajā parametrā norādītā komanda ir pabeigta ar nulles atgriešanas kodu, tiks izpildīta galvenā komanda
- ja vien — ja šajā parametrā norādītā komanda ir pabeigta ar atgriešanas kodu, kas nav nulle, tiks izpildīta galvenā komanda
- rada — ja šajā parametrā norādītais fails neeksistē, tiks izpildīta galvenā komanda
- atsvaidzinoši - ja
true
, tad komanda tiks izpildīta tikai tad, kad šis izpildītājs saņems paziņojumu no citiem resursiem - cwd — direktorijs, no kura palaist komandu
- lietotājs — lietotājs, no kura palaist komandu
- sniedzējs - kā palaist komandu:
- positix — ir vienkārši izveidots bērnu process, noteikti norādiet taka
- apvalks - komanda tiek palaista čaulā
/bin/sh
, var nebūt norādīts taka, varat izmantot globbing, caurules un citas apvalka funkcijas. Parasti tiek noteikta automātiski, ja ir kādas īpašas rakstzīmes (|
,;
,&&
,||
utt.).
cron
Kontrolē cronjobs.
opcijas:
- resursa nosaukums - tikai sava veida identifikators
- nodrošināt — crownjob valsts:
present
- izveidot, ja neeksistēabsent
- dzēst, ja tāds ir
- komanda - kādu komandu palaist
- vide — kurā vidē palaist komandu (vides mainīgo un to vērtību saraksts, izmantojot
=
) - lietotājs — no kura lietotāja palaist komandu
- minūte, stunda, darbdiena, MĒNESĪ, mēneša diena — kad palaist kronu. Ja kāds no šiem atribūtiem nav norādīts, tā vērtība crontab būs
*
.
Programmā Puppet 6.0 cron it kā
Par resursiem kopumā
Prasības resursa unikalitātei
Visbiežāk sastopamā kļūda, ar kuru mēs sastopamies, ir Deklarācijas dublikāts. Šī kļūda rodas, ja direktorijā parādās divi vai vairāki viena veida resursi ar tādu pašu nosaukumu.
Tāpēc es rakstīšu vēlreiz: tā paša mezgla manifestos nedrīkst būt viena veida resursi ar tādu pašu nosaukumu!
Dažreiz ir jāinstalē pakotnes ar tādu pašu nosaukumu, bet ar dažādiem pakotņu pārvaldniekiem. Šajā gadījumā jums ir jāizmanto parametrs name
lai izvairītos no kļūdas:
package { 'ruby-mysql':
ensure => installed,
name => 'mysql',
provider => 'gem',
}
package { 'python-mysql':
ensure => installed,
name => 'mysql',
provider => 'pip',
}
Citiem resursu veidiem ir līdzīgas iespējas, lai palīdzētu izvairīties no dublēšanās − name
у apkalpošana, command
у exec, un tā tālāk.
Metaparametri
Katram resursa veidam ir daži īpaši parametri neatkarīgi no tā veida.
Pilns meta parametru saraksts
Īss saraksts:
- pieprasīt — šis parametrs norāda, no kuriem resursiem ir atkarīgs šis resurss.
- pirms - Šis parametrs norāda, kuri resursi ir atkarīgi no šī resursa.
- abonēt — šis parametrs norāda, no kuriem resursiem šis resurss saņem paziņojumus.
- paziņot — Šis parametrs norāda, kuri resursi saņem paziņojumus no šī resursa.
Visi uzskaitītie metaparametri pieņem vai nu vienu resursa saiti, vai saišu masīvu kvadrātiekavās.
Saites uz resursiem
Resursa saite ir vienkārši resursa pieminēšana. Tos galvenokārt izmanto, lai norādītu uz atkarībām. Atsauce uz neesošu resursu izraisīs kompilācijas kļūdu.
Saites sintakse ir šāda: resursa tips ar lielo burtu (ja tipa nosaukumā ir dubultās kolas, tad katra nosaukuma daļa starp koliem ir ar lielo burtu), tad resursa nosaukums kvadrātiekavās (nosaukuma reģistrs nemainās!). Nedrīkst būt atstarpēm, kvadrātiekavas tiek rakstītas uzreiz aiz tipa nosaukuma.
Piemērs:
file { '/file1': ensure => present }
file { '/file2':
ensure => directory,
before => File['/file1'],
}
file { '/file3': ensure => absent }
File['/file1'] -> File['/file3']
Atkarības un paziņojumi
Kā minēts iepriekš, vienkāršas atkarības starp resursiem ir pārejošas. Starp citu, esiet piesardzīgs, pievienojot atkarības - varat izveidot cikliskas atkarības, kas radīs kompilācijas kļūdu.
Atšķirībā no atkarībām, paziņojumi nav pārejoši. Uz paziņojumiem attiecas šādi noteikumi:
- Ja resurss saņem paziņojumu, tas tiek atjaunināts. Atjaunināšanas darbības ir atkarīgas no resursa veida − exec izpilda komandu, apkalpošana restartē pakalpojumu, pakete pārinstalē pakotni. Ja resursam nav definēta atjaunināšanas darbība, nekas nenotiek.
- Vienas Puppet darbības laikā resurss tiek atjaunināts ne vairāk kā vienu reizi. Tas ir iespējams, jo paziņojumos ir iekļautas atkarības, un atkarības diagrammā nav iekļauti cikli.
- Ja Lelle maina resursa stāvokli, resurss nosūta paziņojumus visiem tā abonētajiem resursiem.
- Ja resurss tiek atjaunināts, tas nosūta paziņojumus visiem tā abonētajiem resursiem.
Nenoteiktu parametru apstrāde
Parasti, ja kādam resursa parametram nav noklusējuma vērtības un šis parametrs nav norādīts manifestā, Puppet nemainīs šo rekvizītu attiecīgajam resursam mezglā. Piemēram, ja šāda veida resurss fails parametrs nav norādīts owner
, tad Puppet nemainīs atbilstošā faila īpašnieku.
Ievads klasēs, mainīgajos un definīcijās
Pieņemsim, ka mums ir vairāki mezgli, kuriem ir vienāda konfigurācijas daļa, taču ir arī atšķirības - pretējā gadījumā mēs to visu varētu aprakstīt vienā blokā node {}
. Protams, var vienkārši nokopēt identiskas konfigurācijas daļas, taču kopumā tas ir slikts risinājums – konfigurācija aug, un ja mainīsi konfigurācijas vispārīgo daļu, tad daudzviet nāksies rediģēt vienu un to pašu. Tajā pašā laikā ir viegli kļūdīties, un kopumā princips DRY (neatkārtojies) tika izgudrots ne velti.
Lai atrisinātu šo problēmu, ir tāds dizains kā klase.
Nodarbības
Vispirms ir jāapraksta klase. Pats apraksts nekur nepievieno nekādus resursus. Klase ir aprakstīta manifestos:
# Описание класса начинается с ключевого слова class и его названия.
# Дальше идёт тело класса в фигурных скобках.
class example_class {
...
}
Pēc tam klasi var izmantot:
# первый вариант использования — в стиле ресурса с типом class
class { 'example_class': }
# второй вариант использования — с помощью функции include
include example_class
# про отличие этих двух вариантов будет рассказано дальше
Piemērs no iepriekšējā uzdevuma - pārvietosim nginx instalēšanu un konfigurēšanu uz klasi:
class nginx_example {
package { 'nginx':
ensure => installed,
}
-> file { '/etc/nginx':
ensure => directory,
source => 'puppet:///modules/example/nginx-conf',
recure => true,
purge => true,
force => true,
}
~> service { 'nginx':
ensure => running,
enable => true,
}
}
node 'server2.testdomain' {
include nginx_example
}
Mainīgie
Klase no iepriekšējā piemēra vispār nav elastīga, jo tā vienmēr nodrošina to pašu nginx konfigurāciju. Izveidosim ceļu uz konfigurācijas mainīgo, tad šo klasi var izmantot, lai instalētu nginx ar jebkuru konfigurāciju.
To var izdarīt
Uzmanību: mainīgie lielumi programmā Puppet ir nemainīgi!
Turklāt mainīgajam var piekļūt tikai pēc tam, kad tas ir deklarēts, pretējā gadījumā mainīgā vērtība būs undef
.
Piemērs darbam ar mainīgajiem:
# создание переменных
$variable = 'value'
$var2 = 1
$var3 = true
$var4 = undef
# использование переменных
$var5 = $var6
file { '/tmp/text': content => $variable }
# интерполяция переменных — раскрытие значения переменных в строках. Работает только в двойных кавычках!
$var6 = "Variable with name variable has value ${variable}"
Lellei ir nosaukumvietas, un attiecīgi mainīgajiem ir redzamības zona: mainīgo ar tādu pašu nosaukumu var definēt dažādās nosaukumvietās. Atrisinot mainīgā lieluma vērtību, mainīgais tiek meklēts pašreizējā nosaukumvietā, pēc tam aptverošajā nosaukumvietā un tā tālāk.
Vārdtelpas piemēri:
- globālais - mainīgie ārpus klases vai mezgla apraksta nonāk tur;
- mezgla nosaukumvieta mezgla aprakstā;
- klases nosaukumvieta klases aprakstā.
Lai izvairītos no neskaidrībām, piekļūstot mainīgajam, mainīgā nosaukumā varat norādīt nosaukumvietu:
# переменная без пространства имён
$var
# переменная в глобальном пространстве имён
$::var
# переменная в пространстве имён класса
$classname::var
$::classname::var
Vienosimies, ka ceļš uz nginx konfigurāciju atrodas mainīgajā $nginx_conf_source
. Tad klase izskatīsies šādi:
class nginx_example {
package { 'nginx':
ensure => installed,
}
-> file { '/etc/nginx':
ensure => directory,
source => $nginx_conf_source, # здесь используем переменную вместо фиксированной строки
recure => true,
purge => true,
force => true,
}
~> service { 'nginx':
ensure => running,
enable => true,
}
}
node 'server2.testdomain' {
$nginx_conf_source = 'puppet:///modules/example/nginx-conf'
include nginx_example
}
Taču dotais piemērs ir slikts, jo ir zināmas “slepenās zināšanas”, ka kaut kur klasē tiek lietots mainīgais ar tādu un tādu nosaukumu. Daudz pareizāk ir šīs zināšanas padarīt vispārīgas - klasēm var būt parametri.
Klases parametri ir mainīgie klases nosaukumvietā, tie ir norādīti klases galvenē un var tikt izmantoti kā parastie mainīgie klases pamattekstā. Parametru vērtības tiek norādītas, izmantojot klasi manifestā.
Parametram var iestatīt noklusējuma vērtību. Ja parametram nav noklusējuma vērtības un vērtība netiek iestatīta lietošanas laikā, tas izraisīs kompilācijas kļūdu.
Parametizēsim klasi no iepriekš redzamā piemēra un pievienosim divus parametrus: pirmais obligātais ir ceļš uz konfigurāciju, bet otrais, neobligāts, ir pakotnes nosaukums ar nginx (piemēram, Debianā ir pakotnes nginx
, nginx-light
, nginx-full
).
# переменные описываются сразу после имени класса в круглых скобках
class nginx_example (
$conf_source,
$package_name = 'nginx-light', # параметр со значением по умолчанию
) {
package { $package_name:
ensure => installed,
}
-> file { '/etc/nginx':
ensure => directory,
source => $conf_source,
recurse => true,
purge => true,
force => true,
}
~> service { 'nginx':
ensure => running,
enable => true,
}
}
node 'server2.testdomain' {
# если мы хотим задать параметры класса, функция include не подойдёт* — нужно использовать resource-style declaration
# *на самом деле подойдёт, но про это расскажу в следующей серии. Ключевое слово "Hiera".
class { 'nginx_example':
conf_source => 'puppet:///modules/example/nginx-conf', # задаём параметры класса точно так же, как параметры для других ресурсов
}
}
Programmā Puppet mainīgie tiek drukāti. Ēst
Tips tiek rakstīts tieši pirms parametra nosaukuma:
class example (
String $param1,
Integer $param2,
Array $param3,
Hash $param4,
Hash[String, String] $param5,
) {
...
}
Klases: ietver klases nosaukumu pret klasi {'classname':}
Katra klase ir sava veida resurss klase. Tāpat kā jebkura cita veida resursiem, vienā mezglā nevar būt divi vienas klases gadījumi.
Ja mēģināt pievienot klasi vienam mezglam divas reizes, izmantojot class { 'classname':}
(nav atšķirības, ar dažādiem vai identiskiem parametriem), būs kompilācijas kļūda. Bet, ja izmantojat klasi resursu stilā, varat nekavējoties skaidri iestatīt visus tās parametrus manifestā.
Tomēr, ja lietojat include
, tad klasi var pievienot tik reižu, cik vēlaties. Fakts ir tāds include
ir idempotenta funkcija, kas pārbauda, vai direktorijam ir pievienota klase. Ja klase neatrodas direktorijā, tā to pievieno, un, ja tā jau pastāv, tā neko nedara. Bet lietošanas gadījumā include
Klases deklarēšanas laikā nevar iestatīt klases parametrus – visi nepieciešamie parametri jāiestata ārējā datu avotā – Hiera vai ENC. Par tiem mēs runāsim nākamajā rakstā.
Definē
Kā tika teikts iepriekšējā blokā, viena un tā pati klase mezglā nevar atrasties vairāk kā vienu reizi. Tomēr dažos gadījumos jums ir jāspēj izmantot vienu un to pašu koda bloku ar dažādiem parametriem tajā pašā mezglā. Citiem vārdiem sakot, ir nepieciešams savs resursa veids.
Piemēram, lai instalētu PHP moduli, programmā Avito mēs rīkojamies šādi:
- Instalējiet pakotni ar šo moduli.
- Izveidosim šī moduļa konfigurācijas failu.
- Mēs izveidojam saiti uz php-fpm konfigurāciju.
- Mēs izveidojam saiti uz php cli konfigurāciju.
Šādos gadījumos dizains, piemēram, $title
, kur tiek norādīts resursa nosaukums, kad tas tiek deklarēts. Tāpat kā klasēm, vispirms ir jāapraksta definīcija, pēc kuras to var izmantot.
Vienkāršots piemērs ar PHP moduli:
define php74::module (
$php_module_name = $title,
$php_package_name = "php7.4-${title}",
$version = 'installed',
$priority = '20',
$data = "extension=${title}.son",
$php_module_path = '/etc/php/7.4/mods-available',
) {
package { $php_package_name:
ensure => $version,
install_options => ['-o', 'DPkg::NoTriggers=true'], # триггеры дебиановских php-пакетов сами создают симлинки и перезапускают сервис php-fpm - нам это не нужно, так как и симлинками, и сервисом мы управляем с помощью Puppet
}
-> file { "${php_module_path}/${php_module_name}.ini":
ensure => $ensure,
content => $data,
}
file { "/etc/php/7.4/cli/conf.d/${priority}-${php_module_name}.ini":
ensure => link,
target => "${php_module_path}/${php_module_name}.ini",
}
file { "/etc/php/7.4/fpm/conf.d/${priority}-${php_module_name}.ini":
ensure => link,
target => "${php_module_path}/${php_module_name}.ini",
}
}
node server3.testdomain {
php74::module { 'sqlite3': }
php74::module { 'amqp': php_package_name => 'php-amqp' }
php74::module { 'msgpack': priority => '10' }
}
Vienkāršākais veids, kā atklāt deklarācijas dublikāta kļūdu, ir Definēt. Tas notiek, ja definīcijai ir resurss ar nemainīgu nosaukumu un kādā mezglā ir divi vai vairāki šīs definīcijas gadījumi.
No tā ir viegli pasargāt sevi: visiem definīcijā iekļautajiem resursiem ir jābūt nosaukumiem atkarībā no $title
. Alternatīva ir idempotena resursu pievienošana; vienkāršākajā gadījumā pietiek ar visiem definīcijas gadījumiem kopīgos resursus pārvietot atsevišķā klasē un iekļaut šo klasi definīcijā - funkcijā include
idempotents.
Ir arī citi veidi, kā panākt idempotenci, pievienojot resursus, proti, izmantojot funkcijas defined
и ensure_resources
, bet par to pastāstīšu nākamajā sērijā.
Atkarības un paziņojumi par klasēm un definīcijām
Klases un definīcijas pievieno šādus noteikumus atkarību un paziņojumu apstrādei:
- atkarība no klases/definē pievieno atkarības no visiem klases/definētajiem resursiem;
- klases/definēt atkarība pievieno atkarības visiem klases/definētajiem resursiem;
- class/define paziņojums informē visus klases/definēt resursus;
- class/define abonements abonē visus klases/define resursus.
Nosacīti apgalvojumi un atlasītāji
if
Šeit viss ir vienkārši:
if ВЫРАЖЕНИЕ1 {
...
} elsif ВЫРАЖЕНИЕ2 {
...
} else {
...
}
ja vien
ja vien if ir apgrieztā veidā: koda bloks tiks izpildīts, ja izteiksme ir nepatiesa.
unless ВЫРАЖЕНИЕ {
...
}
lieta
Arī šeit nav nekā sarežģīta. Kā vērtības varat izmantot regulāras vērtības (virknes, skaitļus utt.), regulāras izteiksmes un datu tipus.
case ВЫРАЖЕНИЕ {
ЗНАЧЕНИЕ1: { ... }
ЗНАЧЕНИЕ2, ЗНАЧЕНИЕ3: { ... }
default: { ... }
}
Selektori
Atlasītājs ir valodas konstrukcija, kas līdzīga case
, bet tā vietā, lai izpildītu koda bloku, tas atgriež vērtību.
$var = $othervar ? { 'val1' => 1, 'val2' => 2, default => 3 }
Moduļi
Ja konfigurācija ir maza, to var viegli saglabāt vienā manifestā. Bet jo vairāk konfigurāciju mēs aprakstām, jo vairāk klašu un mezglu ir manifestā, tas palielinās un kļūst neērti strādāt.
Turklāt ir koda atkārtotas izmantošanas problēma – kad viss kods ir vienā manifestā, ir grūti šo kodu koplietot ar citiem. Lai atrisinātu šīs divas problēmas, programmai Puppet ir entītija, ko sauc par moduļiem.
Moduļi - tās ir klašu, definīciju un citu Leļļu entītiju kopas, kas ievietotas atsevišķā direktorijā. Citiem vārdiem sakot, modulis ir neatkarīga leļļu loģikas daļa. Piemēram, var būt modulis darbam ar nginx, un tajā būs tas, kas un tikai tas, kas nepieciešams darbam ar nginx, vai arī var būt modulis darbam ar PHP utt.
Moduļiem tiek veiktas versijas, un tiek atbalstītas arī moduļu atkarības viens no otra. Ir atvērta moduļu krātuve -
Leļļu serverī moduļi atrodas saknes direktorija moduļu apakšdirektorijā. Katra moduļa iekšpusē ir standarta direktoriju shēma - manifesti, faili, veidnes, lib utt.
Failu struktūra modulī
Moduļa saknē var būt šādi direktoriji ar aprakstošiem nosaukumiem:
manifests
- tajā ir manifestifiles
- tajā ir failitemplates
- tajā ir veidneslib
— tajā ir Rubīna kods
Šis nav pilnīgs direktoriju un failu saraksts, taču šim rakstam pagaidām pietiek.
Moduļa resursu un failu nosaukumi
Moduļa resursus (klases, definīcijas) nevar nosaukt tā, kā vēlaties. Turklāt pastāv tieša atbilstība starp resursa nosaukumu un faila nosaukumu, kurā Puppet meklēs šī resursa aprakstu. Ja pārkāpjat nosaukšanas noteikumus, Puppet vienkārši neatradīs resursa aprakstu, un jūs saņemsit kompilācijas kļūdu.
Noteikumi ir vienkārši:
- Visiem resursiem modulī ir jāatrodas moduļa nosaukumvietā. Ja modulis tiek izsaukts
foo
, tad jānosauc visi tajā esošie resursifoo::<anything>
, vai vienkāršifoo
. - Resursam ar moduļa nosaukumu jābūt failā
init.pp
. - Citiem resursiem failu nosaukumu shēma ir šāda:
- prefikss ar moduļa nosaukumu tiek atmests
- visi dubultie koli, ja tādi ir, tiek aizstāti ar slīpsvītām
- paplašinājums ir pievienots
.pp
Es parādīšu ar piemēru. Pieņemsim, ka es rakstu moduli nginx
. Tajā ir šādi resursi:
- klase
nginx
aprakstīts manifestāinit.pp
; - klase
nginx::service
aprakstīts manifestāservice.pp
; - definēt
nginx::server
aprakstīts manifestāserver.pp
; - definēt
nginx::server::location
aprakstīts manifestāserver/location.pp
.
veidnes
Protams, jūs pats zināt, kas ir veidnes; es tās šeit sīkāk neaprakstīšu. Bet es to atstāšu katram gadījumam
Veidņu izmantošana: veidnes nozīmi var paplašināt, izmantojot funkciju template
, kas tiek nodots ceļš uz veidni. Šāda veida resursiem fails izmanto kopā ar parametru content
. Piemēram, šādi:
file { '/tmp/example': content => template('modulename/templatename.erb')
Skatīt ceļu <modulename>/<filename>
nozīmē failu <rootdir>/modules/<modulename>/templates/<filename>
.
Turklāt ir funkcija inline_template
— tas saņem veidnes tekstu kā ievadi, nevis faila nosaukumu.
Veidnēs varat izmantot visus Leļļu mainīgos pašreizējā tvērumā.
Puppet atbalsta veidnes ERB un EPP formātā:
Īsi par ERB
Kontroles struktūras:
<%= ВЫРАЖЕНИЕ %>
— ievieto izteiksmes vērtību<% ВЫРАЖЕНИЕ %>
— aprēķināt izteiksmes vērtību (neievietojot to). Šeit parasti tiek iekļauti nosacījuma paziņojumi (ja) un cilpas (katrs).<%# КОММЕНТАРИЙ %>
Izteiksmes ERB ir rakstītas rubīnā (ERB faktiski ir iegultais rubīns).
Lai piekļūtu mainīgajiem no manifesta, ir jāpievieno @
uz mainīgā nosaukumu. Lai noņemtu rindiņas pārtraukumu, kas parādās pēc vadības konstrukcijas, ir jāizmanto beigu atzīme -%>
.
Veidnes izmantošanas piemērs
Pieņemsim, ka es rakstu moduli, lai kontrolētu ZooKeeper. Par konfigurācijas izveidi atbildīgā klase izskatās apmēram šādi:
class zookeeper::configure (
Array[String] $nodes,
Integer $port_client,
Integer $port_quorum,
Integer $port_leader,
Hash[String, Any] $properties,
String $datadir,
) {
file { '/etc/zookeeper/conf/zoo.cfg':
ensure => present,
content => template('zookeeper/zoo.cfg.erb'),
}
}
Un atbilstošā veidne zoo.cfg.erb
- Tātad:
<% if @nodes.length > 0 -%>
<% @nodes.each do |node, id| -%>
server.<%= id %>=<%= node %>:<%= @port_leader %>:<%= @port_quorum %>;<%= @port_client %>
<% end -%>
<% end -%>
dataDir=<%= @datadir %>
<% @properties.each do |k, v| -%>
<%= k %>=<%= v %>
<% end -%>
Fakti un iebūvētie mainīgie
Bieži vien konkrētā konfigurācijas daļa ir atkarīga no tā, kas pašlaik notiek mezglā. Piemēram, atkarībā no Debian laidiena ir jāinstalē viena vai cita pakotnes versija. To visu var pārraudzīt manuāli, pārrakstot manifestus, ja mezgli mainās. Bet tā nav nopietna pieeja; automatizācija ir daudz labāka.
Lai iegūtu informāciju par mezgliem, Puppet ir mehānisms, ko sauc par faktiem. Dati - šī ir informācija par mezglu, kas ir pieejama manifestos parastu mainīgo veidā globālajā nosaukumu telpā. Piemēram, resursdatora nosaukums, operētājsistēmas versija, procesora arhitektūra, lietotāju saraksts, tīkla saskarņu saraksts un to adreses un daudz kas cits. Fakti ir pieejami manifestos un veidnēs kā regulāri mainīgie.
Piemērs darbam ar faktiem:
notify { "Running OS ${facts['os']['name']} version ${facts['os']['release']['full']}": }
# ресурс типа notify просто выводит сообщение в лог
Formāli runājot, faktam ir nosaukums (virkne) un vērtība (ir pieejami dažādi veidi: virknes, masīvi, vārdnīcas). Ēst
Darbības laikā leļļu aģents vispirms kopē visus pieejamos faktu apkopotājus no pappetservera uz mezglu, pēc tam tos palaiž un nosūta savāktos faktus uz serveri; Pēc tam serveris sāk apkopot katalogu.
Fakti izpildāmo failu veidā
Šādi fakti tiek ievietoti direktorijā moduļos facts.d
. Protams, failiem jābūt izpildāmiem. Palaižot, tiem ir jāizvada informācija standarta izvadē YAML vai atslēga=vērtība formātā.
Neaizmirstiet, ka fakti attiecas uz visiem mezgliem, kurus kontrolē poppet serveris, kurā ir izvietots jūsu modulis. Tāpēc skriptā pārbaudiet, vai sistēmā ir visas programmas un faili, kas nepieciešami jūsu fakta darbībai.
#!/bin/sh
echo "testfact=success"
#!/bin/sh
echo '{"testyamlfact":"success"}'
Rubīna fakti
Šādi fakti tiek ievietoti direktorijā moduļos lib/facter
.
# всё начинается с вызова функции Facter.add с именем факта и блоком кода
Facter.add('ladvd') do
# в блоках confine описываются условия применимости факта — код внутри блока должен вернуть true, иначе значение факта не вычисляется и не возвращается
confine do
Facter::Core::Execution.which('ladvdc') # проверим, что в PATH есть такой исполняемый файл
end
confine do
File.socket?('/var/run/ladvd.sock') # проверим, что есть такой UNIX-domain socket
end
# в блоке setcode происходит собственно вычисление значения факта
setcode do
hash = {}
if (out = Facter::Core::Execution.execute('ladvdc -b'))
out.split.each do |l|
line = l.split('=')
next if line.length != 2
name, value = line
hash[name.strip.downcase.tr(' ', '_')] = value.strip.chomp(''').reverse.chomp(''').reverse
end
end
hash # значение последнего выражения в блоке setcode является значением факта
end
end
Teksta fakti
Šādi fakti tiek ievietoti direktorija mezglos /etc/facter/facts.d
vecajā Leļļu vai /etc/puppetlabs/facts.d
jaunajā Leļļu.
examplefact=examplevalue
---
examplefact2: examplevalue2
anotherfact: anothervalue
Nokļūšana pie faktiem
Ir divi veidi, kā pievērsties faktiem:
- caur vārdnīcu
$facts
:$facts['fqdn']
; - izmantojot fakta nosaukumu kā mainīgā nosaukumu:
$fqdn
.
Vislabāk ir izmantot vārdnīcu $facts
, vai vēl labāk, norādiet globālo nosaukumvietu ($::facts
).
Iebūvētie mainīgie
Papildus faktiem ir arī
- uzticami fakti — mainīgie, kas tiek ņemti no klienta sertifikāta (tā kā sertifikāts parasti tiek izsniegts poppet serverī, aģents nevar vienkārši paņemt un mainīt savu sertifikātu, tāpēc mainīgie ir “uzticami”): sertifikāta nosaukums, sertifikāta nosaukums. resursdators un domēns, sertifikāta paplašinājumi.
- servera fakti — mainīgie, kas saistīti ar informāciju par serveri — versija, nosaukums, servera IP adrese, vide.
- aģentu fakti — mainīgie, ko tieši pievieno leļļu aģents, nevis faktors — sertifikāta nosaukums, aģenta versija, marionetes versija.
- galvenais mainīgie - Pappetmaster mainīgie (sic!). Tas ir apmēram tāds pats kā iekšā servera fakti, kā arī ir pieejamas konfigurācijas parametru vērtības.
- kompilatoru mainīgie — kompilatora mainīgie, kas atšķiras katrā tvērumā: pašreizējā moduļa nosaukums un tā moduļa nosaukums, kurā tika piekļūts pašreizējam objektam. Tos var izmantot, piemēram, lai pārbaudītu, vai jūsu privātās nodarbības netiek izmantotas tieši no citiem moduļiem.
1. papildinājums: kā to visu palaist un atkļūdot?
Rakstā bija daudz leļļu koda piemēru, taču mums vispār netika norādīts, kā palaist šo kodu. Nu es sevi laboju.
Lai palaistu Puppet, pietiek ar aģentu, taču vairumā gadījumu jums būs nepieciešams arī serveris.
Aģents
Vismaz kopš versijas XNUMX, marionet-agent pakotnes no
Vienkāršākajā gadījumā, lai izmantotu leļļu konfigurāciju, pietiek ar aģenta palaišanu bezservera režīmā: ar nosacījumu, ka leļļu kods ir kopēts mezglā, palaidiet puppet apply <путь к манифесту>
:
atikhonov@atikhonov ~/puppet-test $ cat helloworld.pp
node default {
notify { 'Hello world!': }
}
atikhonov@atikhonov ~/puppet-test $ puppet apply helloworld.pp
Notice: Compiled catalog for atikhonov.localdomain in environment production in 0.01 seconds
Notice: Hello world!
Notice: /Stage[main]/Main/Node[default]/Notify[Hello world!]/message: defined 'message' as 'Hello world!'
Notice: Applied catalog in 0.01 seconds
Protams, labāk ir iestatīt serveri un palaist aģentus mezglos dēmona režīmā - tad reizi pusstundā viņi lietos no servera lejupielādēto konfigurāciju.
Jūs varat atdarināt darba push modeli - dodieties uz jūs interesējošo mezglu un sāciet sudo puppet agent -t
. Atslēga -t
(--test
) faktiski ietver vairākas opcijas, kuras var iespējot atsevišķi. Šīs opcijas ir šādas:
- nedarbiniet dēmonu režīmā (pēc noklusējuma aģents startē dēmona režīmā);
- izslēgt pēc kataloga lietošanas (pēc noklusējuma aģents turpinās strādāt un lietot konfigurāciju reizi pusstundā);
- uzrakstīt detalizētu darba žurnālu;
- parādīt izmaiņas failos.
Aģentam ir darbības režīms bez izmaiņām - to var izmantot, kad neesat pārliecināts, ka esat uzrakstījis pareizo konfigurāciju un vēlaties pārbaudīt, ko tieši aģents darbības laikā mainīs. Šo režīmu iespējo parametrs --noop
komandrindā: sudo puppet agent -t --noop
.
Turklāt jūs varat iespējot darba atkļūdošanas žurnālu - tajā marionete raksta par visām darbībām, ko tā veic: par resursu, ko tā pašlaik apstrādā, par šī resursa parametriem, par to, kādas programmas tas palaiž. Protams, tas ir parametrs --debug
.
Serveris
Šajā rakstā es neapskatīšu pilnu pappetservera iestatīšanu un koda izvietošanu tajā; teikšu tikai to, ka ir pieejama pilnībā funkcionējoša servera versija, kurai nav nepieciešama papildu konfigurācija, lai strādātu ar nelielu skaitu mezgli (teiksim, līdz simtam). Lielākam mezglu skaitam būs nepieciešama regulēšana - pēc noklusējuma leļļu serveris palaiž ne vairāk kā četrus darbiniekus, lai nodrošinātu lielāku veiktspēju, jums jāpalielina to skaits un neaizmirstiet palielināt atmiņas ierobežojumus, pretējā gadījumā serveris lielāko daļu laika savāks atkritumus.
Koda izvietošana — ja jums tas ir nepieciešams ātri un vienkārši, skatieties (r10k)[
2. papildinājums: Kodēšanas vadlīnijas
- Ievietojiet visu loģiku klasēs un definīcijās.
- Klases un definīcijas saglabājiet moduļos, nevis mezglus aprakstošos manifestos.
- Izmantojiet faktus.
- Neveidojiet if, pamatojoties uz saimniekdatora nosaukumiem.
- Jūtieties brīvi pievienot parametrus klasēm un definīcijām — tas ir labāk nekā klases/definēšanas pamattekstā paslēpta netieša loģika.
Kāpēc es ieteiktu to darīt, es paskaidrošu nākamajā rakstā.
Secinājums
Beigsim ar ievadu. Nākamajā rakstā pastāstīšu par Hiera, ENC un PuppetDB.
Aptaujā var piedalīties tikai reģistrēti lietotāji.
Patiesībā materiālu ir daudz vairāk - varu rakstīt rakstus par šādām tēmām, balsot par to, par ko būtu interesanti lasīt:
- 59,1%Uzlabotas leļļu konstrukcijas — daži nākamā līmeņa sūdi: cilpas, kartēšana un citas lambda izteiksmes, resursu savācēji, eksportētie resursi un savstarpējā saziņa, izmantojot Puppet, tagi, nodrošinātāji, abstrakti datu tipi.13
- 31,8%“I’m my mother’s admin” jeb kā mēs Avito sadraudzējāmies ar vairākiem dažādu versiju poppet serveriem, un principā daļa par poppet servera administrēšanu.7
- 81,8%Kā mēs rakstām leļļu kodu: instrumenti, dokumentācija, testēšana, CI/CD.18
Nobalsoja 22 lietotāji. 9 lietotāji atturējās.
Avots: www.habr.com