Ievads lelli

Puppet ir konfigurācijas pārvaldības sistēma. To izmanto, lai nogādātu saimniekus vēlamajā stāvoklī un uzturētu šo stāvokli.

Es strādāju ar Puppet jau vairāk nekā piecus gadus. Šis teksts būtībā ir tulkots un pārkārtots galveno punktu apkopojums no oficiālās dokumentācijas, kas ļaus iesācējiem ātri izprast Lelles būtību.

Ievads lelli

Pamatinformācija

Puppet operētājsistēma ir klients-serveris, lai gan tā atbalsta arī bezservera darbību ar ierobežotu funkcionalitāti.

Tiek izmantots vilkšanas darbības modelis: pēc noklusējuma klienti reizi pusstundā sazinās ar serveri, lai iegūtu konfigurāciju un to lietotu. Ja esat strādājis ar Ansible, tad viņi izmanto citu push modeli: administrators iniciē konfigurācijas pielietošanas procesu, paši klienti neko nelietos.

Tīkla komunikācijas laikā tiek izmantota divvirzienu TLS šifrēšana: serverim un klientam ir savas privātās atslēgas un atbilstošie sertifikāti. Parasti serveris klientiem izsniedz sertifikātus, bet principā ir iespējams izmantot ārēju CA.

Ievads manifestos

Leļļu terminoloģijā uz leļļu serveri savienot mezgli (mezgli). Mezglu konfigurācija ir uzrakstīta manifestos īpašā programmēšanas valodā - Puppet DSL.

Leļļu DSL ir deklaratīva valoda. Tas apraksta vēlamo mezgla stāvokli atsevišķu resursu deklarāciju veidā, piemēram:

  • Fails pastāv, un tam ir noteikts saturs.
  • Pakete ir instalēta.
  • Pakalpojums ir sācies.

Resursi var būt savstarpēji saistīti:

  • Ir atkarības, tās ietekmē resursu izmantošanas kārtību.
    Piemēram, “vispirms instalējiet pakotni, pēc tam rediģējiet konfigurācijas failu un pēc tam sāciet pakalpojumu”.
  • Ir paziņojumi – ja kāds resurss ir mainījies, tas nosūta paziņojumus uz tā abonētajiem resursiem.
    Piemēram, ja mainās konfigurācijas fails, varat automātiski restartēt pakalpojumu.

Turklāt Puppet DSL ir funkcijas un mainīgie, kā arī nosacījuma priekšraksti un atlasītāji. Tiek atbalstīti arī dažādi šablonu mehānismi – EPP un ERB.

Lelle ir rakstīta rubīnā, tāpēc daudzas konstrukcijas un termini ir ņemti no turienes. Rubīns ļauj paplašināt Puppet - pievienot sarežģītu loģiku, jaunus resursu veidus, funkcijas.

Kamēr darbojas Puppet, katra konkrētā servera mezgla manifesti tiek apkopoti direktorijā. Katalogs ir resursu un to attiecību saraksts pēc funkciju, mainīgo vērtību aprēķināšanas un nosacījumu priekšrakstu paplašināšanas.

Sintakse un koda stils

Šeit ir oficiālās dokumentācijas sadaļas, kas palīdzēs izprast sintaksi, ja ar sniegtajiem piemēriem nepietiek:

Šeit ir piemērs, kā izskatās manifests:

# Комментарии пишутся, как и много где, после решётки.
#
# Описание конфигурации ноды начинается с ключевого слова node,
# за которым следует селектор ноды — хостнейм (с доменом или без)
# или регулярное выражение для хостнеймов, или ключевое слово default.
#
# После этого в фигурных скобках описывается собственно конфигурация ноды.
#
# Одна и та же нода может попасть под несколько селекторов. Про приоритет
# селекторов написано в статье про синтаксис описания нод.
node 'hostname', 'f.q.d.n', /regexp/ {
  # Конфигурация по сути является перечислением ресурсов и их параметров.
  #
  # У каждого ресурса есть тип и название.
  #
  # Внимание: не может быть двух ресурсов одного типа с одинаковыми названиями!
  #
  # Описание ресурса начинается с его типа. Тип пишется в нижнем регистре.
  # Про разные типы ресурсов написано ниже.
  #
  # После типа в фигурных скобках пишется название ресурса, потом двоеточие,
  # дальше идёт опциональное перечисление параметров ресурса и их значений.
  # Значения параметров указываются через т.н. hash rocket (=>).
  resource { 'title':
    param1 => value1,
    param2 => value2,
    param3 => value3,
  }
}

Atkāpes un rindiņu pārtraukumi nav obligāta manifesta daļa, taču ir ieteicama stila ceļvedis. Kopsavilkums:

  • Divu atstarpju atkāpes, tabulēšanas zīmes netiek izmantotas.
  • Cirtainās breketes ir atdalītas ar atstarpi; kolus neatdala ar atstarpi.
  • Komati aiz katra parametra, ieskaitot pēdējo. Katrs parametrs ir atsevišķā rindā. Izņēmums ir gadījumam bez parametriem un viena parametra: var rakstīt vienā rindā un bez komata (t.i. resource { 'title': } и resource { 'title': param => value }).
  • Bultiņām uz parametriem jābūt vienā līmenī.
  • To priekšā ir uzrakstītas resursu attiecību bultiņas.

Failu atrašanās vieta pappetserverā

Lai iegūtu sīkāku skaidrojumu, es iepazīstināšu ar jēdzienu “saknes direktorijs”. Saknes direktorijs ir direktorijs, kurā ir noteikta mezgla leļļu konfigurācija.

Saknes direktorijs atšķiras atkarībā no Puppet versijas un izmantotajām vidēm. Vides ir neatkarīgas konfigurācijas kopas, kas tiek glabātas atsevišķos direktorijos. Parasti lieto kopā ar git, tādā gadījumā vides tiek veidotas no git zariem. Attiecīgi katrs mezgls atrodas vienā vai otrā vidē. To var konfigurēt pašā mezglā vai ENC, par ko es runāšu nākamajā rakstā.

  • Trešajā versijā ("vecā lelle") bija bāzes direktorijs /etc/puppet. Vides izmantošana nav obligāta - piemēram, mēs tās neizmantojam ar veco Puppet. Ja tiek izmantotas vides, tās parasti tiek glabātas /etc/puppet/environments, saknes direktorijs būs vides direktorijs. Ja vides netiek izmantotas, saknes direktorijs būs bāzes direktorijs.
  • Sākot ar ceturto versiju (“jaunā lelle”), vides izmantošana kļuva obligāta, un bāzes direktorijs tika pārvietots uz /etc/puppetlabs/code. Attiecīgi vides tiek glabātas /etc/puppetlabs/code/environments, saknes direktorijs ir vides direktorijs.

