Yntroduksje ta Puppet

Puppet is in konfiguraasjebehearsysteem. It wurdt brûkt om hosts nei de winske steat te bringen en dizze steat te behâlden.

Ik wurkje no mear as fiif jier mei Puppet. Dizze tekst is yn essinsje in oersette en opnij oardere kompilaasje fan wichtige punten út 'e offisjele dokumintaasje, wêrtroch begjinners de essinsje fan Puppet fluch kinne begripe.

Yntroduksje ta Puppet

Basisynformaasje

It bestjoeringssysteem fan Puppet is client-server, hoewol it ek serverless operaasje stipet mei beheinde funksjonaliteit.

In pull model fan operaasje wurdt brûkt: standert, ien kear elk heal oere, kliïnten kontakt de tsjinner foar in konfiguraasje en tapasse it. As jo ​​mei Ansible wurke hawwe, brûke se in oar pushmodel: de behearder begjint it proses fan it tapassen fan de konfiguraasje, de kliïnten sels sille neat tapasse.

Tidens netwurkkommunikaasje wurdt twa-wei TLS-fersifering brûkt: de tsjinner en kliïnt hawwe har eigen privee kaaien en oerienkommende sertifikaten. Typysk jout de tsjinner sertifikaten út foar kliïnten, mar yn prinsipe is it mooglik om in eksterne CA te brûken.

Ynlieding ta manifesten

In Puppet terminology nei de poppentsjinner ferbine knopen (knooppunten). De konfiguraasje foar de knopen wurdt skreaun yn manifesten yn in spesjale programmeartaal - Puppet DSL.

Puppet DSL is in deklarative taal. It beskriuwt de winske steat fan it knooppunt yn 'e foarm fan ferklearrings fan yndividuele middels, bygelyks:

  • It bestân bestiet en hat spesifike ynhâld.
  • It pakket is ynstalleare.
  • De tsjinst is begûn.

Boarnen kinne mei-inoar ferbûn wurde:

  • D'r binne ôfhinklikens, se beynfloedzje de folchoarder wêryn boarnen wurde brûkt.
    Bygelyks, "ynstallearje earst it pakket, bewurkje dan it konfiguraasjebestân, en begjin dan de tsjinst."
  • D'r binne notifikaasjes - as in boarne is feroare, stjoert it notifikaasjes nei de boarnen dy't har ynskreaun binne.
    Bygelyks, as it konfiguraasjetriem feroaret, kinne jo de tsjinst automatysk opnij starte.

Derneist hat de Puppet DSL funksjes en fariabelen, lykas betingsten útspraken en selectors. Ferskate sjabloanmeganismen wurde ek stipe - EPP en ERB.

Puppet is skreaun yn Ruby, sadat in protte fan 'e konstruksjes en termen dêrwei nommen binne. Ruby lit jo Puppet útwreidzje - komplekse logika tafoegje, nije soarten boarnen, funksjes.

Wylst Puppet rint, wurde manifesten foar elke spesifike knooppunt op 'e tsjinner gearstald yn in map. directory is in list fan middels en harren relaasjes nei it berekkenjen fan de wearde fan funksjes, fariabelen en útwreiding fan betingsten útspraken.

Syntaksis en codestyle

Hjir binne seksjes fan 'e offisjele dokumintaasje dy't jo sille helpe de syntaksis te begripen as de levere foarbylden net genôch binne:

Hjir is in foarbyld fan hoe't it manifest derút sjocht:

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

Ynspringing en line breaks binne gjin ferplichte diel fan it manifest, mar der is in oanrikkemandearre stylgids. Gearfetting:

  • Twa-romte ynspringen, ljeppers wurde net brûkt.
  • Krullende beugels wurde skieden troch in spaasje;
  • Komma's nei elke parameter, ynklusyf de lêste. Elke parameter is op in aparte line. In útsûndering wurdt makke foar it gefal sûnder parameters en ien parameter: jo kinne op ien rigel en sûnder komma skriuwe (d.w.s. resource { 'title': } и resource { 'title': param => value }).
  • De pylken op 'e parameters moatte op itselde nivo wêze.
  • Boarne relaasje pylken binne skreaun foar harren.

Lokaasje fan triemmen op pappetserver

Foar fierdere útlis sil ik it konsept fan "root directory" yntrodusearje. De root-map is de map dy't de Puppet-konfiguraasje befettet foar in spesifike knooppunt.

De root-map ferskilt ôfhinklik fan de ferzje fan Puppet en de brûkte omjouwings. Omjouwings binne ûnôfhinklike sets fan konfiguraasje dy't wurde opslein yn aparte mappen. Gewoanlik brûkt yn kombinaasje mei git, yn hokker gefal wurde omjouwings makke fan git-tûken. Dêrnjonken leit elke knooppunt yn ien of oare omjouwing. Dit kin wurde konfigureare op it knooppunt sels, of yn ENC, dêr't ik oer sil prate yn it folgjende artikel.

  • Yn 'e tredde ferzje ("âlde Puppet") wie de basismap /etc/puppet. It gebrûk fan omjouwings is opsjoneel - wy brûke se bygelyks net mei de âlde Puppet. As omjouwings wurde brûkt, wurde se normaal opslein yn /etc/puppet/environments, sil de rootmap de omjouwingsmap wêze. As omjouwings net brûkt wurde, sil de root-map de basismap wêze.
  • Fanôf de fjirde ferzje ("nije Puppet") waard it gebrûk fan omjouwings ferplicht, en de basismap waard ferpleatst nei /etc/puppetlabs/code. Dêrtroch wurde omjouwings opslein yn /etc/puppetlabs/code/environments, root-map is de omjouwingsmap.

