Puppet on konfigureerimise haldamise süsteem. Seda kasutatakse hostide viimiseks soovitud olekusse ja selle oleku säilitamiseks.
Olen Puppetiga tööd teinud juba üle viie aasta. See tekst on sisuliselt tõlgitud ja ümber korraldatud kokkuvõte ametlikest dokumentidest, mis võimaldab algajatel kiiresti Puppeti olemusse süveneda.

Põhinformatsioon
Puppet töötab klient-server arhitektuuril, kuigi on saadaval ka serverita versioon piiratud funktsionaalsusega.
Kasutatakse pull-mudelit: vaikimisi kord poole tunni jooksul pöörduvad kliendid serveri poole, et saada konfiguratsiooni ja rakendada seda. Kui olete töötanud Ansible'iga, siis seal kasutatakse teistsugust push-mudelit: administraator algatab konfiguratsiooni rakendamise protsessi, kliendid ise ei rakenda midagi.
Võrgus suhtlemisel kasutatakse kahepoolset TLS-krüptimist: serveril ja kliendil on oma privaatvõtmed ja vastavad sertifikaadid. Tavaliselt väljastab server sertifikaadid klientidele, kuid põhimõtteliselt on võimalik kasutada ka välist CA-d.
Tutvumine manifestidega
Puppeti terminoloogias pöördutakse puppet-serveri noodide (nodes). Noodide konfiguratsioon kirjutatakse manifestides eriti keeles Puppet DSL.
Puppet DSL on deklaratiivne keel. Sellel kirjeldatakse soovitud olekut noodi kujul, definitsiooniga üksikute ressurssidena, näiteks:
- Fail eksisteerib ja tal on kindel sisu.
- Pakett on installitud.
- Teenuse töö on alanud.
Ressursid võivad omavahel seotud olla:
- On sõltuvused, mis mõjutavad ressursside rakendamise järjekorda.
Näiteks: "Esmalt installi pakett, seejärel muuda konfiguratsioonifaili, pärast seda käivita teenus." - On teavitamised – kui ressurssi muudetakse, saadab see teate allkirjastatud ressurssidele.
Kui konfiguratsioonifail muudetakse, võidakse teenust automaatselt taaskäivitada.
Lisaks on Puppet DSL-is funktsioonid ja muutujad, samuti tingimuslaused ja selektorid. Toetatakse ka erinevaid šabloonimise mehhanisme – EPP ja ERB.
Puppet on kirjutatud Ruby keeles, seetõttu on paljusid konstruktsioone ja termineid võetud sealt. Ruby võimaldab Puppetit laiendada – täiendada keeruka loogika, uute ressursitüüpide ja funktsioonidega.
Puppeti töö ajal koostatakse iga konkreetse sõlme maani festid serveris katalooge. Kataloog — see on ressursside ja nende omavaheliste seoste loetelu pärast funktsioonide, muutujate väärtuste arvutamist ja tingimuslike operaatorite avamist.
Süntaks ja koodistiil
Siin on ametliku dokumentatsiooni sektsioonid, mis aitavad süntaksiga tuttavaks saada, kui antud näidised ei ole piisavad:
Siin on näide, milline välja näeb maani fest:
# Комментарии пишутся, как и много где, после решётки.
#
# Описание конфигурации ноды начинается с ключевого слова node,
# за которым следует селектор ноды — хостнейм (с доменом или без)
# или регулярное выражение для хостнеймов, или ключевое слово default.
#
# После этого в фигурных скобках описывается собственно конфигурация ноды.
#
# Одна и та же нода может попасть под несколько селекторов. Про приоритет
# селекторов написано в статье про синтаксис описания нод.
node 'hostname', 'f.q.d.n', /regexp/ {
# Конфигурация по сути является перечислением ресурсов и их параметров.
#
# У каждого ресурса есть тип и название.
#
# Внимание: не может быть двух ресурсов одного типа с одинаковыми названиями!
#
# Описание ресурса начинается с его типа. Тип пишется в нижнем регистре.
# Про разные типы ресурсов написано ниже.
#
# После типа в фигурных скобках пишется название ресурса, потом двоеточие,
# дальше идёт опциональное перечисление параметров ресурса и их значений.
# Значения параметров указываются через т.н. hash rocket (=>).
resource { 'title':
param1 => value1,
param2 => value2,
param3 => value3,
}
}Tühikud ja reavahetused ei ole maani festis kohustuslikud, kuid on soovitatav . Lühidalt öeldes:
- Kaks tühikut, tabulaatoreid ei kasutata.
- Kohad peavad olema eraldatud tühikuga, kakspunkti puhul ei eraldata.
- Komad iga parameetri järel, sealhulgas viimane. Iga parameeter — eraldi reaal. Erand kehtib juhul, kui puuduvad parameetrid ja üks parameeter: neid saab kirjutada ühele reale ja ilma kommata (t. ei.
resource { 'title': }jaresource { 'title': param => value }). - Parameetrite noolte peab olema ühel tasemel.
- Ressursside omavahelise seose nooled kirjutatakse enne neid.
Failide asukoht Puppet-serveris
Edasiste selgituste jaoks tutvustan mõistet 'juurkataloog'. Juurkataloog on kataloog, kus asub Puppet-konfiguratsioon konkreetsele sõlmele.
Juurkataloog erineb sõltuvalt Puppet'i versioonist ja keskkondade kasutamisest. Keskkonnad on sõltumatud konfiguratsioonide kogumid, mis asuvad eraldi kataloogides. Tavaliselt kasutavad neid koos gitiga, sel juhul luuakse keskkonnad git'i harudest. Vastavalt asub iga sõlm ühest või teisest keskkonnast. See konfigureeritakse sõlmes endas või ENC-is, millest räägin järgmises artiklis.
- Kolmandas versioonis ('vana Puppeti') oli põhikataloog
/etc/puppet. Keskkondade kasutamine on valikuline — me näiteks ei kasuta neid vana Puppeti puhul. Kui keskkondi kasutatakse, siis hoitakse neid tavaliselt/etc/puppet/environments, siis juurkataloog on keskkonna kataloog. Kui keskkondi ei kasutata, on juurkataloog põhi. - Alates neljandast versioonist ('uus Puppet') on keskkondade kasutamine muutunud kohustuslikuks ja põhikataloog on viidud
/etc/puppetlabs/code. Seega säilitatakse keskkonnad/etc/puppetlabs/code/environments, põhikaust on keskkonna kaust.
Põhikaustas peab olema alamkaust manifests, kus asub üks või mitu manifesti sõlmede kirjeldusega. Lisaks peab seal olema alamkaust modules, kus asuvad moodulid. Mis on moodulid, räägin ma veidi hiljem. Samuti võib vanas Puppetis olla alamkaust files, kus asuvad erinevad failid, mille me kopeerime sõlmedesse. Uues Puppetis on kõik failid viidud moodulitesse.
Manifestide failidel on laiend .pp.
Kaks reaalset näidet
Sõlme ja sellel olevale ressursile kirjeldus
Sõlmes server1.testdomain peab olema loodud fail /etc/issue sisu Debian GNU/Linux n l. Fail peab kuuluma kasutajale ja rühmale root, õigused peavad olema 644.
Kirjutame manifesti:
node 'server1.testdomain' { # konfiguratsiooni plokk, mis on seotud sõlmega server1.testdomain
file { '/etc/issue': # kirjelda faili /etc/issue
ensure => present, # see fail peab olemas olema
content => 'Debian GNU/Linux n l', # sellel peab olema selline sisu
owner => root, # omanik
group => root, # omanikurühm
mode => '0644', # failile õigused. Need on määratud stringina (jutumärkides), sest muidu tõlgendatakse liigendit 0 alguses kaheksandana ja kõik läheb valesti
}
}Ressursside omavahelised seosed sõlmes
Sõlmes server2.testdomain peab olema käivitunud nginx, mis töötab eelnevalt ettevalmistatud konfiguratsiooniga.
Dekomponeerime ülesande:
- Peab olema installitud pakett
nginx. - Peab olema kopeeritud konfiguratsioonifailid serverilt.
- Peab olema käivitunud teenus
nginx. - Konfiguratsiooni uuendamisel tuleb teenus uuesti käivitada.
Kirjutame manifesti:
node 'server2.testdomain' { # server2.testdomain' nodi konfiguratsiooniblokk
package { 'nginx': # kirjeldame nginx paketti
ensure => installed, # see peab olema installitud
}
# Otsene nool (->) tähendab, et allolev ressurss peab
# olema loodud pärast ülaltoodud resurssi.
# Need sõltuvused on transitiivsed.
-> file { '\/etc\/nginx': # kirjeldame faili \/etc\/nginx
ensure => directory, # see peab olema kataloog
source => 'puppet:\/\/\/modules\/example\/nginx-conf', # selle sisu tuleb võtta puppeti serverist määratud aadressilt
recurse => true, # kausta faile tuleb kopeerida rekuursiivselt
purge => true, # tuleb kustutada liigsed failid (need, mida pole allikas)
force => true, # kustutada liigsed kataloogid
}
# Kurrulise noole (~>) tähendab, et allolev ressurss peab
# reageerima ülaltoodud ressurssi muutustele.
# Kurruline nool hõlmab endas otsest (->).
~> service { 'nginx': # kirjeldame nginx teenust
ensure => running, # see peab olema töös
enable => true, # see peab automaatselt käivituma süsteemi käivitamisel
}
# Kui teenuse tüüp saab teate,
# vastav teenus käivitatakse uuesti.
}Selle töötamiseks on vajalik umbkaudu selline failide asetus puppeti serveris:
/etc/puppetlabs/code/environments/production/ # (это для нового Паппета, для старого корневой директорией будет /etc/puppet)
├── manifests/
│ └── site.pp
└── modules/
└── example/
└── files/
└── nginx-conf/
├── nginx.conf
├── mime.types
└── conf.d/
└── some.confResursside tüübid
Toetatud ressursside tüüpide täielik loetelu on , siin kirjeldan viit põhiklassi, mille jaoks minu praktikas piisab enamikus ülesannetes.
file
Haldab faile, katalooge, sümboolseid linke, nende sisu ja juurdepääsuõigusi.
Parameetrid:
- ressursi nimi — failitee (valikuline)
- path — failitee (kui see pole määratud nimele)
- ensure — faili tüüp:
absent— eemaldada failpresent— peab olema mis tahes tüüpi fail (kui faili ei ole, luuakse tavaline fail)file— tavaline faildirectory— katalooglink— sümboolne link
- content — faili sisu (sobib ainult tavaliseks failiks, ei saa kasutada koos source või target)
- source — viide teele, kust peab kopeerima faili sisu (ei saa kasutada koos content või target). See võib olla määratud kas URI scheemiga
puppet:(siis kasutatakse faile puppeti serverist), samuti võib olla scheemagahttp:(loodan, et on selge, mis juhtub sel juhul), ja isegi scheematafile:või absoluutse teena ilma scheemita (siis kasutatakse faili kohalike failisüsteemis nodis) - target — kuhu sümbolviit peaks osutama (ei saa kasutada koos content või source)
- omanik — kasutaja, kellele fail kuuluma peaks
- gruppe — grupp, kellele fail kuuluma peaks
- režiim — õigused failile (stringina)
- rekursiivne — aktiveerib kaustade rekursiivse töötlemise
- eemaldamine — aktiveerib failide eemaldamise, mida Puppet ei kirjelda
- sunne — aktiveerib kaustade eemaldamise, mida Puppet ei kirjelda
pakett
Installib ja eemaldab pakette. Suudab töödelda teateid — installib paketti uuesti, kui on määratud parameeter uuesti_installimiselt_kui_uuendatud.
Parameetrid:
- ressursi nimi — paketi nimi (valikuline)
- nimi — paketi nimi (kui ei ole määratud nimes)
- pakkuja — pakihaldur, mida tuleb kasutada
- ensure — soovitud paketi olek:
present,paigaldatud— paigaldatud ükskõik milliseks versioonikslatest— paigaldatud viimane versioonabsent— eemaldatud (apt-get remove)eemaldatud— eemaldatud koos konfiguratsioonifailidega (apt-get purge)hoitud— paketi versioon on blokeeritud (apt-mark hold)ükskõik milline muu string— paigaldatud määratud versioon
- uuesti_installimiselt_kui_uuendatud — kui
true, siis paketti uuesti installides ilmub teade. Kasulik source-based jaotiste puhul, kus pakettide uuesti kogumine võib olla vajalik kokkuvõtete muutmisel. Vaikimisifalse.
teenus
Halda teenuseid. Suudab töödelda teateid — taaskäivitab teenuse.
Parameetrid:
- ressursi nimi — teenus, mida tuleb hallata (valikuline)
- nimi — teenus, mida tuleb hallata (kui ei ole määratud nimes)
- ensure — soovitud teenuse olek:
käivitatud— käivitatudpeatatud— peatatud
- lubada — haldab teenuse automaatset käivitamist:
true— automaatne käivitamine on lubatud (systemctl enable)mask— maskeeritud (systemctl mask)false— automaatne käivitamine on keelatud (systemctl disable)
- taaskäivitamine — käsk teenuse taaskäivitamiseks
- staatus — käsk teenuse oleku kontrollimiseks
- on_taaskäivitamine — märkida, kas teenuse initskripti toetab taaskäivitamist. Kui
falseja parameeter on määratud taaskäivitamine — rakendatakse selle parameetri väärtust. Kuifalseja parameeter taaskäivitamine ei ole määratud — teenus peatatakse ja käivitatakse taaskäivitamiseks (kuid systemd kasutab käskusystemctl restart). - on_staatus — märkida, kas teenuse initskript toetab käsku
staatus. Kuifalse, siis rakendatakse parameetri väärtust staatus. Vaikimisitrue.
exec
Käivitab välised käsud. Kui parameetreid ei määrata loob, ainult_kui, kui_olemas või ainult_uuendamisel, käsk käivitatakse igal Puppetile edastamisel. Suudab töödelda teateid — käivitab käsu.
Parameetrid:
- ressursi nimi — käsk, mida tuleb täita (valikuline)
- käsk — käsk, mida tuleb täita (kui see ei ole määratud nimel)
- path — teed, kus otsida täidetavat faili
- ainult_kui — kui antud parameetrites määratud käsk lõppes nullkoodiga, täidetakse põhiülesanne
- kui_olemas — kui antud parameetrites määratud käsk lõppes mitte-nullkoodiga, täidetakse põhiülesanne
- loob — kui antud parameetrites määratud faili ei eksisteeri, täidetakse põhiülesanne
- ainult_uuendamisel — kui
true, siis käsk käivitatakse ainult siis, kui see exec saab teate teistelt ressurssidelt - cwd — kataloog, millest käivitada käsk
- kasutaja — kasutaja, kelle alt käivitada käsk
- pakkuja — millega käivitada käsk:
- posix — lihtsalt luuakse tütard protsess, peab olema määratud path
- käsurea tõlgendus — käsk käivitatakse tõlgenduses
/bin/sh, ei ole kohustuslik määrata path, saab kasutada globaalset, torusid ja muid käsurea funktsioone. Tavaliselt määratakse automaatselt, kui on kõikvõimalikke erimärke (|,;,&&,||ja nii edasi).
cron
Haldab cron tööülesandeid.
Parameetrid:
- ressursi nimi — lihtsalt mingi identifikaator
- ensure — cron tööülesande seisund:
present— loo, kui ei eksisteeriabsent— kustuta, kui eksisteerib
- käsk — millist käsku käivitada
- keskkond — millises keskkonnas käivitada käsk (muutujate nimekirja ja nende väärtuste eraldamine
=) - kasutaja — kellest kasutajast käivitada käsk
- minut, tund, nädalapäev, kuu, kuu päev — millal käivitada cron. Kui mõni neist atribuutidest ei ole määratud, on selle väärtuseks cron tabelis
*.
Puppet 6.0-s cron nagu oleks puppetserveris, seetõttu ei ole dokumentatsiooni ühiselt webisaidil. Kuid see puppet-agent'is, seetõttu ei pea seda eraldi paigaldama. Selle kohta dokumentatsiooni saab vaadata , või .
Ressurssidest üldiselt
Nõuded ressursside unikaalsuse osas
Sageim viga, millega me kokku puutume — Korduv deklareerimine. See viga tekib, kui katalooge satuvad kaks või enam sama tüüpi ressurssi sama nimega.
Seetõttu ütlen veel kord: manifestides ühe sõlme jaoks ei tohi olla sama tüüpi ressursse sama nimega (title)!
Mõnikord on vajalik paigaldada sama nimega pakette, kuid erinevate paketihalduritega. Sellisel juhul tuleb kasutada parameetrit nimi, et vältida viga:
package { 'ruby-mysql':
ensure => installed,
name => 'mysql',
provider => 'gem',
}
package { 'python-mysql':
ensure => installed,
name => 'mysql',
provider => 'pip',
}Muud tüüpi ressurssidel on sarnased parameetrid, mis aitavad vältida dubleerimist, — nimi on teenus, käsk on exec, jne.
Metaparameetrid
Igal ressursi tüübil on mõned spetsiifilised parameetrid, sõltumata selle olemusest.
Täielik nimekiri metaparameetritest .
Lühike nimekiri:
- require — selles parameetris märgitakse, millest sõltub käesolev ressurss.
- before — selles parameetris märgitakse, millised ressursid sõltuvad käesolevast ressursist.
- subscribe — selles parameetris märgitakse, millistelt ressurssidelt saadakse teateid käesoleva ressursi kohta.
- notify — selles parameetris märgitakse, millised ressursid saavad teateid käesolevalt ressursilt.
Kõik loetletud metaparameetrid saavad kas ühe viite ressursile või massiivi viiteid, mis on väljendatud nurksulgudes.
Viidatud ressursid
Viide ressursile on lihtsalt ressursi mainimine. T neid kasutatakse peamiselt sõltuvuste märkimiseks. Viide mitteolevale ressursile põhjustab kompileerimisviga.
Viidendi süntaks on järgmine: ressursi tüüp suure algustähega (kui nime tipus on topelt koolonid, siis kirjutatakse iga osa nime vahel suurte tähtedega), seejärel nurksulgudes ressursi nimi (nime registrit ei muudeta!). Tühikuid ei tohiks olla, nurksulgusid kirjutatakse kohe pärast tüübi nime.
Näide:
file { 'file1': ensure => present }
file { 'file2':
ensure => directory,
before => File['file1'],
}
file { 'file3': ensure => absent }
File['file1'] -> File['file3']Sõltuvused ja teated
Nagu varem mainitud, on ressursside vahelised lihtsad sõltuvused transitiivsed. Muide, olge ettevaatlik sõltuvuste määramisel — võimalike ringsete sõltuvuste tegemine toob kaasa kompileerimisvea.
Erinevalt sõltuvustest ei ole teated transitiivsed. Teadete jaoks kehtivad järgmised reeglid:
- Kui ressurss saab teate, uuendatakse seda. Uuendamise toimingud sõltuvad ressursi tüübist — exec käivitab käsu, teenus taaskäivitab teenuse, pakett uuesti installib paketi. Kui ressursi jaoks pole määratud toimingut uuendamisel, siis ei juhtu midagi.
- Üheks ajaks uuendatakse Puppet'i ressurssi mitte rohkem kui üks kord. See on võimalik, kuna teated sisaldavad sõltuvusi ning sõltuvuste graafis ei ole tsükleid.
- Kui Puppet muutab ressursi olekut, saadab resurssi teated kõigile, kes sellele ressursile on tellinud.
- Kui ressurssi uuendatakse, saadab see teate kõigile, kes on selle ressursi tellinud.
Nimetamata parameetrite töötlemine
Reeglina, kui ressursi parameetril ei ole vaikeväärtust ja see parameeter ei ole manifeedis määratletud, ei muuda Puppet vastava ressursi omadust sõlmes. Näiteks, kui ressursi tüübil on file parameeter ei ole määratletud omanik, siis Puppet ei muuda vastava faili omanikku.
Klasside, muutujate ja defineerimiste tundmaõppimine
Oletame, et meil on mitu sõlme, kus on sama konfiguratsiooni osa, kuid on ka erinevusi — muidu võiksime seda kõike kirjeldada ühes plokis node {}. Loomulikult võib lihtsalt kopeerida sarnased konfiguratsiooni osad, kuid üldiselt on see halb lahendus — konfiguratsioon paisub, kui üldises konfiguratsioonis muudetakse midagi, tuleb muuta sama asja paljudes kohtades. Sellega on lihtne eksida, ja DRY (ärge korrake end) põhimõte ei ole ilmaasjata välja mõeldud.
Selle probleemi lahendamiseks on olemas selline konstruktsioon nagu klass.
Klassid
— on nimeline Puppet'i koodiplokk. Klasse vajatakse koodi taaskasutamiseks.
Alustuseks tuleb klassi kirjeldada. Kirjeldus ise ei lisa mingeid ressursse. Klass kirjeldatakse manifeetides:
# Описание класса начинается с ключевого слова class и его названия.
# Дальше идёт тело класса в фигурных скобках.
class example_class {
...
}Pärast seda saab klassi kasutada:
# первый вариант использования — в стиле ресурса с типом class
class { 'example_class': }
# второй вариант использования — с помощью функции include
include example_class
# про отличие этих двух вариантов будет рассказано дальшеEelneva ülesande näide — eraldame nginx'i installimise ja seadistamise klassi:
class nginx_example {
package { 'nginx':
ensure => installed,
}
-> file { '/etc/nginx':
ensure => directory,
source => 'puppet:///modules/example/nginx-conf',
recurse => true,
purge => true,
force => true,
}
-> service { 'nginx':
ensure => running,
enable => true,
}
}
node 'server2.testdomain' {
include nginx_example
}Muutujad
Eelneva näite klass on täiesti jäik, kuna see toob alati sama nginx'i määratluse. Teeme nii, et konfiguratsiooni tee muutuks muutujaks, siis saab seda klassi kasutada nginx'i installimiseks mis tahes konfiguratsiooniga.
Seda saab teha .
Tähelepanu: Puppetis on muutumatud muutujad!
Lisaks saab muutujat kasutada alles pärast selle deklareerimist, vastasel juhul on muutujaks undef.
Muutujate töö näide:
# создание переменных
$variable = 'value'
$var2 = 1
$var3 = true
$var4 = undef
# использование переменных
$var5 = $var6
file { '/tmp/text': content => $variable }
# интерполяция переменных — раскрытие значения переменных в строках. Работает только в двойных кавычках!
$var6 = "Variable with name variable has value ${variable}"Puppetis on nimede ruumid, ja muutujatel on seega ulatus: muutuja, millel on sama nimi, võib olla määratletud erinevates nimede ruumides. Muutuja väärtuse määramisel otsitakse muutujat kõigepealt praeguses nimede ruumis, seejärel ümbritsevas ruumis ja nii edasi.
Nimede ruumide näited:
- globaalne — sinna kuuluvad muutujad, mis on väljaspool klassi või noodi määratlemist;
- noodi nimede ruum noodi määratlemisel;
- klassi nimede ruum klassi määratlemisel.
Kuna kahemõttelisuse vältimiseks muutuja poole pöördumisel on võimalik nimede ruumi näidata muutuja nimes:
# переменная без пространства имён
$var
# переменная в глобальном пространстве имён
$::var
# переменная в пространстве имён класса
$classname::var
$::classname::varLeppige kokku, et nginx'i konfiguratsiooni tee asub muutuja $nginx_conf_source. Siis näeb klass välja järgmiselt:
class nginx_example {
package { 'nginx':
ensure => installed,
}
-> file { '/etc/nginx':
ensure => directory,
source => $nginx_conf_source, # siin kasutame muutuja asemel fikseeritud stringi
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
}Kuid antud näide on halb, kuna on mingi „salajane teadmine“, et klassis kasutatakse muuutjat teatud nimega. Oluliselt korrektsem on see teadmine jagada — klassidel võivad olla parameetrid.
Klassi parameetrid — need on muutujad klassi nimede ruumis, need määratakse klassi päises ja neid saab kasutada nagu tavalisi muutujaid klassi kehas. Parameetrite väärtused määratletakse klassi kasutamisel manifestis.
Parameetrile saab määrata vaikeväärtuse. Kui parameetril ei ole vaikeväärtust ja väärtust ei ole määratud klassi kasutamisel, põhjustab see kompileerimisviga.
Teeme eelmisel näitel klassi parameetriteks ja lisame kaks parameetrit: esimene, kohustuslik — konfiguratsioonitee, ja teine, valikuline — nginx'i paketi nimi (Debianis on näiteks pakette 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', # задаём параметры класса точно так же, как параметры для других ресурсов
}
}Puppetis on muutujad tüüpide järgi. On . Andmedüübid kasutatakse tavaliselt parameetrite väärtuste valideerimiseks, mis edastatakse klassidesse ja definitsioonidesse. Kui edastatud parameeter ei vasta määratud tüübile, toimub kompileerimisvea ilmnemine.
Tüüp kirjutatakse vahetult parameetri nime ette:
class example (
String $param1,
Integer $param2,
Array $param3,
Hash $param4,
Hash[String, String] $param5,
) {
...
}Klassid: include classname vs class{‘classname’:}
Iga klass on ressursi tüüp class. Nagu kõigi teiste ressursitüüpide puhul, ei tohi ühel sõlmel olla kaht identset klassi eksemplari.
Kui proovida lisada klass sama sõlme kaks korda, kasutades class { 'classname':} (olgu need erinevad või samad parameetrid), tekib kompileerimisviga. Kuid juhul, kui klassi kasutatakse ressursistiilis, saab kõiki selle parameetreid otse manifestis selgelt määrata.
Kuid kui kasutada include, siis saab klassi lisada nii palju kordi kui soovite. Asi on selles, et include — idempotentne funktsioon, mis kontrollib, kas klass on kataloogis olemas. Kui klassi kataloogis ei ole, lisab see selle, ja kui see on juba olemas, siis ei tee midagi. Kuid klassi defineerimise korral ei saa klassi parameetreid määrata klassi kuulutamise ajal — kõik kohustuslikud parameetrid peavad olema määratud välistest andmeallikatest — Hiera või ENC. Nendest räägime järgmises artiklis. include Definitsioonid
Kuna on juba mainitud, ei tohi sama klass olla sõlmes rohkem kui üks kord. Siiski on mõnel juhul vajalik rakendada sama koodiplokki erinevate parameetritega ühel sõlmel. Teisisõnu, on vajadus enda ressursitüübi järele.
Näiteks, et PHP moodulit installida, teeme Avitos järgmist:
Installeerime selle mooduli paketi.
- Loome selle mooduli konfigureerimisfaili.
- Loome sümboolsed lingid php-fpm konfigureerimisele.
- Loome sümboolsed lingid php cli konfigureerimisele.
- Sellistes olukordades kasutatakse sellist konstruktsiooni nagu
define $title , kuhu salvestatakse ressursi nimi selle kuulutamise ajal. Nagu klasside puhul, tuleb define'i kõigepealt kirjeldada, seejärel saab seda kasutada., kuhu ressurssi nimi läheb pärast selle deklareerimist. Nii nagu klasside puhul, tuleb defineerida kõigepealt, seejärel saab seda kasutada.
Lihtne 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'], # debian php pakettide trigged ise loovad sümbollingid ja taaskäivitavad php-fpm teenuse - see ei ole vajalik, kuna nii sümbollingid kui teenust haldame Puppetiga
}
=> 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' }
}Definitsioonis on kõige lihtsam tabada viga Duplicate declaration. See juhtub, kui definitsioonis on ressurss püsiva nimega ja mõnes sõlmes on kaks või enam selle definitsiooni eksemplari.
Kaitsmine selle eest on lihtne: kõik ressursid definitsiooni sees peavad olema nimed, mis sõltuvad , kuhu salvestatakse ressursi nimi selle kuulutamise ajal. Nagu klasside puhul, tuleb define'i kõigepealt kirjeldada, seejärel saab seda kasutada.. Alternatiivina - idempotentne ressursside lisamine, kõige lihtsama juhtumi korral on piisav, kui viia kõik definitsiooni eksemplaride jaoks ühised ressursid eraldi klassi ja lisada see klass definitsiooni - funktsioon include on idempotentne.
On ka teisi viise idempotentsuse saavutamiseks ressursside lisamisel, nimelt funktsioonide kasutamine defined ja ensure_resources, kuid sellest räägin järgmises osas.
Sõltuvused ja teatised klasside ja definitsioonide jaoks
Klassid ja definitsioonid lisavad järgmised reeglid sõltuvustest ja teadetest:
- sõltuvus klassi/definitsiooni puhul lisab sõltuvused kõigile klassi/definitsiooni ressurssidele;
- klass/definitsioon sõltuvus lisab sõltuvused kõikidele klassi/definitsiooni ressurssidele;
- klass/definitsiooni teatis teavitab kõiki klassi/definitsiooni ressursse;
- klass/definitsioonile registreerimine registreerib kõik klassi/definitsiooni ressursid.
Tingimuslikud operaatorid ja valikud
if
Siin on kõik lihtne:
if VYRASTUSED1 {
...
} elsif VYRASTUSED2 {
...
} else {
...
}kui_olemas
unless - see on if vastupidi: koodiblokk täidetakse, kui väljend on vale.
unless VYRASTUSED {
...
}case
Siin pole ka midagi keerulist. Väärtustena saab kasutada tavalisi väärtusi (stringid, numbrid jne), regulaaravaldisi ning ka andmetüüpe.
case VÄRJEND {
VÄÄRTUS1: { ... }
VÄÄRTUS2, VÄÄRTUS3: { ... }
default: { ... }
}Valijad
Valija on keelekonstruktsioon, mis sarnaneb case, kuid koodi blokeerimise täitmise asemel tagastab see väärtuse.
$var = $othervar ? { 'val1' => 1, 'val2' => 2, default => 3 }Moodulid
Kui konfiguratsioon on väike, on seda lihtne hoida ühes manifestis. Kuid mida rohkem konfiguratsiooni me kirjeldame, seda rohkem klasse ja sõlmi tekib manifestis, see kasvab ja selle kasutamine muutub ebamugavaks.
Lisaks on koodi taaskasutamiseks probleem – kui kogu kood on ühes manifestis, on sellega keeruline teistega jagada. Neid kahte probleemi lahendamiseks on Puppetis selline olemus nagu moodulid.
Moodulid – need on klasside, defineerimiste ja muude Puppet-olendite kogumid, mis on viidud eraldi kausta. Teisisõnu, moodul on sõltumatu tükk Puppet-loogikast. Näiteks võib olla moodul, mis töötleb nginx'iga, ja see sisaldab ainult seda, mis on vajalik töötamiseks nginx'iga, või võib olla moodul PHP töötlemiseks ja nii edasi.
Moodulid on versioonitud, samuti toetatakse moodulite sõltuvusi omavahel. On olemas avatud moodulite reponeerimine – .
Puppet-serveris asuvad moodulid juurkatalooge moodules. Iga mooduli sees on standardne katalooge struktuur – manifests, files, templates, lib ja edasi.
Moodli failide struktuur
Mooduli juures võivad olla järgmised kaustad, millel on kõlavad nimed:
manifests– selles asuvad manifestidfiles– selles asuvad failidtemplates– selles asuvad mallidlib– selles asub Ruby-kood
See ei ole kaustade ja failide täielik loetelu, kuid selle artikli jaoks piisab.
Ressursside nimed ja failide nimed moodulis
Mooduli ressursse (klassid, defineeringud) ei tohi nimetada kuidas iganes. Samuti on olemas otsene seos ressursi nime ja faili nime vahel, kus Puppet otsib selle ressursi kirjeldust. Kui nimetamisreegleid rikutakse, ei leia Puppet lihtsalt ressursside kirjeldust ja see toob kaasa kompileerimisvea.
Reeglid on lihtsad:
- Kõik mooduli ressursid peavad olema mooduli nimeregistris. Kui mooduli nimi on
foo, siis kõik ressursid selles peavad olema nimetatudfoo::, või lihtsaltfoo. - Mooduli nimega ressurss peab olema failis
init.pp. - Kõikide teiste ressursside failide nimetamise skeem on järgmine:
- mooduli nime eelosa jäetakse välja
- kõik kahekordsed koolonid, kui need on olemas, asendatakse kaldkriipsudega
- lisatakse siiski laiend
.pp
Demonstreerin näite abil. Oletame, et kirjutan mooduli nginx. Sellel on järgmised ressursid:
- klass
nginxmille kirjeldus on manifestisinit.pp; - klass
nginx::servicemille kirjeldus on manifestisservice.pp; - (define, defined type, defined resource type). Define on sarnane klassile, kuid on erinevusi: esiteks, iga define on ressursitüüp, mitte ressurss; teiseks, igal define'il on vaikimisi parameeter
nginx::servermille kirjeldus on manifestisserver.pp; - (define, defined type, defined resource type). Define on sarnane klassile, kuid on erinevusi: esiteks, iga define on ressursitüüp, mitte ressurss; teiseks, igal define'il on vaikimisi parameeter
nginx::server::locationmille kirjeldus on manifestisserver/location.pp.
Šablonid
Tõenäoliselt teate juba, mis on šablonid, ei hakka siinkohal pikalt seletama. Aga igaks juhuks jätan .
Kuidas šablone kasutada: šabloni väärtus võib välja tuua funktsiooni abil template, millele edastatakse tee šablonini. Ressursside tüüpide puhul file kasutatakse koos parameetriga content. Näiteks nii:
file { '/tmp/example': content => template('modulename/templatename.erb')Tee, mis on kujul / tähendab faili /modules//templates/.
Lisaks on olemas funktsioon inline_template — sellele antakse sisendiks šabloni tekst, mitte faili nimi.
Šablonites võib kasutada kõiki Puppet'i muutujaid praeguses ulatuses.
Puppet toetab šablone ERB ja EPP formaadis:
Lühidalt ERB-st
Kontrollstruktuurid:
<%= ВЫРАЖЕНИЕ %>— lisab väärtuse väljendist<% ВЫРАЖЕНИЕ %>— arvutab väljendi väärtuse (ilma, et seda sisestaks). Siia lähevad tavaliselt tingimusoperaatorid (if), tsüklid (each).<%# КОММЕНТАРИЙ %>
Väljendid ERB-s on kirjutatud Ruby's (tõepoolest, ERB — see on Embedded Ruby).
Muutujate ligipääsuks manifestist tuleb lisada @ muutuja nimele. Rida vahetamise eemaldamiseks, mis tekib pärast kontrollstruktuuri, tuleb kasutada sulgev märgendit -%>.
Šabloni kasutamise näide
Oletame, et kirjutan mooduli ZooKeeper'i haldamiseks. Klass, mis vastutab konfi loomise eest, näeb välja umbes selline:
class zookeeper::configure (\n Array[String] $nodes,\n Integer $port_client,\n Integer $port_quorum,\n Integer $port_leader,\n Hash[String, Any] $properties,\n String $datadir,\n) {\n file { '/etc/zookeeper/conf/zoo.cfg':\n ensure => present,\n content => template('zookeeper/zoo.cfg.erb'),\n }\n}Ja vastav šablon zoo.cfg.erb — on selline:
0 -%>\n\nserver.=:::\n\n\n\ndataDir=\n\n\n=\nFaktid ja sisemised muutujad
Sageli sõltub konkreetne konfiguratsiooni osa sellest, mis antud hetkel ühe noodi peal toimub. Näiteks sõltuvalt sellest, milline Debian'i versioon on paigaldatud, tuleb installida see või teine pakett. Võib seda kõike käsitsi jälgida, kirjutades manifeeste ümber noodi muutumise korral. Kuid see on tõsiseltvõetav lähenemine, automatiseerimine on palju parem.
Puppeti nodide kohta teabe saamiseks on olemas selline mehhanism nagu faktid. Faktid on teave noodi kohta, mis on manifeestides saadaval tavaliste globaalsete muutuja vormis. Näiteks hosti nimi, operatsioonisüsteemi versioon, protsessori arhitektuur, kasutajate nimekiri, võrgu- ja nende aadresside loend ning palju palju muud. Faktid on saadaval manifeestides ja mallides nagu tavalised muutuja.
Faktide näide:
notify { "Käivitamine OS ${facts['os']['name']} versioon ${facts['os']['release']['full']}": }
# notify tüüpi ressurss lihtsalt kuvab sõnumi logisseKui rääkida formaalselt, siis faktidel on nimi (string) ja väärtus (saadaval erinevad tüübid: stringid, massiivid, sõnastikud). On . Samuti saab kirjutada oma. Faktide kogujad on kirjeldatud , või nagu . Samuti võivad faktid olla esitatud noodidel.
Puppeti agent kopeerib esmalt Puppeti serverilt kõik saadaval olevad faktide kogujad noodi, seejärel käivitab need ja saadab kogutud faktid serverisse; alles pärast seda alustab server katalooge kompileerimist.
Käivitatavad failid faktidena
Sellised faktid paigutatakse moodulitesse katalooge facts.d. Loomulikult peavad failid olema käivitatavad. Käivitamisel peavad nad stdout'ile esitama teavet kas YAML-formaadis või 'võti=väärus' formaadis.
Ärge unustage, et faktid jagunevad kõigile nodidele, mis on Puppeti serveri all, kuhu teie moodul rakendatakse. Seetõttu kontrollige skriptis, et süsteemis oleks kõik vajalikud teie fakti töötamiseks programmid ja failid.
#!/bin/sh
echo "testfact=success"#!/bin/sh
echo '{"testyamlfact":"success"}'Faktid Ruby's
Sellised faktid paigutatakse moodulitesse katalooge 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
endTekstifaktid
Sellised faktid paigutatakse nodide katalooge /etc/facter/facts.d vana Puppeti või /etc/puppetlabs/facts.d uus Puppeti.
examplefact=examplevalue---
examplefact2: examplevalue2
anotherfact: anothervalueFaktide poole pöördumine
Faktidele saab pöörduda kahel viisil:
- sõnastiku kaudu
$facts:$facts['fqdn']; - kasutades fakti nime muutujana:
$fqdn.
Parim on kasutada sõnastikku $facts, veel parem on määrata globaalne nimiruum ($::facts).
Sisestatud muutujad
Faktide kõrval on veel , mis on saadaval globaalsetes nimiruumides.
- trusted facts — muutujad, mis saadakse kliendi sertifikaadist (kuna sertifikaadi väljastamine toimub tavaliselt puppet-serveris, ei saa agent lihtsalt oma sertifikaati muuta, seega on 'usaldusväärsed' muutujad): sertifikaadi nimi, hosti nimi ja domeen, laiendused sertifikaadist.
- server facts — muutujad, mis on seotud serveri teabega — versioon, nimi, serveri IP-aadress, keskkond.
- agent facts — muutujad, mis lisatakse otse puppet-agenti poolt, mitte facter'i poolt — sertifikaadi nimi, agendi versioon, puppeti versioon.
- master variables — puppetmasteri muutujad (sic!). Seal on umbes sama, mis server facts, pluss konfiguratsiooniparametrite väärtused.
- compiler variables — kompilaatori muutujad, mis erinevad igas ulatuses: käimasoleva mooduli nimi ja mooduli nimi, milles toimetati praeguse objekti juurde. Neid saab kasutada näiteks, et kontrollida, et teie privaatsed klassid ei kasutaks otse teistest moodulitest.
Lisa 1: kuidas seda kõike käivitada ja siluda?
Artiklis oli palju puppet-koodi näiteid, kuid ei räägitud, kuidas seda koodi käivitada. Noh, ma parandaksin end.
Puppet'i jaoks on piisavalt agenti, kuid enamikul juhtudel on vajalik ka server.
Agent
Alates viiendast versioonist sisaldavad puppet-agent'i paketid kõiki sõltuvusi (ruby ja vastavad gem'id), seega ei tohiks installimisega palju probleeme olla (ma räägin Debian-põhistest jaotustest — RPM-põhiseid jaotusi me ei kasuta).
Lihtsaimatel juhtudel piisab puppet-konfiguratsiooni rakendamiseks agendi käivitamisest serverivabas režiimis: tingimusel, et puppet-kood on node'ile kopeeritud, 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 secondsParim kindlasti käivitada server ja lasta agentidel nodides daemon-režiimis töötada — siis nad rakendavad konfiguratsiooni, mis serverist alla laaditud, iga poole tunni tagant.
Sa saad simuleerida push-mudelit — mine soovitud nodi ja käivita sudo puppet agent -t. Võti -t (--test) sisaldab tegelikult mitmeid valikuid, mida saab eraldi sisse lülitada. Nende valikute hulka kuuluvad:
- mitte töötada daemon-režiimis (vaikimisi agent käivitub daemon-režiimis);
- lõpetada töö pärast katalooge rakendamist (vaikimisi agent jätkab tööd ja rakendab konfiguratsiooni iga poole tunni tagant);
- kirjutada üksikasjalikku logi;
- näidata muudatusi failides.
Agendil on teie muudatusteta töörežiim — seda saab kasutada, kui te pole kindel, et olete õigesti kirjutanud konfiguratsiooni, ja soovite kontrollida, mida agent tegelikult tööl teeb. See režiim aktiveeritakse parameetriga --noop komandoreas: sudo puppet agent -t --noop.
Lisaks saab aktiveerida tõrkeotsingu logimise — seal kirjutab puppet kõigist tegevustest, mida ta teostab: ressursist, mida ta hetkel töötleb, selle ressursi parameetritest, milliseid programme ta käivitab. Loomulikult on see parameeter --debug.
Server
Puppetserveri täielikku seadistamist ja koodi sellele juurutamist ei hakka ma selles artiklis käsitlema, ütlen vaid, et kastist väljalaske versioon serverist, mis ei vaja ulatuslikku seadistamist väikese hulga nodide (ütleme, kuni saja) korral töötab täiesti. Suurem nodide arv nõuab juba häälestamist — vaikimisi puppetserver ei käivita rohkem kui nelja töölist, suurema jõudluse saavutamiseks tuleb nende arvu suurendada ja ärge unustage suurendada mälu piire, vastasel juhul kulutab server suure osa ajast garbage collect’imisele.
Koodi juurutamiseks — kui on vaja kiiresti ja lihtsalt, vaadake (r10k)[], väikeste installatsioonide jaoks peaks seda piisama.
Täiendav 2: soovitused koodi kirjutamiseks
- Viige kogu loogika klassidesse ja defineerimisse.
- Hoida klassid ja defineerimised moodulites, mitte sõlmede kirjeldustega manifestides.
- Kasutage fakte.
- Ärge tehke if'e hostinimede põhjal.
- Ärge kartke lisada parameetreid klasside ja defineerimiste jaoks — see on parem kui varjatud loogika kasutamine klassi/defineeringu kehas.
Miks ma soovitan seda teha — selgitan järgmises artiklis.
Kokkuvõte
Siin lõpetame sissejuhatuse. Järgmises artiklis räägin Hiera, ENC ja PuppetDB-st.
Ainult registreeritud kasutajad saavad küsitluses osaleda. , palun.
Tegelikult on materjali palju rohkem — ma saan kirjutada artikleid järgmiste teemade kohta, hääletage, millest te sooviksite lugeda:
- 59,1%Täiendavad puppet koostrukt sooned — mõned järgmise taseme asjad: tsüklid, kaardistamine ja muud lambda väljendid, ressursside kollektorid, eksporditavad ressursid ja hostide vahelised suhted Puppetis, sildid, pakkujad, abstraktsed andmetüübid.
- 31,8%"Ma olen emme admin" või kuidas me Avitos sõbrustasime erinevate versioonidega puppet-serveritega, ja üldiselt osa puppet-serveri haldamisest.
- 81,8%Kuidas me kirjutame puppet koodi: tööriistade lisamine, dokumentatsioon, testimine, CI/CD.
Hääletas 22 kasutajat. 9 kasutajat jäid erapooletuks.
Allikas: habr.com