Saknes direktorijā ir jābūt apakšdirektorijam manifests, kurā ir viens vai vairāki manifesti, kas apraksta mezglus. Turklāt ir jābūt apakšdirektorijam modules, kurā ir moduļi. Es jums pastāstīšu, kādi moduļi ir nedaudz vēlāk. Turklāt vecajam Puppet var būt arī apakšdirektorijs files, kurā ir dažādi faili, kurus kopējam uz mezgliem. Jaunajā Puppet visi faili ir ievietoti moduļos.

Manifesta failiem ir paplašinājums .pp.

Pāris kaujas piemēri

Mezgla apraksts un tajā esošais resurss

Uz mezgla server1.testdomain ir jāizveido fails /etc/issue ar saturu Debian GNU/Linux n l. Failam ir jābūt lietotājam un grupai root, piekļuves tiesībām jābūt 644.

Mēs rakstām manifestu:

node 'server1.testdomain' {   # блок конфигурации, относящийся к ноде server1.testdomain
    file { '/etc/issue':   # описываем файл /etc/issue
        ensure  => present,   # этот файл должен существовать
        content => 'Debian GNU/Linux n l',   # у него должно быть такое содержимое
        owner   => root,   # пользователь-владелец
        group   => root,   # группа-владелец
        mode    => '0644',   # права на файл. Они заданы в виде строки (в кавычках), потому что иначе число с 0 в начале будет воспринято как записанное в восьмеричной системе, и всё пойдёт не так, как задумано
    }
}

Attiecības starp resursiem mezglā

Uz mezgla server2.testdomain nginx ir jādarbojas, strādājot ar iepriekš sagatavotu konfigurāciju.

Sadalīsim problēmu:

  • Ir nepieciešams instalēt pakotni nginx.
  • Konfigurācijas faili ir jāpārkopē no servera.
  • Pakalpojumam ir jādarbojas nginx.
  • Ja konfigurācija tiek atjaunināta, pakalpojums ir jārestartē.

Mēs rakstām manifestu:

node 'server2.testdomain' {   # блок конфигурации, относящийся к ноде server2.testdomain
    package { 'nginx':   # описываем пакет nginx
        ensure => installed,   # он должен быть установлен
    }
  # Прямая стрелка (->) говорит о том, что ресурс ниже должен
  # создаваться после ресурса, описанного выше.
  # Такие зависимости транзитивны.
    -> file { '/etc/nginx':   # описываем файл /etc/nginx
        ensure  => directory,   # это должна быть директория
        source  => 'puppet:///modules/example/nginx-conf',   # её содержимое нужно брать с паппет-сервера по указанному адресу
        recurse => true,   # копировать файлы рекурсивно
        purge   => true,   # нужно удалять лишние файлы (те, которых нет в источнике)
        force   => true,   # удалять лишние директории
    }
  # Волнистая стрелка (~>) говорит о том, что ресурс ниже должен
  # подписаться на изменения ресурса, описанного выше.
  # Волнистая стрелка включает в себя прямую (->).
    ~> service { 'nginx':   # описываем сервис nginx
        ensure => running,   # он должен быть запущен
        enable => true,   # его нужно запускать автоматически при старте системы
    }
  # Когда ресурс типа service получает уведомление,
  # соответствующий сервис перезапускается.
}

Lai tas darbotos, leļļu serverī ir nepieciešama aptuveni šāda faila atrašanās vieta:

/etc/puppetlabs/code/environments/production/ # (это для нового Паппета, для старого корневой директорией будет /etc/puppet)
├── manifests/
│   └── site.pp
└── modules/
    └── example/
        └── files/
            └── nginx-conf/
                ├── nginx.conf
                ├── mime.types
                └── conf.d/
                    └── some.conf

Resursu veidi

Pilns atbalstīto resursu veidu saraksts ir atrodams šeit dokumentācijā, šeit es aprakstīšu piecus pamattipus, ar kuriem manā praksē pietiek, lai atrisinātu lielāko daļu problēmu.

fails

Pārvalda failus, direktorijus, simboliskās saites, to saturu un piekļuves tiesības.

opcijas:

  • resursa nosaukums — ceļš uz failu (pēc izvēles)
  • taka - ceļš uz failu (ja tas nav norādīts nosaukumā)
  • nodrošināt - faila tips:
    • absent - izdzēst failu
    • present — jābūt jebkura veida failam (ja faila nav, tiks izveidots parasts fails)
    • file - parastais fails
    • directory - direktorijs
    • link - simboliskā saite
  • saturs — faila saturs (piemērots tikai parastajiem failiem, nevar izmantot kopā ar avots vai mērķis)
  • avots — saite uz ceļu, no kura vēlaties kopēt faila saturu (nevar izmantot kopā ar saturs vai mērķis). Var norādīt kā URI ar shēmu puppet: (tad tiks izmantoti faili no leļļu servera), un ar shēmu http: (Es ceru, ka ir skaidrs, kas notiks šajā gadījumā), un pat ar diagrammu file: vai kā absolūts ceļš bez shēmas (tad tiks izmantots fails no mezgla vietējā FS)
  • mērķis — kur jānorāda simboliskā saite (nevar izmantot kopā ar saturs vai avots)
  • īpašnieks — lietotājs, kuram vajadzētu piederēt failam
  • grupa — grupa, kurai failam vajadzētu piederēt
  • mode - faila atļaujas (kā virkne)
  • atkārtot - nodrošina rekursīvu direktoriju apstrādi
  • caurejas līdzeklis - ļauj dzēst failus, kas nav aprakstīti sadaļā Puppet
  • piespiest - ļauj dzēst direktorijus, kas nav aprakstīti Puppet

pakete

Instalē un noņem pakotnes. Spēj apstrādāt paziņojumus - pārinstalē pakotni, ja parametrs ir norādīts reinstall_on_refresh.