D'r moat in submap wêze yn 'e rootmap manifests, dy't ien of mear manifesten befettet dy't de knopen beskriuwe. Dêrneist moat der in submap wêze modules, dy't de modules befettet. Ik sil jo fertelle wat modules binne in bytsje letter. Derneist kin de âlde Puppet ek in submap hawwe files, dy't ferskate triemmen befettet dy't wy kopiearje nei de knopen. Yn de nije Puppet wurde alle bestannen yn modules pleatst.

Manifestbestannen hawwe de tafoeging .pp.

In pear combat foarbylden

Beskriuwing fan it knooppunt en boarne derop

Op it knooppunt server1.testdomain in triem moat oanmakke wurde /etc/issue mei ynhâld Debian GNU/Linux n l. It bestân moat eigendom wêze fan in brûker en groep root, tagongsrjochten moatte wêze 644.

Wy skriuwe in manifest:

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 в начале будет воспринято как записанное в восьмеричной системе, и всё пойдёт не так, как задумано
    }
}

Relaasjes tusken boarnen op in knooppunt

Op it knooppunt server2.testdomain nginx moat rinne, wurkje mei in earder taret konfiguraasje.

Litte wy it probleem ûntdekke:

  • It pakket moat ynstalleare wurde nginx.
  • It is needsaaklik dat de konfiguraasjetriemmen wurde kopieare fan 'e tsjinner.
  • De tsjinst moat rinne nginx.
  • As de konfiguraasje bywurke is, moat de tsjinst opnij starte wurde.

Wy skriuwe in manifest:

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 получает уведомление,
  # соответствующий сервис перезапускается.
}

Om dit te wurkjen hawwe jo sawat de folgjende triemlokaasje nedich op 'e poppenserver:

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

Resource Soarten

In folsleine list mei stipe boarnetypen is hjir te finen yn 'e dokumintaasje, Hjir sil ik fiif basistypen beskriuwe, dy't yn myn praktyk genôch binne om de measte problemen op te lossen.

map

Beheart bestannen, mappen, symlinks, har ynhâld en tagongsrjochten.

