Puppet on konfiguratsioonihaldussüsteem. Seda kasutatakse hostide viimiseks soovitud olekusse ja selle oleku säilitamiseks.
Olen Puppetiga töötanud juba üle viie aasta. See tekst on sisuliselt tõlgitud ja ümber järjestatud kogumik ametliku dokumentatsiooni põhipunktidest, mis võimaldab algajatel Nuku olemusest kiiresti aru saada.
Põhiteave
Nuku operatsioonisüsteem on klient-server, kuigi see toetab ka piiratud funktsionaalsusega serverita toimimist.
Kasutatakse tõmbemudelit: vaikimisi võtavad kliendid iga poole tunni järel serveriga ühendust konfiguratsiooni saamiseks ja selle rakendamiseks. Kui olete Ansiblega töötanud, siis nad kasutavad teistsugust tõukemudelit: administraator algatab konfiguratsiooni rakendamise, kliendid ise ei rakenda midagi.
Võrguside ajal kasutatakse kahepoolset TLS-krüptimist: serveril ja kliendil on oma privaatvõtmed ja vastavad sertifikaadid. Tavaliselt väljastab server klientidele sertifikaate, kuid põhimõtteliselt on võimalik kasutada ka välist CA-d.
Sissejuhatus manifestidesse
Nukute terminoloogias nukuserverile ühendada sõlmed (sõlmed). Sõlmede konfiguratsioon on kirjutatud manifestides spetsiaalses programmeerimiskeeles - Puppet DSL.
Puppet DSL on deklaratiivne keel. See kirjeldab sõlme soovitud olekut üksikute ressursside deklaratsioonide kujul, näiteks:
- Fail on olemas ja sellel on konkreetne sisu.
- Pakett on installitud.
- Teenus on alanud.
Ressursid võivad olla omavahel seotud:
- On sõltuvusi, need mõjutavad ressursside kasutamise järjekorda.
Näiteks "esmalt installige pakett, seejärel redigeerige konfiguratsioonifaili ja seejärel käivitage teenus." - Teatised on olemas – kui ressurss on muutunud, saadab ta selle tellitud ressurssidele teated.
Näiteks kui konfiguratsioonifail muutub, saate teenuse automaatselt taaskäivitada.
Lisaks on Puppet DSL-il funktsioone ja muutujaid, samuti tingimuslauseid ja valijaid. Toetatud on ka erinevad mallimehhanismid – EPP ja ERB.
Nukk on kirjutatud rubiiniga, nii et paljud konstruktsioonid ja terminid on sealt võetud. Ruby võimaldab teil Puppeti laiendada - lisada keerukat loogikat, uut tüüpi ressursse, funktsioone.
Kui Puppet töötab, kompileeritakse serveri iga konkreetse sõlme manifestid kataloogi. Kataloog on ressursside ja nende seoste loend pärast funktsioonide, muutujate väärtuse arvutamist ja tingimuslausete laiendamist.
Süntaks ja koodistiil
Siin on ametliku dokumentatsiooni jaotised, mis aitavad teil süntaksit mõista, kui esitatud näidetest ei piisa:
Siin on näide selle kohta, kuidas manifest välja näeb:
# Комментарии пишутся, как и много где, после решётки.
#
# Описание конфигурации ноды начинается с ключевого слова node,
# за которым следует селектор ноды — хостнейм (с доменом или без)
# или регулярное выражение для хостнеймов, или ключевое слово default.
#
# После этого в фигурных скобках описывается собственно конфигурация ноды.
#
# Одна и та же нода может попасть под несколько селекторов. Про приоритет
# селекторов написано в статье про синтаксис описания нод.
node 'hostname', 'f.q.d.n', /regexp/ {
# Конфигурация по сути является перечислением ресурсов и их параметров.
#
# У каждого ресурса есть тип и название.
#
# Внимание: не может быть двух ресурсов одного типа с одинаковыми названиями!
#
# Описание ресурса начинается с его типа. Тип пишется в нижнем регистре.
# Про разные типы ресурсов написано ниже.
#
# После типа в фигурных скобках пишется название ресурса, потом двоеточие,
# дальше идёт опциональное перечисление параметров ресурса и их значений.
# Значения параметров указываются через т.н. hash rocket (=>).
resource { 'title':
param1 => value1,
param2 => value2,
param3 => value3,
}
}
Taande ja reavahetused ei ole manifesti kohustuslikud osad, kuid soovitatavad on olemas
- Kahe tühikuga taane, tabeldusmärke ei kasutata.
- Lokkis sulgusid eraldab tühik, kooloneid ei eralda tühikuga.
- Komad pärast iga parameetrit, sealhulgas viimast. Iga parameeter on eraldi real. Erandiks on parameetrite ja ühe parameetrita juhtum: kirjutada saab ühele reale ja ilma komata (st.
resource { 'title': }
иresource { 'title': param => value }
). - Parameetrite nooled peaksid olema samal tasemel.
- Nende ette on kirjutatud ressursside seose nooled.
Failide asukoht pappetserveris
Täiendava selgituse saamiseks tutvustan juurkataloogi mõistet. Juurkataloog on kataloog, mis sisaldab konkreetse sõlme Nuku konfiguratsiooni.
Juurkataloog erineb olenevalt Puppeti versioonist ja kasutatavatest keskkondadest. Keskkonnad on sõltumatud konfiguratsioonikomplektid, mis on salvestatud eraldi kataloogidesse. Tavaliselt kasutatakse koos gitiga, mille puhul luuakse keskkonnad giti harudest. Vastavalt sellele asub iga sõlm ühes või teises keskkonnas. Seda saab konfigureerida sõlmes endas või ENC-s, millest räägin järgmises artiklis.
- Kolmandas versioonis ("vana nukk") oli baaskataloog
/etc/puppet
. Keskkondade kasutamine on valikuline – näiteks vana Puppetiga me neid ei kasuta. Kui kasutatakse keskkondi, salvestatakse need tavaliselt sisse/etc/puppet/environments
, on juurkataloogiks keskkonnakataloog. Kui keskkondi ei kasutata, on baaskataloogiks juurkataloog. - Alates neljandast versioonist (“uus Puppet”) muutus keskkondade kasutamine kohustuslikuks ning baaskataloog viidi üle
/etc/puppetlabs/code
. Vastavalt sellele salvestatakse keskkondi/etc/puppetlabs/code/environments
, juurkataloog on keskkonnakataloog.
Juurkataloogis peab olema alamkataloog manifests
, mis sisaldab ühte või mitut sõlme kirjeldavat manifesti. Lisaks peaks seal olema alamkataloog modules
, mis sisaldab mooduleid. Mis moodulid on, räägin veidi hiljem. Lisaks võib vanal Puppetil olla ka alamkataloog files
, mis sisaldab erinevaid faile, mille kopeerime sõlmedesse. Uues Puppetis on kõik failid paigutatud moodulitesse.
Manifestifailidel on laiend .pp
.
Paar näidet võitlusest
Sõlme ja sellel oleva ressursi kirjeldus
Sõlme peal server1.testdomain
tuleb luua fail /etc/issue
sisuga Debian GNU/Linux n l
. Fail peab kuuluma kasutajale ja rühmale root
, juurdepääsuõigused peavad olema 644
.
Kirjutame manifesti:
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 в начале будет воспринято как записанное в восьмеричной системе, и всё пойдёт не так, как задумано
}
}
Sõlme ressursside vahelised seosed
Sõlme peal server2.testdomain
nginx peab töötama ja töötama eelnevalt ettevalmistatud konfiguratsiooniga.
Lahendame probleemi:
- Pakett tuleb installida
nginx
. - Konfiguratsioonifailid tuleb serverist kopeerida.
- Teenus peab töötama
nginx
. - Kui konfiguratsiooni värskendatakse, tuleb teenus taaskäivitada.
Kirjutame manifesti:
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 получает уведомление,
# соответствующий сервис перезапускается.
}
Selle toimimiseks vajate nukuserveris ligikaudu järgmist faili asukohta:
/etc/puppetlabs/code/environments/production/ # (это для нового Паппета, для старого корневой директорией будет /etc/puppet)
├── manifests/
│ └── site.pp
└── modules/
└── example/
└── files/
└── nginx-conf/
├── nginx.conf
├── mime.types
└── conf.d/
└── some.conf
Ressursi tüübid
Toetatud ressursitüüpide täieliku loendi leiate siit
fail
Haldab faile, katalooge, sümbollinke, nende sisu ja juurdepääsuõigusi.
Parameetrid:
- ressursi nimi - faili tee (valikuline)
- tee - faili tee (kui see pole nimes määratud)
- tagama - faili tüüp:
absent
- faili kustutaminepresent
— peab olema mis tahes tüüpi fail (kui faili pole, luuakse tavaline fail)file
- tavaline faildirectory
- katalooglink
- sümbollink
- sisu — faili sisu (sobib ainult tavafailide jaoks, ei saa kasutada koos allikas või sihtmärk)
- allikas — link teele, kust soovite faili sisu kopeerida (ei saa kasutada koos sisu või sihtmärk). Võib määrata kas URI-na koos skeemiga
puppet:
(siis kasutatakse nukuserveri faile) ja skeemigahttp:
(Loodan, et on selge, mis sel juhul juhtub) ja isegi diagrammigafile:
või absoluutse teena ilma skeemita (siis kasutatakse sõlme kohaliku FS-i faili) - sihtmärk — kuhu sümlink peaks osutama (ei saa kasutada koos sisu või allikas)
- omanik — kasutaja, kellele fail peaks kuuluma
- rühm — rühm, kuhu fail peaks kuuluma
- režiimis - failiõigused (stringina)
- korduma - võimaldab rekursiivset kataloogide töötlemist
- puhastus - võimaldab kustutada faile, mida Puppetis pole kirjeldatud
- sundida - võimaldab kustutada katalooge, mida Puppetis pole kirjeldatud
pakend
Installib ja eemaldab paketid. Suudab märguandeid käsitleda – installib paketi uuesti, kui parameeter on määratud reinstall_on_refresh.
Parameetrid:
- ressursi nimi - paketi nimi (valikuline)
- nimi - paketi nimi (kui nimes pole märgitud)
- tarnija - kasutada paketihaldurit
- tagama — pakendi soovitud olek:
present
,installed
- mis tahes versioon installitudlatest
- installitud uusim versioonabsent
- kustutatud (apt-get remove
)purged
- kustutatud koos konfiguratsioonifailidega (apt-get purge
)held
- paketi versioon on lukus (apt-mark hold
)любая другая строка
— määratud versioon on installitud
- reinstall_on_refresh - kui a
true
, siis pärast teate saamist installitakse pakett uuesti. Kasulik allikapõhiste distributsioonide puhul, kus järgu parameetrite muutmisel võib osutuda vajalikuks pakettide ümberehitamine. Vaikimisifalse
.
teenus
Haldab teenuseid. Suudab märguandeid töödelda – taaskäivitab teenuse.
Parameetrid:
- ressursi nimi — hallatav teenus (valikuline)
- nimi — teenus, mida tuleb hallata (kui nimes pole märgitud)
- tagama — teenuse soovitud olek:
running
- käivitatudstopped
- peatus
- võimaldama — kontrollib teenuse käivitamise võimalust:
true
— automaatkäivitus on lubatud (systemctl enable
)mask
- maskeeritud (systemctl mask
)false
— automaatkäivitus on keelatud (systemctl disable
)
- restart - käsk teenuse taaskäivitamiseks
- staatus — käsk teenuse oleku kontrollimiseks
- on restart — näitab, kas teenuse algskript toetab taaskäivitamist. Kui
false
ja parameeter on määratud restart — kasutatakse selle parameetri väärtust. Kuifalse
ja parameeter restart pole määratud - teenus peatatakse ja alustatakse taaskäivitamist (kuid systemd kasutab käskusystemctl restart
). - hasstaatus — näitab, kas teenuse algskript toetab käsku
status
. Kuifalse
, siis kasutatakse parameetri väärtust staatus. Vaikimisitrue
.
exec
Käitab väliseid käske. Kui te parameetreid ei määra loob, ainult kui, kui või värskendavalt, käivitatakse käsk iga kord, kui Puppet käivitatakse. Suudab märguandeid töödelda – käivitab käsu.
Parameetrid:
- ressursi nimi — täidetav käsk (valikuline)
- käsk - täidetav käsk (kui see pole nimes määratud)
- tee — teed, kust käivitatavat faili otsida
- ainult kui — kui selles parameetris määratud käsk täidetakse nullkoodiga, täidetakse põhikäsk
- kui — kui selles parameetris määratud käsk täidetakse nullist erineva tagastuskoodiga, täidetakse põhikäsk
- loob — kui selles parameetris määratud faili pole olemas, käivitatakse põhikäsk
- värskendavalt - kui a
true
, käivitatakse käsk ainult siis, kui see exec saab teatise teistelt ressurssidelt - cwd - kataloog, kust käsku käivitada
- kasutaja — kasutaja, kellelt käsku käivitada
- tarnija - kuidas käsku käivitada:
- posix — alamprotsess luuakse lihtsalt, täpsustage kindlasti tee
- koor - käsk käivitatakse kestas
/bin/sh
, ei pruugi olla täpsustatud tee, saate kasutada kera, torusid ja muid kesta funktsioone. Tavaliselt tuvastatakse automaatselt, kui on mingeid erimärke (|
,;
,&&
,||
jne).
cron
Kontrollib cronjobs.
Parameetrid:
- ressursi nimi - lihtsalt mingi identifikaator
- tagama — crownjobi osariik:
present
- luua, kui seda pole olemasabsent
- kustutada, kui see on olemas
- käsk - millist käsku käivitada
- keskkond - millises keskkonnas käsku käivitada (keskkonnamuutujate loend ja nende väärtused
=
) - kasutaja — milliselt kasutajalt käsk käivitada
- minut, tund, argipäev, kuu, kuupäev - millal käivitada cron. Kui mõnda neist atribuutidest pole määratud, on selle väärtus crontabis
*
.
Nukk 6.0 cron nagu oleks
Ressursidest üldiselt
Ressursi unikaalsuse nõuded
Kõige tavalisem viga, millega me kokku puutume, on Deklaratsiooni duplikaat. See tõrge ilmneb siis, kui kataloogis kuvatakse kaks või enam sama tüüpi sama nimega ressurssi.
Seetõttu kirjutan uuesti: sama sõlme manifestid ei tohiks sisaldada sama tüüpi sama pealkirjaga ressursse!
Mõnikord on vaja installida sama nimega, kuid erinevate paketihalduritega pakette. Sel juhul peate kasutama parameetrit name
vea vältimiseks:
package { 'ruby-mysql':
ensure => installed,
name => 'mysql',
provider => 'gem',
}
package { 'python-mysql':
ensure => installed,
name => 'mysql',
provider => 'pip',
}
Teistel ressursitüüpidel on sarnased võimalused dubleerimise vältimiseks − name
у teenus, command
у exec, ja nii edasi.
Metaparameetrid
Igal ressursitüübil on olenemata selle olemusest teatud eriparameetrid.
Metaparameetrite täielik loend
Lühike nimekiri:
- nõudma — see parameeter näitab, millistest ressurssidest see ressurss sõltub.
- enne - See parameeter määrab, millised ressursid sellest ressursist sõltuvad.
- tellima — see parameeter määrab, millistelt ressurssidelt see ressurss teateid saab.
- teatama — See parameeter määrab, millised ressursid saavad sellelt ressursil teateid.
Kõik loetletud metaparameetrid aktsepteerivad kas ühte ressursi linki või nurksulgudes olevate linkide massiivi.
Lingid ressurssidele
Ressursi link on lihtsalt ressursi mainimine. Neid kasutatakse peamiselt sõltuvuste näitamiseks. Olematule ressursile viitamine põhjustab kompileerimisvea.
Lingi süntaks on järgmine: ressursi tüüp suure algustähega (kui tüübi nimi sisaldab topeltkooloneid, siis iga koolonite vahele jääv nimeosa on suurtähtedega), seejärel ressursi nimi nurksulgudes (nime suurtäht ei muutu!). Tühikuid ei tohiks olla, nurksulud kirjutatakse kohe tüübinime järele.
Näide:
file { '/file1': ensure => present }
file { '/file2':
ensure => directory,
before => File['/file1'],
}
file { '/file3': ensure => absent }
File['/file1'] -> File['/file3']
Sõltuvused ja teatised
Nagu varem öeldud, on lihtsad ressurssidevahelised sõltuvused transitiivsed. Muide, olge sõltuvuste lisamisel ettevaatlik – saate luua tsüklilisi sõltuvusi, mis põhjustavad kompileerimisvea.
Erinevalt sõltuvustest ei ole teatised transitiivsed. Teatiste puhul kehtivad järgmised reeglid:
- Kui ressurss saab teatise, värskendatakse seda. Värskendustoimingud sõltuvad ressursi tüübist − exec käivitab käsu, teenus taaskäivitab teenuse, pakend installib paketi uuesti. Kui ressursil pole värskendustoimingut määratletud, ei juhtu midagi.
- Ühe Puppeti käitamise ajal ei värskendata ressurssi rohkem kui üks kord. See on võimalik, kuna teatised sisaldavad sõltuvusi ja sõltuvuste graafik ei sisalda tsükleid.
- Kui Nukk muudab ressursi olekut, saadab ressurss teatisi kõigile selle tellitud ressurssidele.
- Kui ressurssi värskendatakse, saadab see teatisi kõigile selle tellitud ressurssidele.
Määratlemata parameetrite käsitlemine
Reeglina, kui mõnel ressursi parameetril vaikeväärtust pole ja seda parameetrit manifestis pole määratud, siis Puppet sõlme vastava ressursi puhul seda omadust ei muuda. Näiteks kui tüüpi ressurss fail parameeter pole määratud owner
, siis ei muuda Puppet vastava faili omanikku.
Sissejuhatus klassidesse, muutujatesse ja definitsioonidesse
Oletame, et meil on mitu sõlme, millel on sama osa konfiguratsioonist, kuid on ka erinevusi - muidu võiksime seda kõike ühes plokis kirjeldada node {}
. Muidugi saab konfiguratsiooni identseid osi lihtsalt kopeerida, aga üldiselt on see halb lahendus – konfiguratsioon kasvab ja kui muudad konfiguratsiooni üldist osa, pead sa paljudes kohtades sama asja redigeerima. Samas on lihtne eksida ja üldiselt leiutati DRY (ära korda ennast) põhimõte põhjusega.
Selle probleemi lahendamiseks on selline disain nagu klass.
Klassid
Kõigepealt tuleb klassi kirjeldada. Kirjeldus ise ei lisa kuhugi ressurssi. Klassi kirjeldatakse manifestides:
# Описание класса начинается с ключевого слова class и его названия.
# Дальше идёт тело класса в фигурных скобках.
class example_class {
...
}
Pärast seda saab klassi kasutada:
# первый вариант использования — в стиле ресурса с типом class
class { 'example_class': }
# второй вариант использования — с помощью функции include
include example_class
# про отличие этих двух вариантов будет рассказано дальше
Näide eelmisest ülesandest – viime nginxi installimise ja konfigureerimise klassi:
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
}
Muutujad
Eelmise näite klass ei ole üldse paindlik, kuna see toob alati kaasa sama nginxi konfiguratsiooni. Teeme tee konfiguratsioonimuutujaks, siis saab seda klassi kasutada mis tahes konfiguratsiooniga nginxi installimiseks.
Seda saab teha
Tähelepanu: Nuku muutujad on muutumatud!
Lisaks saab muutujale juurde pääseda alles pärast selle deklareerimist, vastasel juhul muutub muutuja väärtus undef
.
Näide muutujatega töötamiseks:
# создание переменных
$variable = 'value'
$var2 = 1
$var3 = true
$var4 = undef
# использование переменных
$var5 = $var6
file { '/tmp/text': content => $variable }
# интерполяция переменных — раскрытие значения переменных в строках. Работает только в двойных кавычках!
$var6 = "Variable with name variable has value ${variable}"
Nukul on nimeruumid, ja muutujatel vastavalt on nähtavusala: Sama nimega muutujat saab määratleda erinevates nimeruumides. Muutuja väärtuse lahendamisel otsitakse muutujat praegusest nimeruumist, seejärel ümbritsevast nimeruumist jne.
Nimeruumi näited:
- globaalne - klassi või sõlme kirjeldusest väljapoole jäävad muutujad lähevad sinna;
- sõlme nimeruum sõlme kirjelduses;
- klassi nimeruum klassi kirjelduses.
Muutujale juurdepääsul ebaselguse vältimiseks saate muutuja nimes määrata nimeruumi:
# переменная без пространства имён
$var
# переменная в глобальном пространстве имён
$::var
# переменная в пространстве имён класса
$classname::var
$::classname::var
Lepime kokku, et tee nginxi konfiguratsioonini asub muutujas $nginx_conf_source
. Siis näeb klass välja selline:
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
}
Toodud näide on aga halb, sest seal on mingi “salateadmine”, et kuskil klassi sees kasutatakse sellise ja sellise nimega muutujat. Palju õigem on muuta need teadmised üldiseks – klassidel võivad olla parameetrid.
Klassi parameetrid on klassi nimeruumi muutujad, need määratakse klassi päises ja neid saab kasutada nagu tavalisi muutujaid klassi kehas. Parameetrite väärtused määratakse klassi kasutamisel manifestis.
Parameetri saab määrata vaikeväärtusele. Kui parameetril ei ole vaikeväärtust ja väärtust kasutamisel ei määrata, põhjustab see kompileerimisvea.
Parameetrime klassi ülaltoodud näite põhjal ja lisame kaks parameetrit: esimene, kohustuslik, on konfiguratsiooni tee ja teine, valikuline, on paketi nimi koos nginxiga (näiteks Debianis on paketid 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', # задаём параметры класса точно так же, как параметры для других ресурсов
}
}
Funktsioonis Puppet tipitakse muutujad. Sööma
Tüüp kirjutatakse vahetult parameetri nime ette:
class example (
String $param1,
Integer $param2,
Array $param3,
Hash $param4,
Hash[String, String] $param5,
) {
...
}
Klassid: kaasata klassinimi vs class{'classname':}
Iga klass on tüüpi ressurss klass. Nagu mis tahes muud tüüpi ressursside puhul, ei saa ühes sõlmes olla sama klassi kahte eksemplari.
Kui proovite lisada klassi samasse sõlme kaks korda kasutades class { 'classname':}
(vahet pole, erinevate või identsete parameetritega), tekib kompileerimisviga. Kuid kui kasutate klassi ressursi stiilis, saate manifestis koheselt määrata kõik selle parameetrid.
Kui aga kasutate include
, siis saab klassi lisada soovi korral mitu korda. Fakt on see, et include
on idempotentne funktsioon, mis kontrollib, kas klass on kataloogi lisatud. Kui klassi kataloogis pole, lisab see selle ja kui see on juba olemas, siis ei tee midagi. Kuid kasutamise korral include
Klassi deklareerimisel ei saa määrata klassi parameetreid – kõik nõutavad parameetrid tuleb määrata välises andmeallikas – Hiera või ENC. Nendest räägime järgmises artiklis.
Määratleb
Nagu eelmises plokis öeldud, ei saa sama klass ühes sõlmes olla rohkem kui üks kord. Mõnel juhul peate siiski saama kasutada sama koodiplokki erinevate parameetritega samas sõlmes. Teisisõnu on vajadus oma ressursitüübi järele.
Näiteks PHP mooduli installimiseks teeme Avitos järgmist:
- Installige pakett selle mooduliga.
- Loome selle mooduli jaoks konfiguratsioonifaili.
- Loome sümboli php-fpm konfiguratsioonile.
- Loome php cli konfiguratsioonile sümlingi.
Sellistel juhtudel kasutatakse sellist disaini nagu $title
, kuhu deklareerimisel läheb ressursi nimi. Nii nagu klasside puhul, tuleb esmalt kirjeldada definitsiooni, misjärel saab seda kasutada.
Lihtsustatud näide PHP mooduliga:
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' }
}
Lihtsaim viis Duplikaatdeklaratsiooni vea tuvastamiseks on Define. See juhtub siis, kui definitsioonil on konstantse nimega ressurss ja mõnes sõlmes on selle definitsiooni kaks või enam eksemplari.
Selle eest on lihtne end kaitsta: kõigil definitsioonis sisalduvatel ressurssidel peab olema nimi, olenevalt sellest $title
. Alternatiiviks on ressursside idempotentne lisamine, kõige lihtsamal juhul piisab definitsiooni kõikide eksemplaride ühised ressursid teisaldamisest eraldi klassi ja selle klassi kaasamisest definitsiooni - funktsiooni include
idempotentne.
Idempotentsuse saavutamiseks on ressursside lisamisel ka teisi võimalusi, nimelt funktsioonide kasutamine defined
и ensure_resources
, kuid ma räägin teile sellest järgmises osas.
Klasside ja määratluste sõltuvused ja teatised
Klassid ja määratlused lisavad sõltuvuste ja teatiste käsitlemisele järgmised reeglid.
- sõltuvus klassist/defineerist lisab sõltuvused klassi/define kõikidest ressurssidest;
- klassi/defineeri sõltuvus lisab sõltuvused kõikidele klassi/defineeri ressurssidele;
- class/define teatis teavitab kõiki klassi/define ressursse;
- class/define tellimus tellib kõik klassi/define ressurssid.
Tingimuslikud väited ja valijad
if
Siin on see lihtne:
if ВЫРАЖЕНИЕ1 {
...
} elsif ВЫРАЖЕНИЕ2 {
...
} else {
...
}
kui
kui if on vastupidine: koodiplokk käivitatakse, kui avaldis on väär.
unless ВЫРАЖЕНИЕ {
...
}
juhul
Ka siin pole midagi keerulist. Väärtustena saate kasutada tavalisi väärtusi (stringe, numbreid jne), regulaaravaldisi ja andmetüüpe.
case ВЫРАЖЕНИЕ {
ЗНАЧЕНИЕ1: { ... }
ЗНАЧЕНИЕ2, ЗНАЧЕНИЕ3: { ... }
default: { ... }
}
Valijad
Selektor on keelekonstruktsioon, mis on sarnane case
, kuid koodiploki täitmise asemel tagastab see väärtuse.
$var = $othervar ? { 'val1' => 1, 'val2' => 2, default => 3 }
Moodulid
Kui konfiguratsioon on väike, saab seda hõlpsasti ühes manifestis hoida. Kuid mida rohkem konfiguratsioone kirjeldame, seda rohkem on manifestis klasse ja sõlmi, see kasvab ja sellega töötamine muutub ebamugavaks.
Lisaks on koodi taaskasutuse probleem – kui kogu kood on ühes manifestis, on raske seda koodi teistega jagada. Nende kahe probleemi lahendamiseks on Puppetil olem nimega moodulid.
Moodulid - need on klasside, definitsioonide ja muude Puppet-üksuste komplektid, mis on paigutatud eraldi kataloogi. Teisisõnu, moodul on Nukuloogika iseseisev osa. Näiteks võib olla moodul nginxiga töötamiseks ja see sisaldab seda ja ainult seda, mida on vaja nginxiga töötamiseks, või võib olla moodul PHP-ga töötamiseks jne.
Moodulid on versioonistatud ja toetatud on ka moodulite sõltuvused üksteisest. Seal on avatud moodulite hoidla -
Nukuserveris asuvad moodulid juurkataloogi moodulite alamkataloogis. Iga mooduli sees on standardne kataloogiskeem – manifestid, failid, mallid, lib jne.
Faili struktuur moodulis
Mooduli juurfail võib sisaldada järgmisi kirjeldavate nimedega katalooge:
manifests
- see sisaldab manifestefiles
- see sisaldab failetemplates
- see sisaldab mallelib
- see sisaldab Ruby koodi
See ei ole täielik kataloogide ja failide loend, kuid praegu piisab selle artikli jaoks.
Moodulis olevate ressursside ja failide nimed
Mooduli ressursse (klasse, definitsioone) ei saa nimetada nii, nagu soovite. Lisaks on otsene vastavus ressursi nime ja faili nime vahel, millest Puppet selle ressursi kirjeldust otsib. Kui rikute nimetamisreegleid, ei leia Puppet lihtsalt ressursi kirjeldust ja saate kompileerimisvea.
Reeglid on lihtsad:
- Kõik mooduli ressursid peavad asuma mooduli nimeruumis. Kui moodul kutsutakse
foo
, siis tuleks kõik selles olevad ressursid nimetadafoo::<anything>
, või lihtsaltfoo
. - Mooduli nimega ressurss peab failis olema
init.pp
. - Muude ressursside puhul on failinimede skeem järgmine:
- mooduli nimega eesliide jäetakse kõrvale
- kõik topeltkoolonid, kui neid on, asendatakse kaldkriipsudega
- laiendus on lisatud
.pp
Toon näitega. Oletame, et kirjutan moodulit nginx
. See sisaldab järgmisi ressursse:
- klass
nginx
manifestis kirjeldatudinit.pp
; - klass
nginx::service
manifestis kirjeldatudservice.pp
; - määratleda
nginx::server
manifestis kirjeldatudserver.pp
; - määratleda
nginx::server::location
manifestis kirjeldatudserver/location.pp
.
Mallid
Kindlasti teate ise, mis on mallid; ma ei kirjelda neid siin üksikasjalikult. Aga ma jätan selle igaks juhuks
Mallide kasutamine: malli tähendust saab funktsiooni abil laiendada template
, mis edastatakse mallile. Seda tüüpi ressursside jaoks fail kasutatakse koos parameetriga content
. Näiteks nii:
file { '/tmp/example': content => template('modulename/templatename.erb')
Vaata teed <modulename>/<filename>
tähendab faili <rootdir>/modules/<modulename>/templates/<filename>
.
Lisaks on olemas funktsioon inline_template
— see saab sisendiks malli teksti, mitte faili nime.
Mallides saate kasutada kõiki praeguse ulatusega Nuku muutujaid.
Nukk toetab ERB- ja EPP-vormingus malle:
Lühidalt ERB-st
Juhtstruktuurid:
<%= ВЫРАЖЕНИЕ %>
— sisestage avaldise väärtus<% ВЫРАЖЕНИЕ %>
— arvutada avaldise väärtus (ilma seda sisestamata). Siia lähevad tavaliselt tingimuslaused (if) ja tsüklid (igaüks).<%# КОММЕНТАРИЙ %>
Avaldised ERB-s kirjutatakse rubiiniga (ERB on tegelikult sisseehitatud rubiin).
Manifestist muutujatele juurdepääsemiseks peate lisama @
muutuja nimele. Juhtkonstruktsiooni järel ilmuva reavahetuse eemaldamiseks peate kasutama sulgevat silti -%>
.
Malli kasutamise näide
Oletame, et kirjutan moodulit ZooKeeperi juhtimiseks. Konfiguratsiooni loomise eest vastutav klass näeb välja umbes selline:
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'),
}
}
Ja vastav mall zoo.cfg.erb
- Niisiis:
<% 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 -%>
Faktid ja sisseehitatud muutujad
Sageli sõltub konfiguratsiooni konkreetne osa sellest, mis sõlmes parasjagu toimub. Näiteks, olenevalt sellest, milline on Debiani väljalase, peate installima ühe või teise paketi versiooni. Saate seda kõike käsitsi jälgida, sõlmede muutumisel manifeste ümber kirjutades. Kuid see ei ole tõsine lähenemine, automatiseerimine on palju parem.
Sõlmede kohta teabe saamiseks on Puppetil mehhanism, mida nimetatakse faktideks. andmed - see on teave sõlme kohta, mis on saadaval manifestides tavaliste muutujate kujul globaalses nimeruumis. Näiteks hostinimi, operatsioonisüsteemi versioon, protsessori arhitektuur, kasutajate loend, võrguliideste ja nende aadresside loend ning palju-palju muud. Faktid on tavaliste muutujatena saadaval manifestides ja mallides.
Faktidega töötamise näide:
notify { "Running OS ${facts['os']['name']} version ${facts['os']['release']['full']}": }
# ресурс типа notify просто выводит сообщение в лог
Vormiliselt öeldes on faktil nimi (string) ja väärtus (saadaval on mitut tüüpi: stringid, massiivid, sõnastikud). Sööma
Töötamise ajal kopeerib nukuagent esmalt kõik olemasolevad faktikogujad pappetserverist sõlme, misjärel käivitab need ja saadab kogutud faktid serverisse; Pärast seda alustab server kataloogi koostamist.
Faktid käivitatavate failide kujul
Sellised faktid paigutatakse kataloogi moodulitesse facts.d
. Loomulikult peavad failid olema käivitatavad. Käitamisel peavad nad väljastama teabe standardväljundisse kas YAML-i või võtme=väärtuse vormingus.
Ärge unustage, et faktid kehtivad kõigi sõlmede kohta, mida juhib hüpikserver, kuhu teie moodul on juurutatud. Seetõttu kontrollige skriptis, et süsteemil oleks kõik teie fakti toimimiseks vajalikud programmid ja failid.
#!/bin/sh
echo "testfact=success"
#!/bin/sh
echo '{"testyamlfact":"success"}'
Rubiini faktid
Sellised faktid paigutatakse kataloogi moodulitesse 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
Teksti faktid
Sellised faktid paigutatakse kataloogi sõlmedesse /etc/facter/facts.d
vanas Nuku- või /etc/puppetlabs/facts.d
uues Nukus.
examplefact=examplevalue
---
examplefact2: examplevalue2
anotherfact: anothervalue
Faktide juurde jõudmine
Faktidele lähenemiseks on kaks võimalust:
- sõnastiku kaudu
$facts
:$facts['fqdn']
; - kasutades muutuja nimena fakti nime:
$fqdn
.
Parim on kasutada sõnaraamatut $facts
või veelgi parem, näita globaalset nimeruumi ($::facts
).
Sisseehitatud muutujad
Lisaks faktidele on ka
- usaldusväärsed faktid — muutujad, mis võetakse kliendi sertifikaadist (kuna sertifikaat väljastatakse tavaliselt poppet-serveris, ei saa agent lihtsalt oma sertifikaati võtta ja muuta, seega on muutujad "usaldusväärsed"): sertifikaadi nimi, sertifikaadi nimi host ja domeen, sertifikaadi laiendused.
- serveri faktid — serveri teabega seotud muutujad — versioon, nimi, serveri IP-aadress, keskkond.
- agendi faktid — muutujad, mille lisab otse nuku-agendi, mitte faktori — sertifikaadi nimi, agendi versioon, nukuversioon.
- põhimuutujad - Pappetmasteri muutujad (sic!). See on umbes sama, mis sees serveri faktid, pluss konfiguratsiooniparameetrite väärtused on saadaval.
- kompilaatori muutujad — kompilaatori muutujad, mis erinevad igas ulatuses: praeguse mooduli nimi ja selle mooduli nimi, milles praegusele objektile ligi pääseti. Nende abil saab näiteks kontrollida, et sinu eraklasse ei kasutata otse teistest moodulitest.
Lisa 1: kuidas seda kõike käivitada ja siluda?
Artikkel sisaldas palju näiteid nukukoodi kohta, kuid ei öelnud meile üldse, kuidas seda koodi käivitada. Noh, ma parandan ennast.
Puppeti käivitamiseks piisab agendist, kuid enamikul juhtudel vajate ka serverit.
Agent
Vähemalt alates versioonist XNUMX, nuku-agendi paketid alates
Lihtsamal juhul piisab nukukonfiguratsiooni kasutamiseks agendi käivitamisest serverita režiimis: eeldusel, et nuku kood kopeeritakse sõlme, käivitage 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
Parem on muidugi seadistada server ja käitada agente sõlmedes deemonirežiimis - siis rakendavad nad iga poole tunni järel serverist allalaaditud konfiguratsiooni.
Saate jäljendada töö tõukemudelit - minge teid huvitavasse sõlme ja alustage sudo puppet agent -t
. Võti -t
(--test
) sisaldab tegelikult mitut valikut, mida saab eraldi lubada. Need valikud hõlmavad järgmist.
- ära tööta deemonirežiimis (vaikimisi käivitub agent deemonirežiimis);
- sulgege pärast kataloogi rakendamist (vaikimisi jätkab agent tööd ja rakendab konfiguratsiooni kord poole tunni jooksul);
- kirjutada üksikasjalik tööpäevik;
- näidata failides tehtud muudatusi.
Agendil on muudatusteta töörežiim – seda saad kasutada siis, kui pole kindel, et oled õige konfiguratsiooni kirjutanud ja soovid kontrollida, mida agent töö käigus täpselt muudab. See režiim on parameetriga lubatud --noop
käsureal: sudo puppet agent -t --noop
.
Lisaks saate lubada teose silumislogi - selles kirjutab nukk kõigist toimingutest, mida ta teeb: ressursi kohta, mida ta praegu töötleb, selle ressursi parameetrite kohta, milliseid programme see käivitab. Loomulikult on see parameeter --debug
.
Server
Ma ei käsitle selles artiklis pappetserveri täielikku seadistamist ja sellele koodi juurutamist; ütlen ainult, et komplektis on serveri täielikult toimiv versioon, mis ei nõua väikese arvu serveritega töötamiseks lisakonfiguratsiooni. sõlmed (ütleme, kuni sada). Suurem arv sõlmi nõuab häälestamist - vaikimisi käivitab nukuserver mitte rohkem kui neli töötajat, suurema jõudluse saavutamiseks peate nende arvu suurendama ja ärge unustage suurendada mälupiiranguid, vastasel juhul kogub server suurema osa ajast prügi.
Koodi juurutamine – kui vajate seda kiiresti ja lihtsalt, siis vaadake (r10k)[
2. lisa: kodeerimisjuhised
- Asetage kogu loogika klassidesse ja definitsioonidesse.
- Hoidke klasse ja määratlusi moodulites, mitte sõlmedes kirjeldavates manifestides.
- Kasutage fakte.
- Ärge tehke hostinimede põhjal if-e.
- Lisage julgelt parameetreid klasside ja definitsioonide jaoks – see on parem kui klassi/define kehasse peidetud kaudne loogika.
Miks ma soovitan seda teha, selgitan järgmises artiklis.
Järeldus
Lõpetame sissejuhatusega. Järgmises artiklis räägin teile Hierast, ENC-st ja PuppetDB-st.
Küsitluses saavad osaleda ainult registreerunud kasutajad.
Tegelikult on materjali palju rohkem – saan kirjutada artikleid järgmistel teemadel, hääletada selle üle, mille kohta sul oleks huvi lugeda:
- 59,1%Täiustatud nukukonstruktsioonid – mõni järgmise taseme jama: tsüklid, kaardistamine ja muud lambda-avaldised, ressursside kogujad, eksporditud ressursid ja hostidevaheline suhtlus Nuku kaudu, sildid, pakkujad, abstraktsed andmetüübid.13
- 31,8%“I’m my mother’s admin” ehk kuidas me Avitos sõbrunesime mitme erineva versiooniga poppet-serveriga ja põhimõtteliselt ka poppet-serveri haldamise osa.7
- 81,8%Kuidas me nukukoodi kirjutame: mõõteriistad, dokumentatsioon, testimine, CI/CD.18
22 kasutajat hääletas. 9 kasutajat jäi erapooletuks.
Allikas: www.habr.com