opcijas:

  • resursa nosaukums — pakotnes nosaukums (pēc izvēles)
  • nosaukums — pakotnes nosaukums (ja nosaukumā nav norādīts)
  • sniedzējs — izmantot pakotņu pārvaldnieku
  • nodrošināt — vēlamais iepakojuma stāvoklis:
    • present, installed - jebkura instalēta versija
    • latest - instalēta jaunākā versija
    • absent - dzēsts (apt-get remove)
    • purged — dzēsts kopā ar konfigurācijas failiem (apt-get purge)
    • held - pakotnes versija ir bloķēta (apt-mark hold)
    • любая другая строка — ir instalēta norādītā versija
  • reinstall_on_refresh - ja true, tad pēc paziņojuma saņemšanas pakotne tiks atkārtoti instalēta. Noderīga uz avotu balstītiem izplatījumiem, kur, mainot būvēšanas parametrus, var būt nepieciešama pakotņu atjaunošana. Noklusējums false.

apkalpošana

Pārvalda pakalpojumus. Var apstrādāt paziņojumus - restartē pakalpojumu.

opcijas:

  • resursa nosaukums — pārvaldāmais pakalpojums (pēc izvēles)
  • nosaukums — pakalpojums, kas jāpārvalda (ja nav norādīts nosaukumā)
  • nodrošināt — vēlamais pakalpojuma stāvoklis:
    • running - palaists
    • stopped - apstājās
  • dot iespēju — kontrolē iespēju palaist pakalpojumu:
    • true — ir iespējota automātiskā palaišana (systemctl enable)
    • mask - maskēts (systemctl mask)
    • false — automātiskā palaišana ir atspējota (systemctl disable)
  • restart - komanda restartēt pakalpojumu
  • stāvoklis — komanda pakalpojuma statusa pārbaudei
  • ir restartēt — norāda, vai pakalpojuma sākumskripts atbalsta restartēšanu. Ja false un parametrs ir norādīts restart — tiek izmantota šī parametra vērtība. Ja false un parametrs restart nav norādīts - pakalpojums tiek apturēts un sākts restartēt (bet systemd izmanto komandu systemctl restart).
  • hasstatus — norāda, vai pakalpojuma sākumskripts atbalsta komandu status. Ja false, tad tiek izmantota parametra vērtība stāvoklis. Noklusējums true.

exec

Palaiž ārējās komandas. Ja nenorādīsiet parametrus rada, tikai ja, ja vien vai atsvaidzinoši, komanda tiks izpildīta katru reizi, kad tiks palaists Puppet. Spēj apstrādāt paziņojumus - izpilda komandu.

opcijas:

  • resursa nosaukums — izpildāmā komanda (pēc izvēles)
  • komanda — izpildāmā komanda (ja tā nav norādīta nosaukumā)
  • taka — ceļi, kuros meklēt izpildāmo failu
  • tikai ja — ja šajā parametrā norādītā komanda ir pabeigta ar nulles atgriešanas kodu, tiks izpildīta galvenā komanda
  • ja vien — ja šajā parametrā norādītā komanda ir pabeigta ar atgriešanas kodu, kas nav nulle, tiks izpildīta galvenā komanda
  • rada — ja šajā parametrā norādītais fails neeksistē, tiks izpildīta galvenā komanda
  • atsvaidzinoši - ja true, tad komanda tiks izpildīta tikai tad, kad šis izpildītājs saņems paziņojumu no citiem resursiem
  • cwd — direktorijs, no kura palaist komandu
  • lietotājs — lietotājs, no kura palaist komandu
  • sniedzējs - kā palaist komandu:
    • positix — ir vienkārši izveidots bērnu process, noteikti norādiet taka
    • apvalks - komanda tiek palaista čaulā /bin/sh, var nebūt norādīts taka, varat izmantot globbing, caurules un citas apvalka funkcijas. Parasti tiek noteikta automātiski, ja ir kādas īpašas rakstzīmes (|, ;, &&, || utt.).

cron

Kontrolē cronjobs.

opcijas:

  • resursa nosaukums - tikai sava veida identifikators
  • nodrošināt — crownjob valsts:
    • present - izveidot, ja neeksistē
    • absent - dzēst, ja tāds ir
  • komanda - kādu komandu palaist
  • vide — kurā vidē palaist komandu (vides mainīgo un to vērtību saraksts, izmantojot =)
  • lietotājs — no kura lietotāja palaist komandu
  • minūte, stunda, darbdiena, MĒNESĪ, mēneša diena — kad palaist kronu. Ja kāds no šiem atribūtiem nav norādīts, tā vērtība crontab būs *.

Programmā Puppet 6.0 cron it kā izņemts no kastes leļļu serverī, tāpēc vispārējā vietnē nav dokumentācijas. Bet viņš atrodas kastē leļļu aģentā, tāpēc nav nepieciešams to instalēt atsevišķi. Jūs varat redzēt tā dokumentāciju Lelles piektās versijas dokumentācijāVai vietnē GitHub.

Par resursiem kopumā

Prasības resursa unikalitātei

Visbiežāk sastopamā kļūda, ar kuru mēs sastopamies, ir Deklarācijas dublikāts. Šī kļūda rodas, ja direktorijā parādās divi vai vairāki viena veida resursi ar tādu pašu nosaukumu.

Tāpēc es rakstīšu vēlreiz: tā paša mezgla manifestos nedrīkst būt viena veida resursi ar tādu pašu nosaukumu!

Dažreiz ir jāinstalē pakotnes ar tādu pašu nosaukumu, bet ar dažādiem pakotņu pārvaldniekiem. Šajā gadījumā jums ir jāizmanto parametrs namelai izvairītos no kļūdas:

package { 'ruby-mysql':
  ensure   => installed,
  name     => 'mysql',
  provider => 'gem',
}
package { 'python-mysql':
  ensure   => installed,
  name     => 'mysql',
  provider => 'pip',
}

Citiem resursu veidiem ir līdzīgas iespējas, lai palīdzētu izvairīties no dublēšanās − name у apkalpošana, command у exec, un tā tālāk.

Metaparametri

Katram resursa veidam ir daži īpaši parametri neatkarīgi no tā veida.

Pilns meta parametru saraksts leļļu dokumentācijā.

Īss saraksts:

  • pieprasīt — šis parametrs norāda, no kuriem resursiem ir atkarīgs šis resurss.
  • pirms - Šis parametrs norāda, kuri resursi ir atkarīgi no šī resursa.
  • abonēt — šis parametrs norāda, no kuriem resursiem šis resurss saņem paziņojumus.
  • paziņot — Šis parametrs norāda, kuri resursi saņem paziņojumus no šī resursa.

Visi uzskaitītie metaparametri pieņem vai nu vienu resursa saiti, vai saišu masīvu kvadrātiekavās.

Saites uz resursiem

Resursa saite ir vienkārši resursa pieminēšana. Tos galvenokārt izmanto, lai norādītu uz atkarībām. Atsauce uz neesošu resursu izraisīs kompilācijas kļūdu.