Parameters:

  • boarne namme - paad nei it bestân (opsjoneel)
  • paad - paad nei it bestân (as it net is oantsjutte yn 'e namme)
  • soargje - triemtype:
    • absent - in triem wiskje
    • present - d'r moat in bestân fan elk type wêze (as d'r gjin bestân is, sil in gewoane bestân oanmakke wurde)
    • file - gewoane triem
    • directory - map
    • link - symboal
  • ynhâld - bestânynhâld (allinich geskikt foar gewoane bestannen, kin net wurde brûkt tegearre mei boarne of doel)
  • boarne - in keppeling nei it paad wêrfan jo de ynhâld fan it bestân kopiearje wolle (kin net tegearre mei ynhâld of doel). Kin wurde oantsjutte as in URI mei in skema puppet: (dan wurde bestannen fan 'e poppentsjinner brûkt), en mei it skema http: (Ik hoopje dat it is dúdlik wat sil barre yn dit gefal), en sels mei it diagram file: of as in absolút paad sûnder skema (dan sil it bestân fan 'e lokale FS op' e node brûkt wurde)
  • doel - wêr't de symlink moat wize (kin net tegearre mei ynhâld of boarne)
  • eigner - de brûker dy't it bestân besit moat
  • groep - de groep dêr't de triem ta hearre moat
  • wize - triemrjochten (as in tekenrige)
  • recurse - makket rekursive mapferwurking mooglik
  • reinigen - makket it mooglik om bestannen te wiskjen dy't net beskreaun binne yn Puppet
  • krêft - makket it mooglik om mappen te wiskjen dy't net beskreaun binne yn Puppet

pakket

Ynstallearret en ferwideret pakketten. Yn steat om notifikaasjes te behanneljen - set it pakket opnij yn as de parameter is oantsjutte reinstall_on_refresh.

Parameters:

  • boarne namme - pakketnamme (opsjoneel)
  • namme - pakketnamme (as net opjûn yn 'e namme)
  • provider - pakketbehearder om te brûken
  • soargje - winske tastân fan it pakket:
    • present, installed - eltse ferzje ynstallearre
    • latest - lêste ferzje ynstallearre
    • absent - wiske (apt-get remove)
    • purged - wiske tegearre mei konfiguraasjebestannen (apt-get purge)
    • held - pakketferzje is beskoattele (apt-mark hold)
    • любая другая строка - de oantsjutte ferzje is ynstalleare
  • reinstall_on_refresh - as a true, dan sil nei ûntfangst fan 'e notifikaasje it pakket opnij ynstalleare wurde. Nuttich foar boarne-basearre distribúsjes, wêrby't opnij opbou fan pakketten nedich wêze kin by it feroarjen fan buildparameters. Standert false.

betsjinning

Beheart tsjinsten. Yn steat om notifikaasjes te ferwurkjen - start de tsjinst opnij.

Parameters:

  • boarne namme - te behearjen tsjinst (opsjoneel)
  • namme - de tsjinst dy't moat wurde beheard (as net spesifisearre yn 'e namme)
  • soargje - winske steat fan 'e tsjinst:
    • running - lansearre
    • stopped - stoppe
  • aktivearje - kontrolearret de mooglikheid om de tsjinst te begjinnen:
    • true - autorun is ynskeakele (systemctl enable)
    • mask - ferklaaid (systemctl mask)
    • false - autorun is útskeakele (systemctl disable)
  • opnij begjinne - kommando om de tsjinst opnij te begjinnen
  • status - kommando om tsjinststatus te kontrolearjen
  • hasrestart - oanjaan oft de tsjinst initscript stipet opnij starte. As false en de parameter wurdt oantsjutte opnij begjinne - de wearde fan dizze parameter wurdt brûkt. As false en parameter opnij begjinne net spesifisearre - de tsjinst wurdt stoppe en begon te opnij starte (mar systemd brûkt it kommando systemctl restart).
  • hasstatus - oanjaan oft de tsjinst initscript it kommando stipet status. As false, dan wurdt de parameterwearde brûkt status. Standert true.

exec

Rint eksterne kommando's. As jo ​​gjin parameters oantsjutte skeelt, allinnich as, of it moast wêze dat of ferfrissend, sil it kommando elke kear útfierd wurde Puppet wurdt útfierd. Yn steat om notifikaasjes te ferwurkjen - rint in kommando út.

Parameters:

  • boarne namme - útfiere kommando (opsjoneel)
  • befel - it út te fieren kommando (as it net yn 'e namme is spesifisearre)
  • paad - paden wêryn te sykjen nei it útfierbere bestân
  • allinnich as - as it kommando oantsjutte yn dizze parameter foltôge is mei in nul weromkearkoade, sil it haadkommando wurde útfierd
  • of it moast wêze dat - as it kommando spesifisearre yn dizze parameter foltôge is mei in weromkearkoade net nul, sil it haadkommando wurde útfierd
  • skeelt - as de triem oantsjutte yn dizze parameter net bestiet, sil it haadkommando wurde útfierd
  • ferfrissend - as a true, dan sil it kommando allinich útfierd wurde as dizze exec notifikaasje ûntfangt fan oare boarnen
  • cwd - map wêrút it kommando útfiere moat
  • brûker - de brûker fan wa't it kommando útfiere moat
  • provider - hoe't jo it kommando útfiere:
    • posix - in bernproses wurdt gewoan makke, wês wis dat jo spesifisearje paad
    • shell - it kommando wurdt lansearre yn 'e shell /bin/sh, meie net oantsjutte paad, Jo kinne globbing, pipes en oare shellfunksjes brûke. Meastentiids automatysk ûntdutsen as d'r spesjale tekens binne (|, ;, &&, || ensafuorthinne).

Cron

Kontrolearret cronjobs.

Parameters:

  • boarne namme - gewoan in soarte fan identifier
  • soargje - crownjob steat:
    • present - meitsje as net bestiet
    • absent - wiskje as bestiet
  • befel - hokker kommando te rinnen
  • miljeu - yn hokker omjouwing it kommando útfiere (list mei omjouwingsfariabelen en har wearden fia =)
  • brûker - fan hokker brûker it kommando útfiere moat
  • minút, oere, wurkdei, moanne, moannedei - wannear te rinnen cron. As ien fan dizze attributen net oantsjutte is, sil de wearde yn 'e crontab wêze *.

Yn Puppet 6.0 Cron as fuorthelle út it fak yn puppetserver, dus d'r is gjin dokumintaasje op 'e algemiene side. Mar hy is yn it fak yn puppet-agent, dus it is net nedich om it apart te ynstallearjen. Jo kinne dêr de dokumintaasje foar sjen yn 'e dokumintaasje foar de fyfde ferzje fan Puppet, of op GitHub.

Oer middels yn it algemien

Easken foar eigenheid fan boarnen

De meast foarkommende flater dy't wy tsjinkomme is Dûbele ferklearring. Dizze flater bart as twa of mear boarnen fan itselde type mei deselde namme ferskine yn 'e map.

Dêrom sil ik nochris skriuwe: manifesten foar deselde knoop moatte net befetsje boarnen fan itselde type mei deselde titel!

Soms is d'r needsaak om pakketten te ynstallearjen mei deselde namme, mar mei ferskate pakketbehearders. Yn dit gefal moatte jo de parameter brûke nameom de flater te foarkommen:

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

Oare boarnetypen hawwe ferlykbere opsjes om duplikaasje te foarkommen - name у betsjinning, command у exec, ensafuorthinne.

Metaparameters

Elk type boarne hat wat spesjale parameters, nettsjinsteande syn aard.

Folsleine list fan meta parameters yn de Puppet dokumintaasje.

Koarte list:

  • fereaskje - dizze parameter jout oan fan hokker boarnen dizze boarne hinget.
  • foar - Dizze parameter spesifisearret hokker boarnen ôfhinklik binne fan dizze boarne.
  • ynskriuwe - dizze parameter spesifisearret út hokker boarnen dizze boarne notifikaasjes ûntfangt.
  • oanskriuwe - Dizze parameter spesifiseart hokker boarnen notifikaasjes ûntfange fan dizze boarne.

Alle neamde metaparameters akseptearje of in inkele boarne keppeling of in array fan keppelings yn fjouwerkante heakjes.

Keppelings nei boarnen

In boarne keppeling is gewoan in fermelding fan 'e boarne. Se wurde benammen brûkt om ôfhinklikens oan te jaan. It ferwizen fan in net-besteande boarne sil in kompilaasjeflater feroarsaakje.

De syntaksis fan 'e keppeling is as folget: boarnetype mei in haadletter (as de typenamme dûbele kolons befettet, dan wurdt elk diel fan 'e namme tusken de kolons mei haadletters), dan de boarnenamme yn fjouwerkante heakjes (it gefal fan 'e namme feroaret net!). Der moatte gjin spaasjes steane fjouwerkante heakjes direkt efter de typenamme.

Foarbyld:

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

Ofhinklikens en notifikaasjes

Dokumintaasje hjir.

Lykas earder sein, binne ienfâldige ôfhinklikens tusken boarnen transityf. Trouwens, wês foarsichtich by it tafoegjen fan ôfhinklikens - jo kinne sykliske ôfhinklikens oanmeitsje, wat in kompilaasjeflater sil feroarsaakje.

Oars as ôfhinklikens binne notifikaasjes net transityf. De folgjende regels jilde foar notifikaasjes:

  • As de boarne in notifikaasje ûntfangt, wurdt it bywurke. De fernijingsaksjes binne ôfhinklik fan it type boarne - exec rint it kommando út, betsjinning herstart de tsjinst, pakket reinstalls it pakket. As de boarne gjin updateaksje hat definieare, dan bart der neat.
  • Tidens ien run fan Puppet wurdt de boarne net mear as ien kear bywurke. Dit is mooglik om't notifikaasjes ôfhinklikens befetsje en de ôfhinklikensgrafyk gjin syklusen befettet.
  • As Puppet de tastân fan in boarne feroaret, stjoert de boarne notifikaasjes nei alle boarnen dy't har ynskreaun binne.
  • As in boarne wurdt bywurke, stjoert it notifikaasjes nei alle boarnen dy't har ynskreaun binne.

It behanneljen fan net spesifisearre parameters

As regel, as guon boarne parameter hat gjin standert wearde en dizze parameter is net oantsjutte yn it manifest, dan sil Puppet net feroarje dit eigendom foar de oerienkommende boarne op it knooppunt. Bygelyks, as in boarne fan type map parameter net oantsjutte owner, dan sil Puppet de eigner fan it oerienkommende bestân net feroarje.

Ynlieding ta klassen, fariabelen en definysjes

Stel dat wy ferskate knopen hawwe dy't itselde diel fan 'e konfiguraasje hawwe, mar d'r binne ek ferskillen - oars kinne wy ​​it allegear yn ien blok beskriuwe node {}. Fansels kinne jo gewoan identike dielen fan 'e konfiguraasje kopiearje, mar yn' t algemien is dit in minne oplossing - de konfiguraasje groeit, en as jo it algemiene diel fan 'e konfiguraasje feroarje, moatte jo itselde ding op in protte plakken bewurkje. Tagelyk is it maklik om in flater te meitsjen, en yn 't algemien is it DRY-prinsipe (net werhelje dysels) foar in reden útfûn.

Om dit probleem op te lossen is d'r sa'n ûntwerp as класс.

Klassen

Klasse is in neamd blok fan poppetkoade. Klassen binne nedich om koade opnij te brûken.

Earst moat de klasse beskreaun wurde. De beskriuwing sels foeget oeral gjin boarnen ta. De klasse wurdt beskreaun yn manifesten:

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

Hjirnei kin de klasse brûkt wurde:

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

In foarbyld fan 'e foarige taak - lit ús de ynstallaasje en konfiguraasje fan nginx ferpleatse nei in klasse:

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
}

Fariabelen

De klasse fan it foarige foarbyld is hielendal net fleksibel, om't it altyd deselde nginx-konfiguraasje bringt. Litte wy it paad meitsje nei de konfiguraasjefariabele, dan kin dizze klasse brûkt wurde om nginx te ynstallearjen mei elke konfiguraasje.

It kin dien wurde mei help fan fariabelen.

Oandacht: fariabelen yn Puppet binne ûnferoarlik!

Dêrnjonken kin in fariabele pas tagonklik wurde nei't dizze ferklearre is, oars sil de wearde fan 'e fariabele wêze undef.

Foarbyld fan wurkjen mei fariabelen:

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

Puppet hat nammeromten, en de fariabelen, neffens, hawwe gebiet fan sichtberens: In fariabele mei deselde namme kin definiearre wurde yn ferskate nammeromten. By it oplossen fan de wearde fan in fariabele wurdt de fariabele socht yn 'e aktuele nammeromte, dan yn 'e omlizzende nammeromte, ensfh.

Foarbylden fan nammeromte:

  • global - fariabelen bûten de klasse of knooppunt beskriuwing gean dêr;
  • node nammeromte yn de node beskriuwing;
  • klasse nammeromte yn 'e klasse beskriuwing.

Om ûndúdlikens te foarkommen by tagong ta in fariabele, kinne jo de nammeromte yn 'e fariabelenamme opjaan:

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

Litte wy it iens wêze dat it paad nei de nginx-konfiguraasje leit yn 'e fariabele $nginx_conf_source. Dan sjocht de klasse der sa út:

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
}

