Nuku tutvustus

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.

Nuku tutvustus

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 stiilis juhend. Kokkuvõte:

  • 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 dokumentatsioonis, kirjeldan siin viit põhitüüpi, millest minu praktikas piisab enamiku probleemide lahendamiseks.

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 kustutamine
    • present — peab olema mis tahes tüüpi fail (kui faili pole, luuakse tavaline fail)
    • file - tavaline fail
    • directory - kataloog
    • link - 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 skeemiga http: (Loodan, et on selge, mis sel juhul juhtub) ja isegi diagrammiga file: 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 installitud
    • latest - installitud uusim versioon
    • absent - 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. Vaikimisi false.

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äivitatud
    • stopped - 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. Kui false ja parameeter restart pole määratud - teenus peatatakse ja alustatakse taaskäivitamist (kuid systemd kasutab käsku systemctl restart).
  • hasstaatus — näitab, kas teenuse algskript toetab käsku status. Kui false, siis kasutatakse parameetri väärtust staatus. Vaikimisi true.

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 olemas
    • absent - 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 karbist välja võetud nukuserveris, seega pole üldisel saidil dokumentatsiooni. Aga tema on kastis nukuagendis, nii et seda pole vaja eraldi paigaldada. Saate vaadata selle dokumentatsiooni Puppeti viienda versiooni dokumentatsioonisVõi GitHubis.

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 namevea 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 Nuku dokumentatsioonis.

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

Dokumentatsioon siin.

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

Klass on nimega poppet-koodi plokk. Koodi taaskasutamiseks on vaja klasse.

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 muutujaid kasutades.

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 palju andmetüüpe. Andmetüüpe kasutatakse tavaliselt klassidele ja määratlustele edastatud parameetriväärtuste kinnitamiseks. Kui edastatud parameeter ei vasta määratud tüübile, tekib kompileerimisviga.

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:

  1. Installige pakett selle mooduliga.
  2. Loome selle mooduli jaoks konfiguratsioonifaili.
  3. Loome sümboli php-fpm konfiguratsioonile.
  4. Loome php cli konfiguratsioonile sümlingi.

Sellistel juhtudel kasutatakse sellist disaini nagu määratleda (määratle, määratletud tüüp, määratletud ressursi tüüp). Define on klassiga sarnane, kuid sellel on erinevusi: esiteks on iga Define ressursitüüp, mitte ressurss; teiseks on igal definitsioonil kaudne parameeter $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

Dokumentatsioon siin.

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 - Nuku sepikoda.

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 manifeste
  • files - see sisaldab faile
  • templates - see sisaldab malle
  • lib - 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

Dokumentatsioon siin.

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 nimetada foo::<anything>, või lihtsalt foo.
  • 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 kirjeldatud init.pp;
  • klass nginx::service manifestis kirjeldatud service.pp;
  • määratleda nginx::server manifestis kirjeldatud server.pp;
  • määratleda nginx::server::location manifestis kirjeldatud server/location.pp.

Mallid

Kindlasti teate ise, mis on mallid; ma ei kirjelda neid siin üksikasjalikult. Aga ma jätan selle igaks juhuks link Wikipediasse.

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 sisseehitatud faktide kogum. Võite kirjutada ka oma. Kirjeldatakse faktikogujaid nagu Ruby funktsioonidvõi kuidas käivitatavad failid. Fakte saab esitada ka vormis tekstifailid andmetega sõlmedel.

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 $factsvõi veelgi parem, näita globaalset nimeruumi ($::facts).

Siin on dokumentatsiooni vastav osa.

Sisseehitatud muutujad

Lisaks faktidele on ka mõned muutujad, saadaval globaalses nimeruumis.

  • 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 ametlik Puppetlabsi hoidla sisaldab kõiki sõltuvusi (rubiin ja vastavad kalliskivid), nii et installimisraskusi pole (räägin Debiani-põhistest distributsioonidest - me ei kasuta RPM-põhiseid distributsioone).

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)[https://github.com/puppetlabs/r10k], väikeste paigalduste jaoks peaks sellest täiesti piisama.

2. lisa: kodeerimisjuhised

  1. Asetage kogu loogika klassidesse ja definitsioonidesse.
  2. Hoidke klasse ja määratlusi moodulites, mitte sõlmedes kirjeldavates manifestides.
  3. Kasutage fakte.
  4. Ärge tehke hostinimede põhjal if-e.
  5. 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. Logi sissepalun.

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