Saites sintakse ir šāda: resursa tips ar lielo burtu (ja tipa nosaukumā ir dubultās kolas, tad katra nosaukuma daļa starp koliem ir ar lielo burtu), tad resursa nosaukums kvadrātiekavās (nosaukuma reģistrs nemainās!). Nedrīkst būt atstarpēm, kvadrātiekavas tiek rakstītas uzreiz aiz tipa nosaukuma.

Piemērs:

file { '/file1': ensure => present }
file { '/file2':
  ensure => directory,
  before => File['/file1'],
}
file { '/file3': ensure => absent }
File['/file1'] -> File['/file3']

Atkarības un paziņojumi

Dokumentācija šeit.

Kā minēts iepriekš, vienkāršas atkarības starp resursiem ir pārejošas. Starp citu, esiet piesardzīgs, pievienojot atkarības - varat izveidot cikliskas atkarības, kas radīs kompilācijas kļūdu.

Atšķirībā no atkarībām, paziņojumi nav pārejoši. Uz paziņojumiem attiecas šādi noteikumi:

  • Ja resurss saņem paziņojumu, tas tiek atjaunināts. Atjaunināšanas darbības ir atkarīgas no resursa veida − exec izpilda komandu, apkalpošana restartē pakalpojumu, pakete pārinstalē pakotni. Ja resursam nav definēta atjaunināšanas darbība, nekas nenotiek.
  • Vienas Puppet darbības laikā resurss tiek atjaunināts ne vairāk kā vienu reizi. Tas ir iespējams, jo paziņojumos ir iekļautas atkarības, un atkarības diagrammā nav iekļauti cikli.
  • Ja Lelle maina resursa stāvokli, resurss nosūta paziņojumus visiem tā abonētajiem resursiem.
  • Ja resurss tiek atjaunināts, tas nosūta paziņojumus visiem tā abonētajiem resursiem.

Nenoteiktu parametru apstrāde

Parasti, ja kādam resursa parametram nav noklusējuma vērtības un šis parametrs nav norādīts manifestā, Puppet nemainīs šo rekvizītu attiecīgajam resursam mezglā. Piemēram, ja šāda veida resurss fails parametrs nav norādīts owner, tad Puppet nemainīs atbilstošā faila īpašnieku.

Ievads klasēs, mainīgajos un definīcijās

Pieņemsim, ka mums ir vairāki mezgli, kuriem ir vienāda konfigurācijas daļa, taču ir arī atšķirības - pretējā gadījumā mēs to visu varētu aprakstīt vienā blokā node {}. Protams, var vienkārši nokopēt identiskas konfigurācijas daļas, taču kopumā tas ir slikts risinājums – konfigurācija aug, un ja mainīsi konfigurācijas vispārīgo daļu, tad daudzviet nāksies rediģēt vienu un to pašu. Tajā pašā laikā ir viegli kļūdīties, un kopumā princips DRY (neatkārtojies) tika izgudrots ne velti.

Lai atrisinātu šo problēmu, ir tāds dizains kā klase.

Nodarbības

Klase ir nosaukts poppet koda bloks. Klases ir nepieciešamas, lai atkārtoti izmantotu kodu.

Vispirms ir jāapraksta klase. Pats apraksts nekur nepievieno nekādus resursus. Klase ir aprakstīta manifestos:

# Описание класса начинается с ключевого слова class и его названия.
# Дальше идёт тело класса в фигурных скобках.
class example_class {
    ...
}

Pēc tam klasi var izmantot:

# первый вариант использования — в стиле ресурса с типом class
class { 'example_class': }
# второй вариант использования — с помощью функции include
include example_class
# про отличие этих двух вариантов будет рассказано дальше

Piemērs no iepriekšējā uzdevuma - pārvietosim nginx instalēšanu un konfigurēšanu uz klasi:

class nginx_example {
    package { 'nginx':
        ensure => installed,
    }
    -> file { '/etc/nginx':
        ensure => directory,
        source => 'puppet:///modules/example/nginx-conf',
        recure => true,
        purge  => true,
        force  => true,
    }
    ~> service { 'nginx':
        ensure => running,
        enable => true,
    }
}

node 'server2.testdomain' {
    include nginx_example
}

Mainīgie

Klase no iepriekšējā piemēra vispār nav elastīga, jo tā vienmēr nodrošina to pašu nginx konfigurāciju. Izveidosim ceļu uz konfigurācijas mainīgo, tad šo klasi var izmantot, lai instalētu nginx ar jebkuru konfigurāciju.

To var izdarīt izmantojot mainīgos.

Uzmanību: mainīgie lielumi programmā Puppet ir nemainīgi!

Turklāt mainīgajam var piekļūt tikai pēc tam, kad tas ir deklarēts, pretējā gadījumā mainīgā vērtība būs undef.

Piemērs darbam ar mainīgajiem:

# создание переменных
$variable = 'value'
$var2 = 1
$var3 = true
$var4 = undef
# использование переменных
$var5 = $var6
file { '/tmp/text': content => $variable }
# интерполяция переменных — раскрытие значения переменных в строках. Работает только в двойных кавычках!
$var6 = "Variable with name variable has value ${variable}"

Lellei ir nosaukumvietas, un attiecīgi mainīgajiem ir redzamības zona: mainīgo ar tādu pašu nosaukumu var definēt dažādās nosaukumvietās. Atrisinot mainīgā lieluma vērtību, mainīgais tiek meklēts pašreizējā nosaukumvietā, pēc tam aptverošajā nosaukumvietā un tā tālāk.

Vārdtelpas piemēri:

  • globālais - mainīgie ārpus klases vai mezgla apraksta nonāk tur;
  • mezgla nosaukumvieta mezgla aprakstā;
  • klases nosaukumvieta klases aprakstā.

Lai izvairītos no neskaidrībām, piekļūstot mainīgajam, mainīgā nosaukumā varat norādīt nosaukumvietu:

# переменная без пространства имён
$var
# переменная в глобальном пространстве имён
$::var
# переменная в пространстве имён класса
$classname::var
$::classname::var

Vienosimies, ka ceļš uz nginx konfigurāciju atrodas mainīgajā $nginx_conf_source. Tad klase izskatīsies šādi:

class nginx_example {
    package { 'nginx':
        ensure => installed,
    }
    -> file { '/etc/nginx':
        ensure => directory,
        source => $nginx_conf_source,   # здесь используем переменную вместо фиксированной строки
        recure => true,
        purge  => true,
        force  => true,
    }
    ~> service { 'nginx':
        ensure => running,
        enable => true,
    }
}