It opjûne foarbyld is lykwols min, om't der wat "geheime kennis" is dat earne yn 'e klasse in fariabele mei sa'n en sa'n namme brûkt wurdt. It is folle krekter om dizze kennis algemien te meitsjen - klassen kinne parameters hawwe.

Klasse parameters binne fariabelen yn 'e klasse nammeromte, se wurde oantsjutte yn' e klasse koptekst en kin brûkt wurde as reguliere fariabelen yn de klasse lichem. Parameterwearden wurde oanjûn by it brûken fan de klasse yn it manifest.

De parameter kin ynsteld wurde op in standertwearde. As in parameter gjin standertwearde hat en de wearde is net ynsteld by it brûken, sil it in kompilaasjeflater feroarsaakje.

Litte wy de klasse út it hjirboppe foarbyld parameterisearje en twa parameters tafoegje: de earste, fereaske, is it paad nei de konfiguraasje, en de twadde, opsjoneel, is de namme fan it pakket mei nginx (yn Debian, bygelyks, binne d'r pakketten 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',   # задаём параметры класса точно так же, как параметры для других ресурсов
  }
}

Yn Puppet wurde fariabelen typt. Ite in protte gegevens typen. Gegevenstypen wurde typysk brûkt om parameterwearden te validearjen dy't trochjûn binne oan klassen en definysjes. As de trochjûn parameter net oerienkomt mei it opjûne type, sil in kompilaasjeflater foarkomme.

