A Puppet egy konfigurációkezelő rendszer. Arra használják, hogy a gazdagépeket a kívánt állapotba hozzák, és ezt az állapotot fenntartsák.
Már több mint öt éve dolgozom a Puppettel. Ez a szöveg lényegében a hivatalos dokumentáció legfontosabb pontjainak lefordított és újrarendezett összeállítása, amely lehetővé teszi a kezdőknek, hogy gyorsan megértsék a Puppet lényegét.
Alapinformációk
A Puppet operációs rendszere kliens-szerver, bár korlátozott funkcionalitással támogatja a szerver nélküli működést is.
Lehívási modellt használnak: alapértelmezés szerint félóránként egyszer felveszik a kapcsolatot a szerverrel a konfigurációért, és alkalmazzák azt. Ha az Ansible-vel dolgozott, akkor más push modellt használnak: az adminisztrátor kezdeményezi a konfiguráció alkalmazásának folyamatát, a kliensek maguk nem alkalmaznak semmit.
A hálózati kommunikáció során kétirányú TLS-titkosítást alkalmaznak: a szervernek és a kliensnek saját privát kulcsa és megfelelő tanúsítványa van. Jellemzően a szerver ad ki tanúsítványokat az ügyfelek számára, de elvileg lehetőség van külső CA használatára is.
Bevezetés a kiáltványokba
A Puppet terminológiában a bábszerverre csatlakozni csomópontok (csomópontok). A csomópontok konfigurációja meg van írva kiáltványokban speciális programozási nyelven - Puppet DSL.
A Puppet DSL egy deklaratív nyelv. Leírja a csomópont kívánt állapotát az egyes erőforrások deklarációi formájában, például:
- A fájl létezik, és meghatározott tartalommal rendelkezik.
- A csomag telepítve van.
- A szolgáltatás elindult.
Az erőforrások összekapcsolhatók:
- Vannak függőségek, ezek befolyásolják az erőforrások felhasználási sorrendjét.
Például: „először telepítse a csomagot, majd szerkessze a konfigurációs fájlt, majd indítsa el a szolgáltatást”. - Vannak értesítések – ha egy erőforrás megváltozott, értesítést küld a rá előfizetett erőforrásoknak.
Például, ha a konfigurációs fájl megváltozik, automatikusan újraindíthatja a szolgáltatást.
Ezenkívül a Puppet DSL rendelkezik függvényekkel és változókkal, valamint feltételes utasításokkal és kiválasztókkal. Különféle sablonozási mechanizmusok is támogatottak – EPP és ERB.
A Puppet Ruby nyelven íródott, ezért sok konstrukció és kifejezés onnan származik. A Ruby lehetővé teszi a Puppet bővítését - összetett logikát, új típusú erőforrásokat, funkciókat ad hozzá.
Amíg a Puppet fut, a kiszolgáló minden egyes csomópontjához tartozó manifesztek egy könyvtárba fordítódnak. Каталог Az erőforrások és kapcsolataik listája a függvények, változók értékének kiszámítása és a feltételes utasítások kiterjesztése után.
Szintaxis és kódstílus
Íme a hivatalos dokumentáció részei, amelyek segítenek megérteni a szintaxist, ha a megadott példák nem elegendőek:
Íme egy példa a jegyzék kinézetére:
# Комментарии пишутся, как и много где, после решётки.
#
# Описание конфигурации ноды начинается с ключевого слова node,
# за которым следует селектор ноды — хостнейм (с доменом или без)
# или регулярное выражение для хостнеймов, или ключевое слово default.
#
# После этого в фигурных скобках описывается собственно конфигурация ноды.
#
# Одна и та же нода может попасть под несколько селекторов. Про приоритет
# селекторов написано в статье про синтаксис описания нод.
node 'hostname', 'f.q.d.n', /regexp/ {
# Конфигурация по сути является перечислением ресурсов и их параметров.
#
# У каждого ресурса есть тип и название.
#
# Внимание: не может быть двух ресурсов одного типа с одинаковыми названиями!
#
# Описание ресурса начинается с его типа. Тип пишется в нижнем регистре.
# Про разные типы ресурсов написано ниже.
#
# После типа в фигурных скобках пишется название ресурса, потом двоеточие,
# дальше идёт опциональное перечисление параметров ресурса и их значений.
# Значения параметров указываются через т.н. hash rocket (=>).
resource { 'title':
param1 => value1,
param2 => value2,
param3 => value3,
}
}
A behúzás és a sortörés nem kötelező része a jegyzéknek, de van egy ajánlott
- Két szóközű behúzás, tabulátor nem használatos.
- A göndör kapcsos zárójeleket szóköz választja el, a kettőspontokat nem választja el szóköz.
- Vessző minden paraméter után, beleértve az utolsót is. Minden paraméter külön sorban van. Kivételt képez a paraméter nélküli és egy paraméter nélküli eset: írhat egy sorba és vessző nélkül (pl.
resource { 'title': }
иresource { 'title': param => value }
). - A paramétereken lévő nyilaknak azonos szinten kell lenniük.
- Előtte az erőforrás-kapcsolat nyilak vannak írva.
Fájlok helye a pappetszerveren
További magyarázatként bemutatom a „gyökérkönyvtár” fogalmát. A gyökérkönyvtár az a könyvtár, amely egy adott csomópont Bábkonfigurációját tartalmazza.
A gyökérkönyvtár a Puppet verziójától és a használt környezetektől függően változik. A környezetek független konfigurációs halmazok, amelyek külön könyvtárakban vannak tárolva. Általában a git-tel együtt használják, ebben az esetben a környezetek git-ágakból jönnek létre. Ennek megfelelően minden csomópont egy vagy másik környezetben helyezkedik el. Ez konfigurálható magán a csomóponton, vagy az ENC-ben, amiről a következő cikkben fogok beszélni.
- A harmadik verzióban ("old Puppet") az alapkönyvtár volt
/etc/puppet
. A környezetek használata nem kötelező – például a régi Puppetnél nem használjuk őket. Ha környezetet használnak, általában tárolják azokat/etc/puppet/environments
, a gyökérkönyvtár a környezeti könyvtár lesz. Ha nem használ környezeteket, akkor a gyökérkönyvtár lesz az alapkönyvtár. - A negyedik verziótól („új Puppet”) a környezetek használata kötelezővé vált, az alapkönyvtár átkerült a
/etc/puppetlabs/code
. Ennek megfelelően a környezetek tárolódnak/etc/puppetlabs/code/environments
, a gyökérkönyvtár a környezeti könyvtár.
A gyökérkönyvtárban kell lennie egy alkönyvtárnak manifests
, amely egy vagy több, a csomópontokat leíró manifestet tartalmaz. Ezen kívül kell lennie egy alkönyvtárnak modules
, amely a modulokat tartalmazza. Kicsit később elmondom, hogy milyen modulok vannak. Ezenkívül a régi Puppet-nek is lehet alkönyvtára files
, amely különféle fájlokat tartalmaz, amelyeket a csomópontokba másolunk. Az új Puppetben minden fájl modulokba kerül.
A jegyzékfájlok a kiterjesztéssel rendelkeznek .pp
.
Pár harci példa
A csomópont és a rajta lévő erőforrás leírása
A csomóponton server1.testdomain
fájlt kell létrehozni /etc/issue
tartalommal Debian GNU/Linux n l
. A fájlnak egy felhasználónak és egy csoportnak kell lennie root
, hozzáférési jogoknak kell lenniük 644
.
Kiáltványt írunk:
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 в начале будет воспринято как записанное в восьмеричной системе, и всё пойдёт не так, как задумано
}
}
Egy csomóponton lévő erőforrások közötti kapcsolatok
A csomóponton server2.testdomain
Az nginx-nek futnia kell, és egy korábban elkészített konfigurációval kell működnie.
Bontsuk fel a problémát:
- A csomagot telepíteni kell
nginx
. - Szükséges a konfigurációs fájlok másolása a szerverről.
- A szolgáltatásnak futnia kell
nginx
. - Ha a konfiguráció frissül, a szolgáltatást újra kell indítani.
Kiáltványt írunk:
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 получает уведомление,
# соответствующий сервис перезапускается.
}
Ahhoz, hogy ez működjön, körülbelül a következő fájlhelyre van szüksége a bábszerveren:
/etc/puppetlabs/code/environments/production/ # (это для нового Паппета, для старого корневой директорией будет /etc/puppet)
├── manifests/
│ └── site.pp
└── modules/
└── example/
└── files/
└── nginx-conf/
├── nginx.conf
├── mime.types
└── conf.d/
└── some.conf
Erőforrás típusok
A támogatott erőforrástípusok teljes listája itt található
filé
Fájlokat, könyvtárakat, szimbolikus hivatkozásokat, azok tartalmát és hozzáférési jogait kezeli.
lehetőségek:
- erőforrás neve - a fájl elérési útja (opcionális)
- ösvény - a fájl elérési útja (ha nincs megadva a névben)
- biztosítására - fájltípus:
absent
- fájl törlésepresent
- bármilyen típusú fájlnak kell lennie (ha nincs fájl, akkor egy normál fájl jön létre)file
- normál fájldirectory
- Könyvtárlink
- szimbolikus link
- tartalom — fájltartalom (csak normál fájlokhoz alkalmas, nem használható együtt forrás vagy cél)
- forrás - hivatkozás arra az elérési útra, ahonnan a fájl tartalmát másolni szeretné (nem használható együtt tartalom vagy cél). Megadható URI-ként egy sémával
puppet:
(akkor a bábszerver fájljai kerülnek felhasználásra), és a sémávalhttp:
(Remélem, világos, hogy ebben az esetben mi fog történni), és még a diagrammal isfile:
vagy abszolút elérési útként séma nélkül (akkor a csomópont helyi FS fájlja kerül felhasználásra) - cél — ahová a szimbolikus hivatkozásnak mutatnia kell (nem használható együtt tartalom vagy forrás)
- tulajdonos — az a felhasználó, akinek a fájl tulajdonosa
- csoport — a csoport, amelyhez a fájlnak tartoznia kell
- üzemmód - fájlengedélyek (karakterláncként)
- visszatérő - lehetővé teszi a rekurzív címtárfeldolgozást
- tisztítás - lehetővé teszi olyan fájlok törlését, amelyek nincsenek leírva a Puppetnél
- kényszeríteni - lehetővé teszi olyan könyvtárak törlését, amelyek nincsenek leírva a Puppetben
csomag
Telepíti és eltávolítja a csomagokat. Képes kezelni az értesítéseket - újratelepíti a csomagot, ha a paraméter meg van adva reinstall_on_refresh.
lehetőségek:
- erőforrás neve – csomag neve (nem kötelező)
- név - csomag neve (ha a névben nincs megadva)
- ellátó - csomagkezelő használata
- biztosítására — a csomag kívánt állapota:
present
,installed
- bármely telepített verziólatest
- a legújabb verzió telepítveabsent
- törölve (apt-get remove
)purged
– törölve a konfigurációs fájlokkal együtt (apt-get purge
)held
- a csomag verziója zárolva van (apt-mark hold
)любая другая строка
— a megadott verzió telepítve van
- reinstall_on_refresh - Ha egy
true
, akkor az értesítés kézhezvétele után a csomag újratelepítésre kerül. Hasznos forrás alapú disztribúciókhoz, ahol újraépítésre lehet szükség az összeállítási paraméterek megváltoztatásakor. Alapértelmezettfalse
.
szolgáltatás
Kezeli a szolgáltatásokat. Képes az értesítések feldolgozására - újraindítja a szolgáltatást.
lehetőségek:
- erőforrás neve – kezelendő szolgáltatás (opcionális)
- név — a kezelendő szolgáltatás (ha a névben nincs megadva)
- biztosítására — a szolgáltatás kívánt állapota:
running
- indítottstopped
- megállt
- lehetővé — szabályozza a szolgáltatás indításának lehetőségét:
true
- az automatikus indítás engedélyezve van (systemctl enable
)mask
- rejtett (systemctl mask
)false
- az automatikus indítás le van tiltva (systemctl disable
)
- újraindítás - parancs a szolgáltatás újraindításához
- állapot — parancs a szolgáltatás állapotának ellenőrzésére
- újra kell indítani — jelzi, hogy a szolgáltatás initscript támogatja-e az újraindítást. Ha
false
és a paraméter megadva újraindítás — ennek a paraméternek az értéke kerül felhasználásra. Hafalse
és paraméter újraindítás nincs megadva - a szolgáltatás leáll és újraindul (de a systemd a parancsot használjasystemctl restart
). - hasstatus — jelzi, hogy a szolgáltatás initscript támogatja-e a parancsot
status
... Hafalse
, akkor a paraméter értéke kerül felhasználásra állapot. Alapértelmezetttrue
.
exec
Külső parancsokat futtat. Ha nem ad meg paramétereket teremt, csak ha, hacsak nem vagy üdítően, a parancs minden alkalommal lefut, amikor a Puppet fut. Képes az értesítések feldolgozására – parancsot futtat.
lehetőségek:
- erőforrás neve - végrehajtandó parancs (opcionális)
- parancs - a végrehajtandó parancs (ha a névben nincs megadva)
- ösvény — elérési utak, amelyekben a végrehajtható fájlt meg kell keresni
- csak ha — ha az ebben a paraméterben megadott parancs nulla visszatérési kóddal fejeződött be, a főparancs végrehajtásra kerül
- hacsak nem — ha az ebben a paraméterben megadott parancs nullától eltérő visszatérési kóddal fejeződött be, akkor a főparancs végrehajtásra kerül
- teremt — ha az ebben a paraméterben megadott fájl nem létezik, a főparancs végrehajtásra kerül
- üdítően - Ha egy
true
, akkor a parancs csak akkor fut le, ha ez a végrehajtó értesítést kap más erőforrásoktól - cwd — könyvtár, ahonnan a parancs fut
- használó — a felhasználó, akitől a parancsot futtatni kell
- ellátó - hogyan kell futtatni a parancsot:
- posix — egy gyermekfolyamat egyszerűen létrejön, feltétlenül adja meg ösvény
- héj - a parancs elindul a shellben
/bin/sh
, nem adható meg ösvény, használhat gömbölyűt, csöveket és egyéb héjfunkciókat. Általában automatikusan észleli, ha vannak speciális karakterek (|
,;
,&&
,||
stb).
cron
Vezérli a cronjobokat.
lehetőségek:
- erőforrás neve - csak valami azonosító
- biztosítására — crownjob állam:
present
- létrehozni, ha nem létezikabsent
- törölni, ha létezik
- parancs - milyen parancsot kell futtatni
- környezet - melyik környezetben futtassa a parancsot (környezeti változók listája és értékeik ezen keresztül
=
) - használó — melyik felhasználótól futtassa a parancsot
- perc, óra, hétköznap, hónap, hónap nap — mikor kell cront futtatni. Ha ezen attribútumok bármelyike nincs megadva, akkor annak értéke a crontabban lesz
*
.
A Puppet 6.0-ban cron mintha
Az erőforrásokról általában
Az erőforrás egyediségének követelményei
A leggyakoribb hiba, amellyel szembesülünk Ismétlődő nyilatkozat. Ez a hiba akkor fordul elő, ha két vagy több azonos típusú, azonos nevű erőforrás jelenik meg a könyvtárban.
Ezért újra leírom: ugyanazon csomóponthoz tartozó manifesztek nem tartalmazhatnak azonos típusú erőforrásokat azonos címmel!
Néha szükség van azonos nevű, de különböző csomagkezelőkkel rendelkező csomagok telepítésére. Ebben az esetben a paramétert kell használni name
a hiba elkerülése érdekében:
package { 'ruby-mysql':
ensure => installed,
name => 'mysql',
provider => 'gem',
}
package { 'python-mysql':
ensure => installed,
name => 'mysql',
provider => 'pip',
}
Más erőforrástípusok hasonló opciókkal rendelkeznek a duplikáció elkerülése érdekében − name
у szolgáltatás, command
у exec, stb.
Metaparaméterek
Minden erőforrástípusnak van néhány speciális paramétere, természetétől függetlenül.
A meta paraméterek teljes listája
Rövid lista:
- szükség — ez a paraméter azt jelzi, hogy ez az erőforrás mely erőforrásoktól függ.
- előtt - Ez a paraméter határozza meg, hogy mely erőforrások függenek ettől az erőforrástól.
- Iratkozz fel — ez a paraméter határozza meg, hogy az erőforrás mely erőforrásoktól kap értesítéseket.
- értesít — Ez a paraméter határozza meg, hogy mely erőforrások kapjanak értesítést ettől az erőforrástól.
A felsorolt metaparaméterek mindegyike egyetlen erőforráshivatkozást vagy szögletes zárójelben lévő hivatkozások tömbjét fogadja el.
Hivatkozások a forrásokhoz
Az erőforráshivatkozás egyszerűen az erőforrás említése. Főleg a függőségek jelzésére szolgálnak. Nem létező erőforrásra való hivatkozás fordítási hibát okoz.
A hivatkozás szintaxisa a következő: erőforrás típusa nagybetűvel (ha a típusnév kettős kettőspontot tartalmaz, akkor a kettőspontok közötti név minden része nagybetűs), majd az erőforrás neve szögletes zárójelben (a név kis- és nagybetűje nem változik!). Szóköz ne legyen, közvetlenül a típusnév után szögletes zárójelet kell írni.
Példa:
file { '/file1': ensure => present }
file { '/file2':
ensure => directory,
before => File['/file1'],
}
file { '/file3': ensure => absent }
File['/file1'] -> File['/file3']
Függőségek és értesítések
Mint korábban említettük, az erőforrások közötti egyszerű függőségek tranzitívak. Amúgy legyen óvatos a függőségek hozzáadásakor – ciklikus függőséget is létrehozhat, ami fordítási hibát okoz.
A függőségekkel ellentétben az értesítések nem átmenetiek. Az értesítésekre a következő szabályok vonatkoznak:
- Ha az erőforrás értesítést kap, akkor frissítésre kerül. A frissítési műveletek az erőforrás típusától függenek − exec futtatja a parancsot, szolgáltatás újraindítja a szolgáltatást, csomag újratelepíti a csomagot. Ha az erőforráshoz nincs megadva frissítési művelet, akkor semmi sem történik.
- A Puppet egy futtatása során az erőforrás legfeljebb egyszer frissül. Ez azért lehetséges, mert az értesítések függőségeket tartalmaznak, a függőségi gráf pedig nem tartalmaz ciklusokat.
- Ha a Puppet megváltoztatja egy erőforrás állapotát, az erőforrás értesítést küld az összes előfizetett erőforrásnak.
- Ha egy erőforrás frissül, értesítést küld az összes előfizetett erőforrásnak.
Meghatározatlan paraméterek kezelése
Általános szabály, hogy ha néhány erőforrás-paraméternek nincs alapértelmezett értéke, és ez a paraméter nincs megadva a jegyzékben, akkor a Puppet nem módosítja ezt a tulajdonságot a csomópont megfelelő erőforrásához. Például, ha egy típusú erőforrás filé paraméter nincs megadva owner
, akkor a Puppet nem módosítja a megfelelő fájl tulajdonosát.
Bevezetés az osztályokba, változókba és definíciókba
Tegyük fel, hogy több csomópontunk van, amelyeknek ugyanaz a konfiguráció része, de vannak különbségek is - különben leírhatnánk az egészet egy blokkban node {}
. Természetesen egyszerűen másolhatja a konfiguráció azonos részeit, de általában ez egy rossz megoldás - a konfiguráció nő, és ha megváltoztatja a konfiguráció általános részét, akkor sok helyen ugyanazt kell szerkesztenie. Ugyanakkor könnyű hibázni, és általában a SZÁRAZ (ne ismételd magad) elvet okkal találták ki.
A probléma megoldására van egy olyan kialakítás, mint osztály.
osztályok
Először is le kell írni az osztályt. Maga a leírás nem ad hozzá semmilyen forrást sehol. Az osztály leírása a manifesztekben:
# Описание класса начинается с ключевого слова class и его названия.
# Дальше идёт тело класса в фигурных скобках.
class example_class {
...
}
Ezt követően az osztály használható:
# первый вариант использования — в стиле ресурса с типом class
class { 'example_class': }
# второй вариант использования — с помощью функции include
include example_class
# про отличие этих двух вариантов будет рассказано дальше
Példa az előző feladatból - helyezzük át az nginx telepítését és konfigurálását egy osztályba:
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
}
Változók
Az előző példa osztálya egyáltalán nem rugalmas, mert mindig ugyanazt az nginx konfigurációt hozza. Tegyük meg a konfigurációs változó elérési útját, akkor ez az osztály használható az nginx telepítésére bármilyen konfigurációval.
Meg lehet csinálni
Figyelem: a Puppet változói megváltoztathatatlanok!
Ráadásul egy változóhoz csak deklarálás után lehet hozzáférni, különben a változó értéke lesz undef
.
Példa a változókkal való munkára:
# создание переменных
$variable = 'value'
$var2 = 1
$var3 = true
$var4 = undef
# использование переменных
$var5 = $var6
file { '/tmp/text': content => $variable }
# интерполяция переменных — раскрытие значения переменных в строках. Работает только в двойных кавычках!
$var6 = "Variable with name variable has value ${variable}"
Bábnak van névterek, és a változók ennek megfelelően rendelkeznek láthatósági terület: Az azonos nevű változót különböző névterekben lehet meghatározni. Egy változó értékének feloldásakor a változót az aktuális névtérben keresi, majd a befoglaló névtérben, és így tovább.
Példák névtérre:
- globális - az osztály- vagy csomópontleíráson kívüli változók oda mennek;
- csomópont névtér a csomópont leírásában;
- osztály névterét az osztályleírásban.
A kétértelműség elkerülése érdekében a változó elérésekor megadhatja a névteret a változó nevében:
# переменная без пространства имён
$var
# переменная в глобальном пространстве имён
$::var
# переменная в пространстве имён класса
$classname::var
$::classname::var
Egyezzünk meg abban, hogy az nginx konfiguráció elérési útja a változóban található $nginx_conf_source
. Akkor az osztály így fog kinézni:
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
}
A megadott példa azonban rossz, mert van némi „titkos tudás”, hogy valahol az osztályon belül egy ilyen és ilyen nevű változót használnak. Sokkal helyesebb ezt a tudást általánossá tenni - az osztályoknak lehetnek paraméterei.
Osztály paraméterei változók az osztály névterében, az osztály fejlécében vannak megadva, és az osztály törzsében szokásos változókhoz hasonlóan használhatók. A paraméterértékek az osztály használatakor vannak megadva a jegyzékben.
A paraméter alapértelmezett értékre állítható. Ha egy paraméternek nincs alapértelmezett értéke, és az érték nincs beállítva használat közben, az fordítási hibát okoz.
Paraméterezzük az osztályt a fenti példából, és adjunk hozzá két paramétert: az első kötelező a konfiguráció elérési útja, a második pedig nem kötelező az nginx csomag neve (pl. Debianban vannak csomagok 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', # задаём параметры класса точно так же, как параметры для других ресурсов
}
}
A Puppetben a változók be vannak írva. Eszik
A típus közvetlenül a paraméter neve elé kerül:
class example (
String $param1,
Integer $param2,
Array $param3,
Hash $param4,
Hash[String, String] $param5,
) {
...
}
Osztályok: include classname vs class{'classname':}
Minden osztály egy típusú erőforrás osztály. Mint minden más típusú erőforrás esetében, ugyanazon a csomóponton nem lehet ugyanannak az osztálynak két példánya.
Ha kétszer próbál meg hozzáadni egy osztályt ugyanahhoz a csomóponthoz class { 'classname':}
(nincs különbség, eltérő vagy azonos paraméterekkel), fordítási hiba lesz. De ha erőforrásstílusban használ egy osztályt, azonnal beállíthatja az összes paraméterét a jegyzékben.
Ha azonban használ include
, akkor az osztály tetszőleges számú alkalommal hozzáadható. A tény az, hogy include
egy idempotens függvény, amely ellenőrzi, hogy egy osztály hozzáadva van-e a könyvtárhoz. Ha az osztály nincs a könyvtárban, akkor hozzáadja, és ha már létezik, akkor nem csinál semmit. De használat esetén include
Osztálydeklaráció során nem lehet osztályparamétereket beállítani – minden szükséges paramétert külső adatforrásban – Hiera vagy ENC – kell beállítani. A következő cikkben róluk fogunk beszélni.
Meghatározza
Ahogy az előző blokkban elhangzott, ugyanaz az osztály nem lehet többször jelen egy csomóponton. Bizonyos esetekben azonban ugyanazt a kódblokkot különböző paraméterekkel kell tudnia használni ugyanazon a csomóponton. Más szóval, szükség van egy saját erőforrástípusra.
Például a PHP modul telepítéséhez a következőket tesszük az Avitóban:
- Telepítse a csomagot ezzel a modullal.
- Hozzon létre egy konfigurációs fájlt ehhez a modulhoz.
- Létrehozunk egy szimbolikus hivatkozást a php-fpm konfigurációjához.
- Létrehozunk egy szimbolikus hivatkozást a php cli konfigurációjához.
Ilyen esetekben egy olyan kialakítás, mint pl $title
, ahová az erőforrás neve kerül deklaráláskor. Csakúgy, mint az osztályok esetében, először le kell írni egy definíciót, amely után használható.
Egy egyszerűsített példa egy PHP modullal:
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' }
}
A Duplicate deklarációs hiba legegyszerűbb módja a Define. Ez akkor fordul elő, ha a definícióban van egy állandó nevű erőforrás, és ennek a definíciónak két vagy több példánya van valamelyik csomóponton.
Könnyű megvédeni magát ettől: a definíción belül minden erőforrásnak nevet kell adni, attól függően $title
. Alternatíva az erőforrások idempotens hozzáadása, a legegyszerűbb esetben elegendő a definíció összes példányára közös erőforrásokat egy külön osztályba áthelyezni, és ezt az osztályt a definíció - függvénybe foglalni. include
idempotens.
Vannak más módok is az idempotencia elérésére erőforrások hozzáadásakor, nevezetesen függvények használatával defined
и ensure_resources
, de erről a következő részben mesélek.
Függőségek és értesítések osztályokhoz és definíciókhoz
Az osztályok és definíciók a következő szabályokkal egészítik ki a függőségek és értesítések kezelését:
- függőség egy osztálytól/definiálástól függőségeket ad az osztály/define összes erőforrásához;
- egy osztály/definiált függőség függőséget ad az összes osztály/definiált erőforráshoz;
- class/define értesítés értesíti az osztály/define összes erőforrását;
- class/define előfizetés a class/define összes erőforrására előfizet.
Feltételes állítások és szelektorok
if
Itt minden egyszerű:
if ВЫРАЖЕНИЕ1 {
...
} elsif ВЫРАЖЕНИЕ2 {
...
} else {
...
}
hacsak nem
hacsak nem az if fordított: a kódblokk végrehajtásra kerül, ha a kifejezés hamis.
unless ВЫРАЖЕНИЕ {
...
}
eset
Itt sincs semmi bonyolult. Értékként használhat reguláris értékeket (karakterláncok, számok stb.), reguláris kifejezéseket és adattípusokat.
case ВЫРАЖЕНИЕ {
ЗНАЧЕНИЕ1: { ... }
ЗНАЧЕНИЕ2, ЗНАЧЕНИЕ3: { ... }
default: { ... }
}
Kiválasztók
A szelektor egy nyelvi konstrukció, amelyhez hasonló case
, de egy kódblokk végrehajtása helyett egy értéket ad vissza.
$var = $othervar ? { 'val1' => 1, 'val2' => 2, default => 3 }
modulok
Ha a konfiguráció kicsi, könnyen tárolható egy manifestben. De minél több konfigurációt írunk le, annál több osztály és csomópont van a manifestben, az növekszik, és kényelmetlenné válik vele dolgozni.
Ezenkívül felmerül a kód újrafelhasználásának problémája – ha az összes kód egy jegyzékben van, nehéz megosztani ezt a kódot másokkal. E két probléma megoldására a Puppet rendelkezik egy modulok nevű entitással.
modulok - ezek osztályok, definíciók és egyéb Puppet entitások egy külön könyvtárban elhelyezett halmazai. Más szóval, a modul a Puppet logika független része. Például lehet egy modul az nginx-szel való munkához, és azt fogja tartalmazni, ami és csak az nginx-szel való munkához szükséges, vagy lehet egy modul a PHP-vel való munkához stb.
A modulok verziózottak, és a modulok egymáshoz való függősége is támogatott. Van egy nyitott modultár -
A bábszerveren a modulok a gyökérkönyvtár modules alkönyvtárában találhatók. Minden modulon belül van egy szabványos könyvtárséma - manifestek, fájlok, sablonok, lib stb.
Fájlszerkezet egy modulban
A modul gyökere a következő leíró nevű könyvtárakat tartalmazhatja:
manifests
- kiáltványokat tartalmazfiles
- fájlokat tartalmaztemplates
- sablonokat tartalmazlib
— Ruby kódot tartalmaz
Ez nem a könyvtárak és fájlok teljes listája, de ehhez a cikkhez egyelőre elegendő.
Erőforrások és fájlok nevei a modulban
Egy modulban lévő erőforrások (osztályok, definíciók) nem nevezhetők tetszés szerint. Ezenkívül közvetlen összefüggés van egy erőforrás neve és annak a fájlnak a neve között, amelyben a Puppet az adott erőforrás leírását keresi. Ha megsérti az elnevezési szabályokat, akkor a Puppet egyszerűen nem találja meg az erőforrás leírását, és fordítási hibát kap.
A szabályok egyszerűek:
- A modulban lévő összes erőforrásnak a modul névterében kell lennie. Ha a modult meghívjuk
foo
, akkor minden benne lévő erőforrást meg kell neveznifoo::<anything>
, vagy csakfoo
. - A modul nevű erőforrásnak szerepelnie kell a fájlban
init.pp
. - Más erőforrások esetében a fájl elnevezési séma a következő:
- a modulnévvel ellátott előtag el lesz vetve
- az összes kettős kettőspontot, ha van, perjelekre cseréljük
- bővítmény hozzáadásra kerül
.pp
Egy példával mutatom be. Tegyük fel, hogy modult írok nginx
. A következő forrásokat tartalmazza:
- osztály
nginx
a manifesztben leírtakinit.pp
; - osztály
nginx::service
a manifesztben leírtakservice.pp
; - meghatározni
nginx::server
a manifesztben leírtakserver.pp
; - meghatározni
nginx::server::location
a manifesztben leírtakserver/location.pp
.
sablonok
Bizonyára Ön is tudja, mik azok a sablonok; itt nem írom le őket részletesen. De minden esetre otthagyom
A sablonok használata: A sablon jelentése függvény segítségével bővíthető template
, amely átadja a sablon elérési útját. típusú erőforrásokhoz filé paraméterrel együtt használjuk content
. Például így:
file { '/tmp/example': content => template('modulename/templatename.erb')
Útvonal megtekintése <modulename>/<filename>
fájlra utal <rootdir>/modules/<modulename>/templates/<filename>
.
Ezen kívül van egy funkció inline_template
— a sablon szövegét kapja bemenetként, nem a fájl nevét.
A sablonokon belül az összes Puppet változót használhatja az aktuális hatókörben.
A Puppet támogatja az ERB és EPP formátumú sablonokat:
Röviden az ERB-ről
Vezérlési struktúrák:
<%= ВЫРАЖЕНИЕ %>
— írja be a kifejezés értékét<% ВЫРАЖЕНИЕ %>
— kiszámítja egy kifejezés értékét (beszúrása nélkül). A feltételes utasítások (if) és a ciklusok (mindegyik) általában ide kerülnek.<%# КОММЕНТАРИЙ %>
Az ERB-ben lévő kifejezések Rubyban vannak írva (az ERB valójában beágyazott rubin).
A változók jegyzékből való eléréséhez hozzá kell adnia @
a változó nevére. A vezérlőkonstrukció után megjelenő sortörés eltávolításához záró címkét kell használnia -%>
.
Példa a sablon használatára
Tegyük fel, hogy írok egy modult a ZooKeeper vezérléséhez. A konfiguráció létrehozásáért felelős osztály valahogy így néz ki:
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'),
}
}
És a megfelelő sablon zoo.cfg.erb
- Így:
<% 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 -%>
Tények és beépített változók
A konfiguráció konkrét része gyakran attól függ, hogy mi történik éppen a csomóponton. Például attól függően, hogy melyik Debian kiadásról van szó, telepítenie kell a csomag egyik vagy másik verzióját. Mindezt manuálisan is figyelemmel kísérheti, átírhatja a manifeszteket, ha csomópontok változnak. De ez nem komoly megközelítés, az automatizálás sokkal jobb.
A csomópontokról való információszerzéshez a Puppet rendelkezik egy tényeknek nevezett mechanizmussal. Tények - ez a csomópontra vonatkozó információ, amely manifesztekben, hétköznapi változók formájában érhető el a globális névtérben. Például a gazdagép neve, az operációs rendszer verziója, a processzor architektúrája, a felhasználók listája, a hálózati interfészek listája és azok címei, és még sok minden más. A tények jegyzékekben és sablonokban normál változóként érhetők el.
Példa a tényekkel való munkavégzésre:
notify { "Running OS ${facts['os']['name']} version ${facts['os']['release']['full']}": }
# ресурс типа notify просто выводит сообщение в лог
Formálisan egy ténynek van neve (karakterlánc) és értéke (különféle típusok állnak rendelkezésre: karakterláncok, tömbök, szótárak). Eszik
Működés közben a bábügynök először az összes elérhető ténygyűjtőt átmásolja a pappetszerverről a csomópontra, majd elindítja azokat, és elküldi az összegyűjtött tényeket a szervernek; Ezt követően a szerver megkezdi a katalógus összeállítását.
Tények futtatható fájlok formájában
Az ilyen tények a könyvtár moduljaiban vannak elhelyezve facts.d
. Természetesen a fájloknak futtathatónak kell lenniük. Futtatáskor információkat kell kiadniuk a szabványos kimenetre YAML vagy kulcs=érték formátumban.
Ne felejtse el, hogy a tények minden olyan csomópontra vonatkoznak, amelyet az a poppet-kiszolgáló vezérel, amelyre a modul telepítve van. Ezért a szkriptben ügyeljen arra, hogy ellenőrizze, hogy a rendszer rendelkezik-e a tény működéséhez szükséges összes programmal és fájllal.
#!/bin/sh
echo "testfact=success"
#!/bin/sh
echo '{"testyamlfact":"success"}'
Rubin tények
Az ilyen tények a könyvtár moduljaiban vannak elhelyezve 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
Szöveges tények
Az ilyen tények a címtár csomópontjaira kerülnek /etc/facter/facts.d
a régi Bábos ill /etc/puppetlabs/facts.d
az új Bábban.
examplefact=examplevalue
---
examplefact2: examplevalue2
anotherfact: anothervalue
Eljutás a tényekhez
Kétféleképpen lehet megközelíteni a tényeket:
- a szótáron keresztül
$facts
:$facts['fqdn']
; - a ténynév használata változónévként:
$fqdn
.
A legjobb, ha szótárt használsz $facts
, vagy még jobb, ha a globális névteret ($::facts
).
Beépített változók
A tények mellett van még
- megbízható tények — a kliens tanúsítványából vett változók (mivel a tanúsítványt általában poppet szerveren adják ki, az ügynök nem tudja csak úgy átvenni és megváltoztatni a tanúsítványát, így a változók „megbízhatóak”): a tanúsítvány neve, a tanúsítvány neve gazdagép és tartomány, kiterjesztések a tanúsítványból.
- szerver tények —a szerverrel kapcsolatos információkkal kapcsolatos változók — verzió, név, szerver IP-címe, környezet.
- ügynöki tények — közvetlenül a báb-ügynök által hozzáadott változók, nem pedig a tényezõk szerint — a tanúsítvány neve, az ügynök verziója, a bábverzió.
- master változók - Pappetmaster változók (sic!). Körülbelül ugyanaz, mint benne szerver tények, plusz konfigurációs paraméterértékek állnak rendelkezésre.
- fordítói változók — az egyes hatókörökben eltérő fordítóváltozók: az aktuális modul neve és annak a modulnak a neve, amelyben az aktuális objektumot elértük. Használhatók például annak ellenőrzésére, hogy a privát osztályaidat nem használják-e közvetlenül más modulokból.
1. kiegészítés: hogyan kell mindezt futtatni és hibakeresni?
A cikk sok példát tartalmazott a bábkódra, de egyáltalán nem árulta el, hogyan futtassuk ezt a kódot. Nos, kijavítom magam.
A Puppet futtatásához elég egy ügynök, de a legtöbb esetben szükség lesz egy szerverre is.
ügynök
Legalábbis az XNUMX-ös verzió óta, a puppet-agent csomagok innen
A legegyszerűbb esetben a bábkonfiguráció használatához elegendő az ügynököt szerver nélküli módban elindítani: feltéve, hogy a bábkódot a csomópontba másolták, indítsa el 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
Természetesen jobb, ha démon módban állítja be a szervert és futtatja az ügynököket a csomópontokon - akkor félóránként egyszer alkalmazzák a szerverről letöltött konfigurációt.
Utánozhatja a munka push modelljét - lépjen az Önt érdeklő csomóponthoz, és kezdje el sudo puppet agent -t
. Kulcs -t
(--test
) valójában több opciót is tartalmaz, amelyek külön-külön engedélyezhetők. Ezek a lehetőségek a következőket tartalmazzák:
- ne futtasson démon módban (alapértelmezés szerint az ügynök démon módban indul);
- leállítás a katalógus alkalmazása után (alapértelmezés szerint az ügynök továbbra is dolgozik, és félóránként alkalmazza a konfigurációt);
- írjon részletes munkanaplót;
- a fájlok változásainak megjelenítése.
Az ügynöknek változtatások nélküli működési módja van - akkor használhatja, ha nem biztos abban, hogy a megfelelő konfigurációt írta-e meg, és szeretné ellenőrizni, hogy az ügynök pontosan mit fog változni működés közben. Ezt a módot a paraméter engedélyezi --noop
a parancssorban: sudo puppet agent -t --noop
.
Ezenkívül engedélyezheti a munka hibakeresési naplóját - ebben a báb ír minden általa végrehajtott műveletről: az éppen feldolgozott erőforrásról, ennek az erőforrásnak a paramétereiről, arról, hogy milyen programokat indít el. Természetesen ez egy paraméter --debug
.
Сервер
Ebben a cikkben nem foglalkozom a pappetszerver teljes beállításával és a kód telepítésével; csak annyit mondok, hogy a kiszolgálónak van egy teljesen működőképes verziója, amely nem igényel további konfigurációt ahhoz, hogy kis számú szerverrel működjön. csomópontok (mondjuk akár száz). Nagyobb számú csomópont hangolást igényel - alapértelmezés szerint a puppetserver legfeljebb négy dolgozót indít el, a nagyobb teljesítmény érdekében növelnie kell a számukat, és ne felejtse el növelni a memóriakorlátokat, különben a szerver az idő nagy részében szemetet gyűjt.
Kódtelepítés – ha gyorsan és egyszerűen szüksége van rá, nézze meg (r10k)[
2. kiegészítés: Kódolási irányelvek
- Helyezzen el minden logikát osztályokba és definíciókba.
- Az osztályokat és definíciókat tartsa a modulokban, ne a csomópontokat leíró jegyzékekben.
- Használd a tényeket.
- Ne hozzon létre if-eket gazdagépnevek alapján.
- Nyugodtan adjon hozzá paramétereket az osztályokhoz és definíciókhoz – ez jobb, mint az osztály/define törzsében elrejtett implicit logika.
A következő cikkben elmagyarázom, miért ajánlom ezt.
Következtetés
Zárjuk be a bevezetést. A következő cikkben a Hiera-ról, az ENC-ről és a PuppetDB-ről fogok mesélni.
A felmérésben csak regisztrált felhasználók vehetnek részt.
Sőt, sokkal több anyag van - az alábbi témákban tudok cikkeket írni, szavazni, hogy miről olvasna szívesen:
- 59,1%Fejlett bábkonstrukciók – néhány következő szintű szar: hurkok, leképezés és egyéb lambda-kifejezések, erőforrás-gyűjtők, exportált erőforrások és gépek közötti kommunikáció a Puppeten keresztül, címkék, szolgáltatók, absztrakt adattípusok.13
- 31,8%„Én vagyok anyám adminisztrátora”, avagy hogyan barátkoztunk az Avitóban több különböző verziójú poppet szerverrel, és elvileg a poppet szerver adminisztrálására vonatkozó rész.7
- 81,8%Hogyan írjuk a bábkódot: műszerezés, dokumentáció, tesztelés, CI/CD.18
22 felhasználó szavazott. 9 felhasználó tartózkodott.
Forrás: will.com