node 'server2.testdomain' {
    $nginx_conf_source = 'puppet:///modules/example/nginx-conf'
    include nginx_example
}

Taču dotais piemērs ir slikts, jo ir zināmas “slepenās zināšanas”, ka kaut kur klasē tiek lietots mainīgais ar tādu un tādu nosaukumu. Daudz pareizāk ir šīs zināšanas padarīt vispārīgas - klasēm var būt parametri.

Klases parametri ir mainīgie klases nosaukumvietā, tie ir norādīti klases galvenē un var tikt izmantoti kā parastie mainīgie klases pamattekstā. Parametru vērtības tiek norādītas, izmantojot klasi manifestā.

Parametram var iestatīt noklusējuma vērtību. Ja parametram nav noklusējuma vērtības un vērtība netiek iestatīta lietošanas laikā, tas izraisīs kompilācijas kļūdu.

Parametizēsim klasi no iepriekš redzamā piemēra un pievienosim divus parametrus: pirmais obligātais ir ceļš uz konfigurāciju, bet otrais, neobligāts, ir pakotnes nosaukums ar nginx (piemēram, Debianā ir pakotnes nginx, nginx-light, nginx-full).

# переменные описываются сразу после имени класса в круглых скобках
class nginx_example (
  $conf_source,
  $package_name = 'nginx-light', # параметр со значением по умолчанию
) {
  package { $package_name:
    ensure => installed,
  }
  -> file { '/etc/nginx':
    ensure  => directory,
    source  => $conf_source,
    recurse => true,
    purge   => true,
    force   => true,
  }
  ~> service { 'nginx':
    ensure => running,
    enable => true,
  }
}

node 'server2.testdomain' {
  # если мы хотим задать параметры класса, функция include не подойдёт* — нужно использовать resource-style declaration
  # *на самом деле подойдёт, но про это расскажу в следующей серии. Ключевое слово "Hiera".
  class { 'nginx_example':
    conf_source => 'puppet:///modules/example/nginx-conf',   # задаём параметры класса точно так же, как параметры для других ресурсов
  }
}

Programmā Puppet mainīgie tiek drukāti. Ēst daudzi datu veidi. Datu tipus parasti izmanto, lai apstiprinātu klasēm un definīcijām nodotās parametru vērtības. Ja nodotais parametrs neatbilst norādītajam tipam, radīsies kompilācijas kļūda.

Tips tiek rakstīts tieši pirms parametra nosaukuma:

class example (
  String $param1,
  Integer $param2,
  Array $param3,
  Hash $param4,
  Hash[String, String] $param5,
) {
  ...
}

Klases: ietver klases nosaukumu pret klasi {'classname':}

Katra klase ir sava veida resurss klase. Tāpat kā jebkura cita veida resursiem, vienā mezglā nevar būt divi vienas klases gadījumi.

Ja mēģināt pievienot klasi vienam mezglam divas reizes, izmantojot class { 'classname':} (nav atšķirības, ar dažādiem vai identiskiem parametriem), būs kompilācijas kļūda. Bet, ja izmantojat klasi resursu stilā, varat nekavējoties skaidri iestatīt visus tās parametrus manifestā.

Tomēr, ja lietojat include, tad klasi var pievienot tik reižu, cik vēlaties. Fakts ir tāds include ir idempotenta funkcija, kas pārbauda, ​​vai direktorijam ir pievienota klase. Ja klase neatrodas direktorijā, tā to pievieno, un, ja tā jau pastāv, tā neko nedara. Bet lietošanas gadījumā include Klases deklarēšanas laikā nevar iestatīt klases parametrus – visi nepieciešamie parametri jāiestata ārējā datu avotā – Hiera vai ENC. Par tiem mēs runāsim nākamajā rakstā.

Definē

Kā tika teikts iepriekšējā blokā, viena un tā pati klase mezglā nevar atrasties vairāk kā vienu reizi. Tomēr dažos gadījumos jums ir jāspēj izmantot vienu un to pašu koda bloku ar dažādiem parametriem tajā pašā mezglā. Citiem vārdiem sakot, ir nepieciešams savs resursa veids.

Piemēram, lai instalētu PHP moduli, programmā Avito mēs rīkojamies šādi:

  1. Instalējiet pakotni ar šo moduli.
  2. Izveidosim šī moduļa konfigurācijas failu.
  3. Mēs izveidojam saiti uz php-fpm konfigurāciju.
  4. Mēs izveidojam saiti uz php cli konfigurāciju.

Šādos gadījumos dizains, piemēram, definēt (definēt, definēts tips, definēts resursa tips). Define ir līdzīga klasei, taču pastāv atšķirības: pirmkārt, katrs Define ir resursa veids, nevis resurss; otrkārt, katrai definīcijai ir netiešs parametrs $title, kur tiek norādīts resursa nosaukums, kad tas tiek deklarēts. Tāpat kā klasēm, vispirms ir jāapraksta definīcija, pēc kuras to var izmantot.

Vienkāršots piemērs ar PHP moduli:

define php74::module (
  $php_module_name = $title,
  $php_package_name = "php7.4-${title}",
  $version = 'installed',
  $priority = '20',
  $data = "extension=${title}.son",
  $php_module_path = '/etc/php/7.4/mods-available',
) {
  package { $php_package_name:
    ensure          => $version,
    install_options => ['-o', 'DPkg::NoTriggers=true'],  # триггеры дебиановских php-пакетов сами создают симлинки и перезапускают сервис php-fpm - нам это не нужно, так как и симлинками, и сервисом мы управляем с помощью Puppet
  }
  -> file { "${php_module_path}/${php_module_name}.ini":
    ensure  => $ensure,
    content => $data,
  }
  file { "/etc/php/7.4/cli/conf.d/${priority}-${php_module_name}.ini":
    ensure  => link,
    target  => "${php_module_path}/${php_module_name}.ini",
  }
  file { "/etc/php/7.4/fpm/conf.d/${priority}-${php_module_name}.ini":
    ensure  => link,
    target  => "${php_module_path}/${php_module_name}.ini",
  }
}

node server3.testdomain {
  php74::module { 'sqlite3': }
  php74::module { 'amqp': php_package_name => 'php-amqp' }
  php74::module { 'msgpack': priority => '10' }
}