It type wurdt skreaun direkt foar de parameter namme:

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

Klassen: befetsje klassenamme vs klasse {'classname':}

Elke klasse is in boarne fan type klasse. Lykas by alle oare soart boarnen kinne d'r net twa eksimplaren fan deselde klasse op deselde knoop wêze.

As jo ​​besykje te foegjen in klasse oan deselde node twa kear mei help class { 'classname':} (gjin ferskil, mei ferskillende of identike parameters), der sil in kompilaasje flater. Mar as jo in klasse brûke yn 'e boarnestyl, kinne jo al har parameters fuortendaliks yn it manifest ynstelle.

Lykwols, as jo brûke include, dan kin de klasse safolle kearen tafoege wurde as jo wolle. It feit is dat include is in idempotinte funksje dy't kontrolearret oft in klasse is tafoege oan de map. As de klasse net yn 'e map is, foeget it ta, en as it al bestiet, docht it neat. Mar yn gefal fan gebrûk include Jo kinne net ynstelle klasse parameters tidens klasse ferklearring - alle fereaske parameters moatte wurde ynsteld yn in eksterne gegevens boarne - Hiera of ENC. Wy sille prate oer harren yn it folgjende artikel.

Defines

Lykas sein waard yn it foarige blok, kin deselde klasse net mear as ien kear oanwêzich wêze op in knooppunt. Yn guon gefallen moatte jo lykwols itselde blok koade kinne brûke mei ferskate parameters op deselde knooppunt. Mei oare wurden, der is ferlet fan in eigen boarne type.

Bygelyks, om de PHP-module te ynstallearjen, dogge wy it folgjende yn Avito:

  1. Ynstallearje it pakket mei dizze module.
  2. Litte wy in konfiguraasjetriem meitsje foar dizze module.
  3. Wy meitsje in symlink nei de konfiguraasje foar php-fpm.
  4. Wy meitsje in symlink nei de konfiguraasje foar php cli.

Yn sokke gefallen, in ûntwerp lykas definiearje (define, definiearre type, definiearre boarne type). In Define is gelyk oan in klasse, mar der binne ferskillen: earst, elk Define is in boarne type, net in boarne; secondly, eltse definysje hat in ymplisite parameter $title, wêr't de boarnenamme giet as it wurdt ferklearre. Krekt as by klassen moat earst in definysje beskreaun wurde, wêrnei't dy brûkt wurde kin.

In ferienfâldige foarbyld mei in module foar PHP:

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' }
}

De maklikste manier om de Duplicate deklaraasjeflater te fangen is yn Define. Dit bart as in definysje hat in boarne mei in konstante namme, en der binne twa of mear eksimplaren fan dizze definysje op guon node.

It is maklik om josels tsjin dit te beskermjen: alle boarnen binnen de definysje moatte in namme hawwe ôfhinklik fan $title. In alternatyf is idempotent tafoeging fan middels yn it simpelste gefal, it is genôch om te ferpleatsen de middels mienskiplik foar alle eksimplaren fan de definysje yn in aparte klasse en befetsje dizze klasse yn de definysje - funksje; include idempotent.

D'r binne oare manieren om idempotens te berikken by it tafoegjen fan boarnen, nammentlik it brûken fan funksjes defined и ensure_resources, mar ik sil fertelle oer it yn de folgjende ôflevering.

Ofhinklikens en notifikaasjes foar klassen en definysjes

Klassen en definysjes foegje de folgjende regels ta oan it behanneljen fan ôfhinklikens en notifikaasjes:

  • ôfhinklikens fan in klasse / definiearje foeget ôfhinklikens oan alle middels fan 'e klasse / definiearje;
  • in klasse / definiearje ôfhinklikens foeget ôfhinklikens oan alle klasse / definiearje boarnen;
  • klasse / definiearje notifikaasje meldt alle boarnen fan 'e klasse / definiearje;
  • klasse / definiearje abonnemint abonnearret op alle middels fan 'e klasse / definiearje.

Betingsten útspraken en selectors

Dokumintaasje hjir.

if

It is hjir ienfâldich:

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

of it moast wêze dat

útsein as in omkearde is: it blok koade sil wurde útfierd as de útdrukking falsk is.

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

rjochtsaak

D'r is hjir ek neat yngewikkeld. Jo kinne reguliere wearden (strings, sifers, ensfh.), reguliere útdrukkingen en gegevenstypen brûke as wearden.

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

Selektors

In selector is in taalkonstruksje fergelykber mei case, mar ynstee fan in blok koade út te fieren, jout it in wearde werom.

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

Modules

As de konfiguraasje lyts is, kin it maklik yn ien manifest wurde bewarre. Mar hoe mear konfiguraasjes wy beskriuwe, de mear klassen en knopen binne der yn it manifest, it groeit, en it wurdt ûngemaklik om mei te wurkjen.

Derneist is d'r it probleem fan koade opnij brûke - as alle koade yn ien manifest is, is it lestich om dizze koade mei oaren te dielen. Om dizze twa problemen op te lossen, hat Puppet in entiteit neamd modules.

Modules - dit binne sets fan klassen, definysjes en oare Puppet-entiteiten pleatst yn in aparte map. Mei oare wurden, in module is in ûnôfhinklik stik Puppet logika. Bygelyks, d'r kin in module wêze foar it wurkjen mei nginx, en it sil befetsje wat en allinich wat nedich is om te wurkjen mei nginx, of d'r kin in module wêze foar wurkjen mei PHP, ensfh.

Modules wurde ferzje, en ôfhinklikens fan modules op elkoar wurde ek stipe. D'r is in iepen repository fan modules - Puppet Forge.

Op de puppet-tsjinner lizze modules yn 'e modules submap fan' e root-map. Binnen elke module is d'r in standert mapskema - manifesten, bestannen, sjabloanen, lib, ensfh.

Bestânsstruktuer yn in module

De root fan 'e module kin de folgjende mappen befetsje mei beskriuwende nammen:

  • manifests - it befettet manifesten
  • files - it befettet bestannen
  • templates - it befettet sjabloanen
  • lib - it befettet Ruby koade

Dit is net in folsleine list fan mappen en bestannen, mar it is genôch foar dit artikel foar no.

Nammen fan boarnen en nammen fan triemmen yn 'e module

Dokumintaasje hjir.

Boarnen (klassen, definysjes) yn in module kinne net neamd wurde wat jo wolle. Dêrneist is der in direkte oerienkomst tusken de namme fan in boarne en de namme fan it bestân wêryn Puppet sil sykje nei in beskriuwing fan dy boarne. As jo ​​​​de regels foar nammen skeine, dan sil Puppet de boarnebeskriuwing gewoan net fine, en jo sille in kompilaasjeflater krije.

De regels binne ienfâldich:

  • Alle boarnen yn in module moatte yn de module nammeromte stean. As de module wurdt neamd foo, dan moatte alle boarnen dêryn neamd wurde foo::<anything>, of gewoan foo.
  • In boarne mei de namme fan de module moat yn it bestân wêze init.pp.
  • Foar oare boarnen is it bestânsnammeskema as folget:
    • it foarheaksel mei de modulenamme wurdt fuorthelle
    • alle dûbele kolons, as der binne, wurde ferfongen mei slashes
    • tafoeging wurdt tafoege .pp

Ik sil demonstrearje mei in foarbyld. Litte wy sizze dat ik in module skriuw nginx. It befettet de folgjende boarnen:

  • класс nginx beskreaun yn it manifest init.pp;
  • класс nginx::service beskreaun yn it manifest service.pp;
  • definiearje nginx::server beskreaun yn it manifest server.pp;
  • definiearje nginx::server::location beskreaun yn it manifest server/location.pp.

Templates

Wiswier jo sels witte wat sjabloanen binne, Ik sil net beskriuwe se yn detail hjir. Mar ik lit it mar foar it gefal link nei Wikipedia.

Hoe kinne jo sjabloanen brûke: De betsjutting fan in sjabloan kin útwreide wurde mei in funksje template, dat wurdt trochjûn it paad nei it sjabloan. Foar middels lykas map brûkt tegearre mei de parameter content. Bygelyks, lykas dit:

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

Besjoch paad <modulename>/<filename> ymplisearret triem <rootdir>/modules/<modulename>/templates/<filename>.

Dêrneist is der in funksje inline_template - it ûntfangt de sjabloantekst as ynfier, net de triemnamme.

Binnen sjabloanen kinne jo alle Puppet-fariabelen brûke yn 'e aktuele omfang.

Puppet stipet sjabloanen yn ERB- en EPP-formaat:

Koart oer ERB