Vienkāršākais veids, kā atklāt deklarācijas dublikāta kļūdu, ir Definēt. Tas notiek, ja definīcijai ir resurss ar nemainīgu nosaukumu un kādā mezglā ir divi vai vairāki šīs definīcijas gadījumi.

No tā ir viegli pasargāt sevi: visiem definīcijā iekļautajiem resursiem ir jābūt nosaukumiem atkarībā no $title. Alternatīva ir idempotena resursu pievienošana; vienkāršākajā gadījumā pietiek ar visiem definīcijas gadījumiem kopīgos resursus pārvietot atsevišķā klasē un iekļaut šo klasi definīcijā - funkcijā include idempotents.

Ir arī citi veidi, kā panākt idempotenci, pievienojot resursus, proti, izmantojot funkcijas defined и ensure_resources, bet par to pastāstīšu nākamajā sērijā.

Atkarības un paziņojumi par klasēm un definīcijām

Klases un definīcijas pievieno šādus noteikumus atkarību un paziņojumu apstrādei:

  • atkarība no klases/definē pievieno atkarības no visiem klases/definētajiem resursiem;
  • klases/definēt atkarība pievieno atkarības visiem klases/definētajiem resursiem;
  • class/define paziņojums informē visus klases/definēt resursus;
  • class/define abonements abonē visus klases/define resursus.

Nosacīti apgalvojumi un atlasītāji

Dokumentācija šeit.

if

Šeit viss ir vienkārši:

if ВЫРАЖЕНИЕ1 {
  ...
} elsif ВЫРАЖЕНИЕ2 {
  ...
} else {
  ...
}

ja vien

ja vien if ir apgrieztā veidā: koda bloks tiks izpildīts, ja izteiksme ir nepatiesa.

unless ВЫРАЖЕНИЕ {
  ...
}

lieta

Arī šeit nav nekā sarežģīta. Kā vērtības varat izmantot regulāras vērtības (virknes, skaitļus utt.), regulāras izteiksmes un datu tipus.

case ВЫРАЖЕНИЕ {
  ЗНАЧЕНИЕ1: { ... }
  ЗНАЧЕНИЕ2, ЗНАЧЕНИЕ3: { ... }
  default: { ... }
}

Selektori

Atlasītājs ir valodas konstrukcija, kas līdzīga case, bet tā vietā, lai izpildītu koda bloku, tas atgriež vērtību.

$var = $othervar ? { 'val1' => 1, 'val2' => 2, default => 3 }

Moduļi

Ja konfigurācija ir maza, to var viegli saglabāt vienā manifestā. Bet jo vairāk konfigurāciju mēs aprakstām, jo ​​vairāk klašu un mezglu ir manifestā, tas palielinās un kļūst neērti strādāt.

Turklāt ir koda atkārtotas izmantošanas problēma – kad viss kods ir vienā manifestā, ir grūti šo kodu koplietot ar citiem. Lai atrisinātu šīs divas problēmas, programmai Puppet ir entītija, ko sauc par moduļiem.

Moduļi - tās ir klašu, definīciju un citu Leļļu entītiju kopas, kas ievietotas atsevišķā direktorijā. Citiem vārdiem sakot, modulis ir neatkarīga leļļu loģikas daļa. Piemēram, var būt modulis darbam ar nginx, un tajā būs tas, kas un tikai tas, kas nepieciešams darbam ar nginx, vai arī var būt modulis darbam ar PHP utt.

Moduļiem tiek veiktas versijas, un tiek atbalstītas arī moduļu atkarības viens no otra. Ir atvērta moduļu krātuve - Leļļu kalve.

Leļļu serverī moduļi atrodas saknes direktorija moduļu apakšdirektorijā. Katra moduļa iekšpusē ir standarta direktoriju shēma - manifesti, faili, veidnes, lib utt.

Failu struktūra modulī

Moduļa saknē var būt šādi direktoriji ar aprakstošiem nosaukumiem:

  • manifests - tajā ir manifesti
  • files - tajā ir faili
  • templates - tajā ir veidnes
  • lib — tajā ir Rubīna kods

Šis nav pilnīgs direktoriju un failu saraksts, taču šim rakstam pagaidām pietiek.

Moduļa resursu un failu nosaukumi

Dokumentācija šeit.

Moduļa resursus (klases, definīcijas) nevar nosaukt tā, kā vēlaties. Turklāt pastāv tieša atbilstība starp resursa nosaukumu un faila nosaukumu, kurā Puppet meklēs šī resursa aprakstu. Ja pārkāpjat nosaukšanas noteikumus, Puppet vienkārši neatradīs resursa aprakstu, un jūs saņemsit kompilācijas kļūdu.

Noteikumi ir vienkārši:

  • Visiem resursiem modulī ir jāatrodas moduļa nosaukumvietā. Ja modulis tiek izsaukts foo, tad jānosauc visi tajā esošie resursi foo::<anything>, vai vienkārši foo.
  • Resursam ar moduļa nosaukumu jābūt failā init.pp.
  • Citiem resursiem failu nosaukumu shēma ir šāda:
    • prefikss ar moduļa nosaukumu tiek atmests
    • visi dubultie koli, ja tādi ir, tiek aizstāti ar slīpsvītām
    • paplašinājums ir pievienots .pp

Es parādīšu ar piemēru. Pieņemsim, ka es rakstu moduli nginx. Tajā ir šādi resursi:

  • klase nginx aprakstīts manifestā init.pp;
  • klase nginx::service aprakstīts manifestā service.pp;
  • definēt nginx::server aprakstīts manifestā server.pp;
  • definēt nginx::server::location aprakstīts manifestā server/location.pp.

veidnes

Protams, jūs pats zināt, kas ir veidnes; es tās šeit sīkāk neaprakstīšu. Bet es to atstāšu katram gadījumam saite uz Vikipēdiju.

Veidņu izmantošana: veidnes nozīmi var paplašināt, izmantojot funkciju template, kas tiek nodots ceļš uz veidni. Šāda veida resursiem fails izmanto kopā ar parametru content. Piemēram, šādi:

file { '/tmp/example': content => template('modulename/templatename.erb')

Skatīt ceļu <modulename>/<filename> nozīmē failu <rootdir>/modules/<modulename>/templates/<filename>.

Turklāt ir funkcija inline_template — tas saņem veidnes tekstu kā ievadi, nevis faila nosaukumu.

Veidnēs varat izmantot visus Leļļu mainīgos pašreizējā tvērumā.

Puppet atbalsta veidnes ERB un EPP formātā:

Īsi par ERB

Kontroles struktūras:

  • <%= ВЫРАЖЕНИЕ %> — ievieto izteiksmes vērtību
  • <% ВЫРАЖЕНИЕ %> — aprēķināt izteiksmes vērtību (neievietojot to). Šeit parasti tiek iekļauti nosacījuma paziņojumi (ja) un cilpas (katrs).
  • <%# КОММЕНТАРИЙ %>

Izteiksmes ERB ir rakstītas rubīnā (ERB faktiski ir iegultais rubīns).

Lai piekļūtu mainīgajiem no manifesta, ir jāpievieno @ uz mainīgā nosaukumu. Lai noņemtu rindiņas pārtraukumu, kas parādās pēc vadības konstrukcijas, ir jāizmanto beigu atzīme -%>.

Veidnes izmantošanas piemērs

Pieņemsim, ka es rakstu moduli, lai kontrolētu ZooKeeper. Par konfigurācijas izveidi atbildīgā klase izskatās apmēram šādi:

class zookeeper::configure (
  Array[String] $nodes,
  Integer $port_client,
  Integer $port_quorum,
  Integer $port_leader,
  Hash[String, Any] $properties,
  String $datadir,
) {
  file { '/etc/zookeeper/conf/zoo.cfg':
    ensure  => present,
    content => template('zookeeper/zoo.cfg.erb'),
  }
}

Un atbilstošā veidne zoo.cfg.erb - Tātad:

<% if @nodes.length > 0 -%>
<% @nodes.each do |node, id| -%>
server.<%= id %>=<%= node %>:<%= @port_leader %>:<%= @port_quorum %>;<%= @port_client %>
<% end -%>
<% end -%>

dataDir=<%= @datadir %>

<% @properties.each do |k, v| -%>
<%= k %>=<%= v %>
<% end -%>

Fakti un iebūvētie mainīgie

Bieži vien konkrētā konfigurācijas daļa ir atkarīga no tā, kas pašlaik notiek mezglā. Piemēram, atkarībā no Debian laidiena ir jāinstalē viena vai cita pakotnes versija. To visu var pārraudzīt manuāli, pārrakstot manifestus, ja mezgli mainās. Bet tā nav nopietna pieeja; automatizācija ir daudz labāka.

Lai iegūtu informāciju par mezgliem, Puppet ir mehānisms, ko sauc par faktiem. Dati - šī ir informācija par mezglu, kas ir pieejama manifestos parastu mainīgo veidā globālajā nosaukumu telpā. Piemēram, resursdatora nosaukums, operētājsistēmas versija, procesora arhitektūra, lietotāju saraksts, tīkla saskarņu saraksts un to adreses un daudz kas cits. Fakti ir pieejami manifestos un veidnēs kā regulāri mainīgie.

Piemērs darbam ar faktiem:

notify { "Running OS ${facts['os']['name']} version ${facts['os']['release']['full']}": }
# ресурс типа notify просто выводит сообщение в лог

Formāli runājot, faktam ir nosaukums (virkne) un vērtība (ir pieejami dažādi veidi: virknes, masīvi, vārdnīcas). Ēst iebūvēto faktu kopums. Varat arī uzrakstīt savu. Faktu apkopotāji ir aprakstīti līdzīgas funkcijas Rubyvai kā izpildāmos failus. Faktus var uzrādīt arī formā teksta faili ar datiem uz mezgliem.

Darbības laikā leļļu aģents vispirms kopē visus pieejamos faktu apkopotājus no pappetservera uz mezglu, pēc tam tos palaiž un nosūta savāktos faktus uz serveri; Pēc tam serveris sāk apkopot katalogu.

Fakti izpildāmo failu veidā

Šādi fakti tiek ievietoti direktorijā moduļos facts.d. Protams, failiem jābūt izpildāmiem. Palaižot, tiem ir jāizvada informācija standarta izvadē YAML vai atslēga=vērtība formātā.

Neaizmirstiet, ka fakti attiecas uz visiem mezgliem, kurus kontrolē poppet serveris, kurā ir izvietots jūsu modulis. Tāpēc skriptā pārbaudiet, vai sistēmā ir visas programmas un faili, kas nepieciešami jūsu fakta darbībai.

#!/bin/sh
echo "testfact=success"
#!/bin/sh
echo '{"testyamlfact":"success"}'

Rubīna fakti

Šādi fakti tiek ievietoti direktorijā moduļos lib/facter.

# всё начинается с вызова функции Facter.add с именем факта и блоком кода
Facter.add('ladvd') do
# в блоках confine описываются условия применимости факта — код внутри блока должен вернуть true, иначе значение факта не вычисляется и не возвращается
  confine do
    Facter::Core::Execution.which('ladvdc') # проверим, что в PATH есть такой исполняемый файл
  end
  confine do
    File.socket?('/var/run/ladvd.sock') # проверим, что есть такой UNIX-domain socket
  end
# в блоке setcode происходит собственно вычисление значения факта
  setcode do
    hash = {}
    if (out = Facter::Core::Execution.execute('ladvdc -b'))
      out.split.each do |l|
        line = l.split('=')
        next if line.length != 2
        name, value = line
        hash[name.strip.downcase.tr(' ', '_')] = value.strip.chomp(''').reverse.chomp(''').reverse
      end
    end
    hash  # значение последнего выражения в блоке setcode является значением факта
  end
end

Teksta fakti

Šādi fakti tiek ievietoti direktorija mezglos /etc/facter/facts.d vecajā Leļļu vai /etc/puppetlabs/facts.d jaunajā Leļļu.

examplefact=examplevalue
---
examplefact2: examplevalue2
anotherfact: anothervalue

Nokļūšana pie faktiem

Ir divi veidi, kā pievērsties faktiem:

  • caur vārdnīcu $facts: $facts['fqdn'];
  • izmantojot fakta nosaukumu kā mainīgā nosaukumu: $fqdn.

Vislabāk ir izmantot vārdnīcu $facts, vai vēl labāk, norādiet globālo nosaukumvietu ($::facts).

Šeit ir attiecīgā dokumentācijas sadaļa.

Iebūvētie mainīgie

Papildus faktiem ir arī daži mainīgie, pieejams globālajā nosaukumvietā.

  • uzticami fakti — mainīgie, kas tiek ņemti no klienta sertifikāta (tā kā sertifikāts parasti tiek izsniegts poppet serverī, aģents nevar vienkārši paņemt un mainīt savu sertifikātu, tāpēc mainīgie ir “uzticami”): sertifikāta nosaukums, sertifikāta nosaukums. resursdators un domēns, sertifikāta paplašinājumi.
  • servera fakti — mainīgie, kas saistīti ar informāciju par serveri — versija, nosaukums, servera IP adrese, vide.
  • aģentu fakti — mainīgie, ko tieši pievieno leļļu aģents, nevis faktors — sertifikāta nosaukums, aģenta versija, marionetes versija.
  • galvenais mainīgie - Pappetmaster mainīgie (sic!). Tas ir apmēram tāds pats kā iekšā servera fakti, kā arī ir pieejamas konfigurācijas parametru vērtības.
  • kompilatoru mainīgie — kompilatora mainīgie, kas atšķiras katrā tvērumā: pašreizējā moduļa nosaukums un tā moduļa nosaukums, kurā tika piekļūts pašreizējam objektam. Tos var izmantot, piemēram, lai pārbaudītu, vai jūsu privātās nodarbības netiek izmantotas tieši no citiem moduļiem.

1. papildinājums: kā to visu palaist un atkļūdot?

Rakstā bija daudz leļļu koda piemēru, taču mums vispār netika norādīts, kā palaist šo kodu. Nu es sevi laboju.

Lai palaistu Puppet, pietiek ar aģentu, taču vairumā gadījumu jums būs nepieciešams arī serveris.

Aģents

Vismaz kopš versijas XNUMX, marionet-agent pakotnes no oficiālā Puppetlabs krātuve satur visas atkarības (rubīns un atbilstošie dārgakmeņi), tāpēc nav nekādu instalēšanas grūtību (es runāju par uz Debian balstītiem izplatījumiem — mēs neizmantojam uz RPM balstītus izplatījumus).

Vienkāršākajā gadījumā, lai izmantotu leļļu konfigurāciju, pietiek ar aģenta palaišanu bezservera režīmā: ar nosacījumu, ka leļļu kods ir kopēts mezglā, palaidiet puppet apply <путь к манифесту>:

atikhonov@atikhonov ~/puppet-test $ cat helloworld.pp 
node default {
    notify { 'Hello world!': }
}
atikhonov@atikhonov ~/puppet-test $ puppet apply helloworld.pp 
Notice: Compiled catalog for atikhonov.localdomain in environment production in 0.01 seconds
Notice: Hello world!
Notice: /Stage[main]/Main/Node[default]/Notify[Hello world!]/message: defined 'message' as 'Hello world!'
Notice: Applied catalog in 0.01 seconds

Protams, labāk ir iestatīt serveri un palaist aģentus mezglos dēmona režīmā - tad reizi pusstundā viņi lietos no servera lejupielādēto konfigurāciju.

Jūs varat atdarināt darba push modeli - dodieties uz jūs interesējošo mezglu un sāciet sudo puppet agent -t. Atslēga -t (--test) faktiski ietver vairākas opcijas, kuras var iespējot atsevišķi. Šīs opcijas ir šādas:

  • nedarbiniet dēmonu režīmā (pēc noklusējuma aģents startē dēmona režīmā);
  • izslēgt pēc kataloga lietošanas (pēc noklusējuma aģents turpinās strādāt un lietot konfigurāciju reizi pusstundā);
  • uzrakstīt detalizētu darba žurnālu;
  • parādīt izmaiņas failos.

Aģentam ir darbības režīms bez izmaiņām - to var izmantot, kad neesat pārliecināts, ka esat uzrakstījis pareizo konfigurāciju un vēlaties pārbaudīt, ko tieši aģents darbības laikā mainīs. Šo režīmu iespējo parametrs --noop komandrindā: sudo puppet agent -t --noop.

Turklāt jūs varat iespējot darba atkļūdošanas žurnālu - tajā marionete raksta par visām darbībām, ko tā veic: par resursu, ko tā pašlaik apstrādā, par šī resursa parametriem, par to, kādas programmas tas palaiž. Protams, tas ir parametrs --debug.

Serveris

Šajā rakstā es neapskatīšu pilnu pappetservera iestatīšanu un koda izvietošanu tajā; teikšu tikai to, ka ir pieejama pilnībā funkcionējoša servera versija, kurai nav nepieciešama papildu konfigurācija, lai strādātu ar nelielu skaitu mezgli (teiksim, līdz simtam). Lielākam mezglu skaitam būs nepieciešama regulēšana - pēc noklusējuma leļļu serveris palaiž ne vairāk kā četrus darbiniekus, lai nodrošinātu lielāku veiktspēju, jums jāpalielina to skaits un neaizmirstiet palielināt atmiņas ierobežojumus, pretējā gadījumā serveris lielāko daļu laika savāks atkritumus.

Koda izvietošana — ja jums tas ir nepieciešams ātri un vienkārši, skatieties (r10k)[https://github.com/puppetlabs/r10k], mazām instalācijām ar to vajadzētu pietikt.

2. papildinājums: Kodēšanas vadlīnijas

  1. Ievietojiet visu loģiku klasēs un definīcijās.
  2. Klases un definīcijas saglabājiet moduļos, nevis mezglus aprakstošos manifestos.
  3. Izmantojiet faktus.
  4. Neveidojiet if, pamatojoties uz saimniekdatora nosaukumiem.
  5. Jūtieties brīvi pievienot parametrus klasēm un definīcijām — tas ir labāk nekā klases/definēšanas pamattekstā paslēpta netieša loģika.

Kāpēc es ieteiktu to darīt, es paskaidrošu nākamajā rakstā.

Secinājums

Beigsim ar ievadu. Nākamajā rakstā pastāstīšu par Hiera, ENC un PuppetDB.

Aptaujā var piedalīties tikai reģistrēti lietotāji. Ielogoties, lūdzu.

Patiesībā materiālu ir daudz vairāk - varu rakstīt rakstus par šādām tēmām, balsot par to, par ko būtu interesanti lasīt:

  • 59,1%Uzlabotas leļļu konstrukcijas — daži nākamā līmeņa sūdi: cilpas, kartēšana un citas lambda izteiksmes, resursu savācēji, eksportētie resursi un savstarpējā saziņa, izmantojot Puppet, tagi, nodrošinātāji, abstrakti datu tipi.13
  • 31,8%“I’m my mother’s admin” jeb kā mēs Avito sadraudzējāmies ar vairākiem dažādu versiju poppet serveriem, un principā daļa par poppet servera administrēšanu.7
  • 81,8%Kā mēs rakstām leļļu kodu: instrumenti, dokumentācija, testēšana, CI/CD.18

Nobalsoja 22 lietotāji. 9 lietotāji atturējās.

Avots: www.habr.com