Kontrôlestruktueren:

  • <%= ВЫРАЖЕНИЕ %> - ynfoegje de wearde fan 'e útdrukking
  • <% ВЫРАЖЕНИЕ %> - berekkenje de wearde fan in útdrukking (sûnder it ynfoegje). Betingsten útspraken (as) en loops (elk) meastal gean hjir.
  • <%# КОММЕНТАРИЙ %>

Ekspresjes yn ERB wurde skreaun yn Ruby (ERB is eins Embedded Ruby).

Om tagong te krijen ta fariabelen fan it manifest, moatte jo tafoegje @ oan de fariabele namme. Foar it fuortheljen fan in line break dy't ferskynt nei in kontrôle konstruksje, Jo moatte brûke in ôfslutende tag -%>.

Foarbyld fan it brûken fan it sjabloan

Litte wy sizze dat ik in module skriuw om ZooKeeper te kontrolearjen. De klasse ferantwurdlik foar it meitsjen fan de konfiguraasje sjocht der sa út:

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'),
  }
}

En it oerienkommende sjabloan zoo.cfg.erb - Dus:

<% 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 -%>

Feiten en ynboude fariabelen

Faak hinget it spesifike diel fan 'e konfiguraasje ôf fan wat der op it stuit op it knooppunt bart. Bygelyks, ôfhinklik fan wat Debian-release is, moatte jo ien of oare ferzje fan it pakket ynstallearje. Jo kinne dit alles manuell kontrolearje, manifestaasjes opnij skriuwe as knooppunten feroarje. Mar dit is net in serieuze oanpak automatisearring is folle better.

Om ynformaasje oer knopen te krijen, hat Puppet in meganisme neamd feiten. Feiten - dit is ynformaasje oer it knooppunt, beskikber yn manifesten yn 'e foarm fan gewoane fariabelen yn' e globale nammeromte. Bygelyks hostnamme, bestjoeringssysteemferzje, prosessorarsjitektuer, list mei brûkers, list mei netwurkynterfaces en har adressen, en folle, folle mear. Feiten binne beskikber yn manifesten en sjabloanen as reguliere fariabelen.

In foarbyld fan wurkjen mei feiten:

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

Formeel sjoen hat in feit in namme (string) en in wearde (ferskate soarten binne beskikber: snaren, arrays, wurdboeken). Ite set fan ynboude feiten. Jo kinne ek jo eigen skriuwe. Feitensamlers wurde beskreaun lykas funksjes yn Ruby, of hoe útfierbere triemmen. Feiten kinne ek presintearre wurde yn it formulier tekstbestannen mei gegevens op de knooppunten.

Tidens de operaasje kopiearret de puppet-agent earst alle beskikbere feitsamlers fan 'e pappetserver nei it knooppunt, wêrnei't it se lanseart en de sammele feiten nei de tsjinner stjoert; Hjirnei begjint de tsjinner mei it kompilearjen fan de katalogus.

Feiten yn 'e foarm fan útfierbere triemmen

Sokke feiten wurde pleatst yn modules yn 'e map facts.d. Fansels moatte de bestannen útfierber wêze. As se útfiere, moatte se ynformaasje útfiere nei standertútfier yn YAML of key=wearde-formaat.

Ferjit net dat de feiten jilde foar alle knooppunten dy't wurde regele troch de poppetserver wêrop jo module wurdt ynset. Dêrom, yn it skript, soargje derfoar dat it systeem alle programma's en bestannen hat dy't nedich binne foar jo feit om te wurkjen.

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

Ruby feiten

Sokke feiten wurde pleatst yn modules yn 'e map 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

Tekst feiten

Sokke feiten wurde pleatst op knopen yn 'e map /etc/facter/facts.d yn âlde Puppet of /etc/puppetlabs/facts.d yn de nije Puppet.

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

Getting nei de Feiten

D'r binne twa manieren om de feiten te benaderjen:

  • troch it wurdboek $facts: $facts['fqdn'];
  • it brûken fan de feitnamme as de fariabelenamme: $fqdn.

It is it bêste om in wurdboek te brûken $facts, of noch better, de globale nammeromte oanjaan ($::facts).

Hjir is de relevante seksje fan 'e dokumintaasje.

Ynboude fariabelen

Njonken de feiten is der ek guon fariabelen, beskikber yn 'e globale nammeromte.

  • fertroude feiten - fariabelen dy't wurde nommen út it sertifikaat fan 'e kliïnt (om't it sertifikaat normaal wurdt útjûn op in poppet-tsjinner, kin de agint syn sertifikaat net gewoan nimme en feroarje, sadat de fariabelen "fertroud" binne): de namme fan it sertifikaat, de namme fan de host en domein, tafoegings fan it sertifikaat.
  • server feiten - fariabelen yn ferbân mei ynformaasje oer de tsjinner-ferzje, namme, tsjinner IP-adres, omjouwing.
  • agent feiten - fariabelen direkt tafoege troch puppet-agent, en net troch feit - sertifikaatnamme, agentferzje, puppetferzje.
  • master fariabelen - Pappetmaster fariabelen (sic!). It is sawat itselde as yn server feiten, plus konfiguraasjeparameterwearden binne beskikber.
  • kompilator fariabelen - kompilatorfariabelen dy't ferskille yn elke omfang: de namme fan 'e aktuele module en de namme fan' e module wêryn it aktuele objekt tagong is. Se kinne bygelyks brûkt wurde om te kontrolearjen dat jo priveeklassen net direkt fan oare modules wurde brûkt.

Tafoeging 1: hoe kinne jo dit alles útfiere en debuggen?

It artikel hie in protte foarbylden fan puppet koade, mar net fertelle ús hielendal hoe't jo rinne dizze koade. No, ik korrigearje mysels.

In agint is genôch om Puppet te rinnen, mar foar de measte gefallen sille jo ek in tsjinner nedich wêze.

Agent

Op syn minst sûnt ferzje 5, puppet-agent pakketten fan offisjele Puppetlabs repository befetsje alle ôfhinklikens (ruby en de oerienkommende edelstenen), dus d'r binne gjin ynstallaasjeproblemen (ik praat oer Debian-basearre distribúsjes - wy brûke gjin RPM-basearre distribúsjes).

Yn it ienfâldichste gefal, om de puppet-konfiguraasje te brûken, is it genôch om de agint yn serverless modus te starten: op betingst dat de puppet-koade wurdt kopieare nei it knooppunt, starte 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

It is fansels better om de tsjinner yn te stellen en aginten op 'e knopen út te fieren yn daemon-modus - dan sille se ien kear elk heal oere de konfiguraasje tapasse dy't is downloade fan 'e tsjinner.

Jo kinne it push-model fan wurk imitearje - gean nei it knooppunt wêryn jo ynteressearre binne en begjin sudo puppet agent -t. Kaai -t (--test) befettet eins ferskate opsjes dy't yndividueel kinne wurde ynskeakele. Dizze opsjes omfetsje de folgjende:

  • rinne net yn daemon-modus (standert begjint de agint yn daemon-modus);
  • ôfslute nei it tapassen fan de katalogus (standert sil de agint trochgean mei wurkjen en de konfiguraasje ien kear yn 'e heale oere tapasse);
  • skriuw in detaillearre wurklog;
  • feroarings yn triemmen sjen litte.

De agint hat in bestjoeringsmodus sûnder feroarings - jo kinne it brûke as jo net wis binne dat jo de juste konfiguraasje skreaun hawwe en wolle kontrolearje wat krekt de agint sil feroarje tidens operaasje. Dizze modus wurdt ynskeakele troch de parameter --noop op de kommandorigel: sudo puppet agent -t --noop.

Derneist kinne jo it debuggenlog fan it wurk ynskeakelje - dêryn skriuwt puppet oer alle aksjes dy't it útfiert: oer de boarne dy't it op it stuit ferwurket, oer de parameters fan dizze boarne, oer hokker programma's it lanseart. Fansels is dit in parameter --debug.

Tsjinner

Ik sil net beskôgje de folsleine opset fan de pappetserver en ynsette koade oan it yn dit artikel Ik sil allinne sizze dat út it fak is der in folslein funksjonele ferzje fan de tsjinner dy't net nedich ekstra konfiguraasje te wurkjen mei in lyts oantal; knopen (sizze, oant hûndert). In grutter oantal knopen sil tuning fereaskje - standert lanseart puppetserver net mear as fjouwer arbeiders, foar gruttere prestaasjes moatte jo har oantal ferheegje en ferjit net om de ûnthâldgrinzen te ferheegjen, oars sil de tsjinner it measte fan 'e tiid garbage sammelje.

Koade-ynset - as jo it fluch en maklik nedich binne, sjoch dan (nei r10k)[https://github.com/puppetlabs/r10k], foar lytse ynstallaasjes soe it genôch wêze moatte.

Addendum 2: Kodearring Rjochtlinen

  1. Plak alle logika yn klassen en definysjes.
  2. Hâld klassen en definysjes yn modules, net yn manifesten dy't knopen beskriuwe.
  3. Brûk de feiten.
  4. Meitsje gjin ifs basearre op hostnammen.
  5. Fiel jo frij om parameters ta te foegjen foar klassen en definysjes - dit is better dan ymplisite logika ferburgen yn it lichem fan 'e klasse / definiearje.

Ik sil útlizze wêrom ik riede dit te dwaan yn it folgjende artikel.

konklúzje

Lit ús einigje mei de ynlieding. Yn it folgjende artikel sil ik jo fertelle oer Hiera, ENC en PuppetDB.

Allinnich registrearre brûkers kinne meidwaan oan 'e enkête. Ynlogge, asjebleaft.

Yn feite is d'r folle mear materiaal - ik kin artikels skriuwe oer de folgjende ûnderwerpen, stimme op wêr't jo ynteressearre binne yn te lêzen:

  • 59,1%Avansearre puppet-konstruksjes - wat stront op folgjende nivo: loops, mapping en oare lambda-útdrukkingen, boarne-samlers, eksportearre boarnen en inter-host-kommunikaasje fia Puppet, tags, providers, abstrakte gegevenstypen.13
  • 31,8%"Ik bin de admin fan myn mem" of hoe't wy yn Avito freonen makken mei ferskate poppetservers fan ferskate ferzjes, en, yn prinsipe, it diel oer it administrearjen fan de poppetserver.7
  • 81,8%Hoe't wy skriuwe puppet koade: ynstrumintaasje, dokumintaasje, testing, CI / CD.18

22 brûkers stimden. 9 brûkers ûntholden har.

Boarne: www.habr.com