Hyrje në Puppet

Puppet është një sistem menaxhimi të konfiguracionit. Ai përdoret për të çuar hostet në gjendjen e duhur dhe për të mbajtur këtë gjendje.

Unë kam punuar me Puppet për më shumë se pesë vjet. Ky tekst është në thelb një përkthim dhe riorganizim i momentëve kryesorë nga dokumentacioni zyrtar, i cili do t'u lejojë fillestarëve të kuptojnë shpejt thelbin e Puppet.

Hyrje në Puppet

Informacion themelor

Skema e punës së Puppet është klient-server, megjithatë mbështetet një variant pune pa server me funksionalitet të kufizuar.

Përdoret modeli pull: si parazgjedhje, klientët kontaktojnë serverin për konfigurim çdo gjysmë ore dhe e aplikojnë atë. Nëse keni punuar me Ansible, atje përdoret një model tjetër, push: administratorët inicojnë procesin e aplikimit të konfigurimit, klientët në vetvete nuk do të aplikojnë asgjë.

Në ndërveprimin në rrjet përdoret enkriptimi TLS dyanshëm: serveri dhe klienti kanë çelësa të tyre privatë dhe certifikata përkatëse. Zakonisht serveri lëshon certifikata për klientët, por në parim është e mundur edhe përdorimi i një CA të jashtëm.

Njoftimi me manifestet

Në terminologjinë e Puppet në serverin puppet lidhen noda (nodet). Konfigurimi për nodet shkruhet në manifestet në një gjuhë të veçantë programimi - Puppet DSL.

Puppet DSL është një gjuhë deklarative. Ajo përshkruan gjendjen e dëshiruar të nodës në formën e shpalljeve të burimeve të veçanta, për shembull:

  • Skedari ekziston dhe ka një përmbajtje të caktuar.
  • Paketa është instaluar.
  • Shërbimi është i aktivizuar.

Burimet mund të jenë të lidhura me njëra-tjetrën:

  • Ka varësi, ato ndikojnë në rregullin e aplikimit të burimeve.
    Për shembull, "së pari instaloni paketën, më pas redaktoni skedarin e konfigurimit, pastaj aktivizoni shërbimin".
  • Ka njoftime - nëse burimi ndryshon, ai dërgon njoftime burimeve që janë regjistruar për të.
    Për shembull, nëse ndryshohet skedari i konfigurimit, mund të rinisni automatikisht shërbimin.

Përveç kësaj, në Puppet DSL ka funksione dhe variabla, si dhe operatorë kushtorë dhe selektues. Po ashtu, mbështeten mekanizma të ndryshëm të modelimit - EPP dhe ERB.

Puppet është shkruar në Ruby, prandaj shumë struktura dhe terma janë marrë nga aty. Ruby lejon që Puppet të zgjerohet - të shkruhen logjika të komplikuara, lloje të reja burimesh, funksione.

Gjatë punës së Puppet, manifestet për çdo nodë konkrete në server kompilohet në katalog. Katalogu — është një listë burimesh dhe lidhjeve të tyre pas llogaritjes së vlerave të funksioneve, variablave dhe zbulimit të operatorëve të kushtit.

Sintaksa dhe stili i kodit

Këtu janë seksionet e dokumentacionit zyrtar që do të ndihmojnë të kuptoni sintaksën, nëse shembujt e dhënë janë të pamjaftueshëm:

Ja një shembull se si duket një manifest:

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

Hapësirat dhe ndarjet e rreshtave nuk janë pjesë e domosdoshme e manifestit, por ka një udhëzues stili. Përmbledhje:

  • Dy hapësira nuk përdoren, tabulat nuk janë të lejuara.
  • Kllapët e lakuara ndahen me hapësirë, ndalimi nuk ndahet me hapësirë.
  • Vijat ndihmuese pas çdo parametri, përfshirë të fundit. Çdo parametr është në një rresht të veçantë. Pëlqehet një përjashtim për rastin pa parametra dhe një parametr: mund të shkruhen në një rresht dhe pa vijë ndihmuese (dmth. resource { 'title': } dhe resource { 'title': param => value }).
  • Vijat ndihmuese të parametrave duhet të jenë në të njëjtin nivel.
  • Vijat ndihmuese të lidhjeve të burimeve shkruhen përpara tyre.

Vendndodhja e skedarëve në serverin Puppet

Për shpjegime të mëtejshme, unë do të introducoj konceptin "direktoria kryesore". Direktoria kryesore është direktoria ku ndodhet konfigurimi i Puppet për një nodë të caktuar.

Direktoria kryesore ndryshon në varësi të versionit të Puppet dhe përdorimit të ambientit. Ambientet janë grupe të pavarura konfigurimi, të cilat ruhen në direktori të ndara. Në përgjithësi përdoren në kombinim me git, në këtë rast ambientet krijohen nga degët e git. Si rezultat, çdo nodë ndodhet në një ambient të caktuar. Kjo është e konfigurueshme në vetë nodën ose në ENC, për të cilin do të flas në artikullin e ardhshëm.

  • Në versionin e tretë ("Puppet-i i vjetër"), direktoria bazë ishte /etc/puppet. Përdorimi i ambienteve është opsional — ne, për shembull, nuk i përdorim me Puppet-in e vjetër. Nëse ambiente përdoren, ato zakonisht ruhen në /etc/puppet/environments, direktoria kryesore do të jetë direktoria e ambientit. Nëse ambientet nuk përdoren, direktoria kryesore do të jetë baza.
  • Deri në versionin e katërt ("Puppet-i i ri"), përdorimi i ambienteve u bë i detyrueshëm dhe direktoria bazë u transferua në /etc/puppetlabs/code. Mjediset ruhen në /etc/puppetlabs/code/environments, direktoria mëmë është direktoria e mjedisit.

Në direktorinë mëmë duhet të ketë një nën-drejtorinë manifests, ku gjenden një ose disa manifetesh me përshkrimin e nodeve. Përveç kësaj, duhet të ketë një nën-drejtorinë modules, ku ndodhen modulet. Çfarë janë modulet, do t’ju tregoj pak më vonë. Për më tepër, në Papet e vjetra gjithashtu mund të ketë një nën-drejtorinë files, ku gjenden skedarë të ndryshëm që ne kopjojmë në node. Në Papet e reja, të gjithë skedarët janë vendosur në modulet.

Skedarët e manifesteve kanë zgjerimin .pp.

Një grup shembujsh praktikë

Përshkrimi i nodit dhe burimeve të tij

Në nod server1.testdomain duhet të krijohet një skedar /etc/issue me përmbajtje Debian GNU/Linux n l. Skedari duhet t’i përkasë përdoruesit dhe grupit root, të drejtat e qasjes duhet të jenë 644.

Shkruajmë manifestin:

node 'server1.testdomain' {   # blloku i konfigurimit, i lidhur me nodin server1.testdomain
    file { ' /etc/issue':   # përshkruajmë skedarin /etc/issue
        ensure  => present,   # ky skedar duhet të ekzistojë
        content => 'Debian GNU/Linux n l',   # ai duhet të ketë këtë përmbajtje
        owner   => root,   # përdoruesi pronar
        group   => root,   # grupi pronar
        mode    => '0644',   # të drejtat mbi skedar. Ato janë caktuar në formën e një stringu (në thonjëza), sepse përndryshe numri me 0 në fillim do të interpretohet si i shkruar në sistemin oktal, dhe gjithçka do të shkojë ndryshe nga si është menduar
    }
}

Ndërveprimet e burimeve në nod

Në nod server2.testdomain duhet të jetë aktivizuar nginx, duke punuar me një konfigurim të përgatitur më parë.

Dekompozojmë detyrën:

  • Duhet të jetë instaluar paketa nginx.
  • Duhet të kopjohen skedarët e konfigurimit nga serveri.
  • Duhet të jetë aktivizuar shërbimi nginx.
  • Në rast të azhurnimit të konfigurimit duhet të rindezët shërbimi.

Shkruajmë manifestin:

node 'server2.testdomain' {   # blloku i konfigurimit që i përket nodës server2.testdomain
    package { 'nginx':   # përshkruajmë paketën nginx
        ensure => installed,   # ai duhet të jetë instaluar
    }
  # Shigjeta e drejtpërdrejtë (-&) tregon se burimi më poshtë duhet
  # të krijohet pas burimit të përshkruar më lart.
  # Këto varësi janë transitive.
    -> file { '/etc/nginx':   # përshkruajmë skedarin /etc/nginx
        ensure  => directory,   # kjo duhet të jetë një drejtor
        source  => 'puppet://modules/example/nginx-conf',   # përmbajtja e saj duhet të merret nga serveri puppet në adresën e caktuar
        recurse => true,   # kopjoni skedarët rekurzivisht
        purge   => true,   # duhet të hiqni skedarët e panevojshëm (ato që nuk janë në burim)
        force   => true,   # hiqni drejtoritë e panevojshme
    }
  # Shigjeta valëzuese (~>) tregon se burimi më poshtë duhet
  # të nënshkruajë ndryshimet e burimit të përshkruar më lart.
  # Shigjeta valëzuese përfshin shigjetën e drejtpërdrejtë (->).
    ~> service { 'nginx':   # përshkruajmë shërbimin nginx
        ensure => running,   # ai duhet të jetë në funksionim
        enable => true,   # duhet të aktivizohet automatikisht gjatë nisjes së sistemit
    }
  # Kur burimi i tipit shërbim merr një njoftim,
  # shërbimi përkatës riniset.
}

Në mënyrë që kjo të funksionojë, është e nevojshme një strukturë e tillë skedari në serverin puppet:

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

Llojet e burimeve

Lista e plotë e llojeve të mbështetur të burimeve ndodhet në dokumentacionin, këtu do të përshkruaj pesë lloje bazë, të cilat në praktikën time mjaftojnë për të zgjidhur shumicën e detyrave.

thotë

Menaxhon skedarët, direktorët, lidhjet simetrike, përmbajtjen e tyre dhe të drejtat e aksesit.

Parametrat:

  • emri i burimit — rruga drejt skedarit (opcional)
  • path — rruga drejt skedarit (nëse nuk është caktuar në emër)
  • ensure — lloji i skedarit:
    • mungon — heq skedarin
    • present — duhet të jetë një skedar i çdo lloji (nëse skedari nuk ekziston, do të krijohet një skedar i zakonshëm)
    • thotë — skedar i zakonshëm
    • directory — direktor
    • link — lidhje simetrike
  • me mbështetje — përmbajtja e skedarit (përshtatet vetëm për skedarët e zakonshëm, nuk mund të përdoret bashkë me source ose target)
  • source — lidhje në rrugën nga e cila duhet të kopjohet përmbajtja e skedarit (nuk mund të përdoret bashkë me me mbështetje ose target). Mund të caktoshet si në formën e URI me skemën puppet: (atëherë do të përdoren skedarët nga serveri puppet), ashtu si me skemën http: (shpresoj se është e qartë se çfarë do të ndodhë në këtë rast), dhe madje edhe me skemën file: ose në formën e një rrugë të plotë pa skemë (atëherë do të përdoret skedari nga sistemi lokal në nodë)
  • target — ku duhet të tregojë lidhja simetrike (nuk mund të përdoret bashkë me me mbështetje ose source)
  • owner — përdoruesi që duhet të jetë pronari i skedarit
  • grup — grupi që duhet të jetë pronari i skedarit
  • mode — permiset për skedarin (në formë vargu)
  • rikthe — përfshin përpunimin rekursiv të direktorive
  • spastrimi — përfshin fshirjen e skedarëve që nuk janë përshkruar në Puppet
  • forco — përfshin fshirjen e direktorive që nuk janë përshkruar në Puppet

paketë

Instalon dhe heq paketat. Mund të përpunojë njoftime — rinstalon paketën nëse është caktuar parametri rinstalo_kur_rifreskohet.

Parametrat:

  • emri i burimit — emri i paketës (opsional)
  • emri — emri i paketës (nëse nuk është caktuar në emër)
  • ofruesi — menaxheri i paketave që duhet të përdoret
  • ensure — gjendja e dëshiruar e paketës:
    • present, instaluar — çdo version është instaluar
    • latest — versioni më i fundit është instaluar
    • mungon — është hequr (apt-get heq)
    • spastruar — është hequr së bashku me skedarët e konfigurimit (apt-get spastruar)
    • mbajtur — versi i paketës është bllokuar (apt-mark mbaj)
    • në çdo rresht tjetër — është instaluar versioni i caktuar
  • rinstalo_kur_rifreskohet — nëse true, atëherë kur merr njoftimin paketa do të rinstalohet. E dobishme për shpërndarjet bazuar në burim, ku ri-ndërtimi i paketimeve mund të jetë i nevojshëm kur ndryshojnë parametrat e ndërtimit. Në mënyrë të paracaktuar false.

shërbim

Menaxhon shërbimet. Mund të përpunojë njoftime — ri-starton shërbimin.

Parametrat:

  • emri i burimit — shërbimi që duhet të menaxhohet (opsional)
  • emri — shërbimi që duhet të menaxhohet (nëse nuk është caktuar në emër)
  • ensure — gjendja e dëshiruar e shërbimit:
    • vrapimi — është duke u nisur
    • ndaluar — është ndaluar
  • aktivizo — menaxhon mundësinë e nisjes së shërbimit:
    • true — është aktivizuar auto-nisja (systemctl aktivizo)
    • mask — është maskuar (systemctl masko)
    • false — auto-nisja është ndaluar (systemctl ndalo)
  • ri-starto — komanda për ri-startimin e shërbimit
  • status — komanda për kontrollimin e statusit të shërbimit
  • ka ri-start — të tregosh nëse skenari i shërbimit përkrah ri-startimin. Nëse false dhe parametri është i caktuar ri-starto — përdoret vlera e këtij parametri. Nëse false dhe parametri ri-starto nuk është caktuar — shërbimi ndalohet dhe fillohet për ri-startim (por në systemd përdoret komanda systemctl ri-starto).
  • ka status — të tregosh nëse skenari i shërbimit përkrah komandën status. Nëse false, atëherë përdoret vlera e parametrave status. Në mënyrë të paracaktuar true.

exec

Ekzekuton komanda të jashtme. Nëse nuk caktosh parametrat krijon, vetëm nëse, përndryshe ose vetëm në rifreskim, komanda do të ekzekutohet në çdo kalim të Puppet. Mund të përpunojë njoftime — ekzekuton komandën.

Parametrat:

  • emri i burimit — komanda që duhet të ekzekutohet (opsional)
  • command — komanda që duhet të ekzekutohet (nëse nuk është caktuar në emër)
  • path — mënyrat për të kërkuar skedarin e ekzekutimit
  • vetëm nëse — nëse komanda e specifikuar në këtë parametër përfundoi me një kod kthimi zero, komanda kryesore do të ekzekutohet
  • përndryshe — nëse komanda e specifikuar në këtë parametër përfundoi me një kod kthimi ndryshe nga zero, komanda kryesore do të ekzekutohet
  • krijon — nëse skedari i specifikuar në këtë parametër nuk ekziston, komanda kryesore do të ekzekutohet
  • vetëm në rifreskim — nëse true, atëherë komanda do të ejecutohet vetëm nëse ky exec merr një njoftim nga burime të tjera
  • cwd — direktoria nga e cila do të ekzekutohet komanda
  • user — përdoruesi nga i cili do të ekzekutohet komanda
  • ofruesi — me ndihmën e cilës do të ekzekutohet komanda:
    • posix — thjesht krijohet një proces nën përgjegjësi, duhet të indikohet path
    • shell — komanda ekzekutohet në shell /bin/sh, nuk është e nevojshme të tregoni path, mund të përdoren globbing, tubat dhe karakteristika të tjera të shell-it. Zakonisht përcaktohet automatikisht, nëse ka ndonjë karakteristikë speciale (|, ;, &&, || etj).

cron

Menaxhon punët e krond

Parametrat:

  • emri i burimit — thjesht një identifikues
  • ensure — gjendja e punës së krond:
    • present — krijohet, nëse nuk ekziston
    • mungon — fshihet, nëse ekziston
  • command — cila komandë do të ekzekutohet
  • mjedis — në cilin ambient do të ekzekutohet komanda (lista e variablave të ambientit dhe vlerave të tyre përmes =)
  • user — nga cili përdorues do të ekzekutohet komanda
  • minute, orë, ditë e javës, muaj, dita e muajit — kur do të ekzekutohet kroni. Nëse ndonjë nga këto atribute nuk është e specifikuar, vlera e saj në crontab do të jetë *.

Në Puppet 6.0 cron siç është eleminuar nga kuti në puppetserver, kështu që nuk ka dokumentacion në faqen e përgjithshme. Por ai eshte ne kuti në puppet-agent, kështu që nuk është e nevojshme ta instaloni veçmas. Dokumentacionin për të mund ta shihni në dokumentacionin e versionit të pestë të Puppet, ose në GitHub.

Për burimet në përgjithësi

Kërkesat për unikësinë e burimeve

Gabimi më i zakonshëm me të cilin përballemi — Deklarata të dyfishta. Ky gabim ndodh kur në katalog hynë dy ose më shumë burime të llojeve të njëjta me të njëjtin emër.

Prandaj, do ta them edhe një herë: në manifestet për një nodë nuk duhet të ketë burime të llojeve të njëjta me të njëjtin emër (titulli)!

Ndonjëherë ka nevojë për të instaluar paka me të njëjtin emër, por me menaxherë të ndryshëm paketash. Në këtë rast, duhet të përdorni parametrin emri, për të shmangur gabimin:

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

Në lloje të tjera burimesh ka parametra të ngjashëm që ndihmojnë për të evituar kopjimin, — emri i shërbim, command i exec, dhe të tjera.

Metaparametrat

Disa parametra të veçantë kanë të gjithë llojet e burimeve, pavarësisht nga natyra e tyre.

Lista e plotë e metaparametrave në dokumentacionin Puppet.

Lista e shkurtër:

  • kërkesa — në këtë parametrin e përcaktohet nga cilat burime varet ky burim.
  • para — në këtë parametrin e përcaktohet se cilat burime varen nga ky burim.
  • abone — në këtë parametrin e përcaktohet nga cilat burime merr njoftime ky burim.
  • njofto — në këtë parametrin e përcaktohet se cilat burime marrin njoftime nga ky burim.

Të gjithë metaparametrat e përmendur pranojnë ose një lidhje burimi, ose një array lidhjesh në kllapa katrore.

Lidhjet në burimet

Një lidhje në burim është thjesht një përmendje e burimit. Ato përdoren kryesisht për përcaktimin e varësive. Një lidhje në një burim joekzistues do të shkaktojë një gabim kompilimi.

Sintaksa e lidhjes është si më poshtë: lloji i burimit me shkronjë të madhe (nëse në emrin e llojit ka dy dy pika, atëherë shkronja e madhe shkruhet për çdo pjesë emri midis dy dy pikave), pastaj në kllapat katrore emri i burimit (regjistri i emrit nuk ndryshon!). Nuk duhet të ketë hapësira, kllapat katrore shkruhen menjëherë pas emrit të llojit.

Shembulli:

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

Varësitë dhe njoftimet

Dokumentacioni është këtu.

Siç është thënë më parë, varësitë e thjeshta midis burimeve janë tranzitive. Një këshillë: duhet të jeni të kujdesshëm me vendosjen e varësive — mund të krijoni varësi ciklike, e cila do të shkaktojë një gabim kompilimi.

Në ndryshim nga varësitë, njoftimet nuk janë tranzitive. Rregullat për njoftimet janë si më poshtë:

  • Nëse një burim merr njoftim, ai përditësohet. Veprimet gjatë përditësimit varen nga lloji i burimit — exec ekzekuton një komandë, shërbim ri-nis një shërbim, paketë ri-instaloni një paketë. Nëse për burimin nuk është përcaktuar një veprim gjatë përditësimit, atëherë nuk ndodh asgjë.
  • Gjatë një çikli të Papet, një burim përditësohet jo më shumë se një herë. Kjo është e mundur sepse njoftimet përfshijnë varësi, dhe grafiku i varësive nuk përmban cikle.
  • Nëse Pappeti ndryshon gjendjen e burimit, atëherë burimi dërgon njoftime të gjithë atyre që janë regjistruar për të.
  • Nëse burimi përmirësohet, atëherë ai dërgon njoftime të gjithë atyre që janë regjistruar për të.

Trajtimi i parametrave të pacaktuar

Në përgjithësi, nëse një parameter burimi nuk ka një vlerë parazgjedhjeje dhe ky parameter nuk është i përcaktuar në manifest, atëherë Pappeti nuk do të ndryshojë këtë pronë në burimin përkatës në nod. Për shembull, nëse burimi i tipit thotë nuk ka një parameter të përcaktuar owner, atëherë Pappeti nuk do të ndryshojë pronarin e skedarit përkatës.

Njohja me klasat, variablat dhe definet

Supozoni se kemi disa nods, ku ka një pjesë të njëjtë konfigurimi, por ka edhe dallime — ndryshe do të mund të përshkruanim gjithçka në një bllok të vetëm node {}. Sigurisht, mund të kopjoni thjesht pjesët e njëjta të konfigurimit, por në përgjithësi kjo është një zgjidhje e keqe — konfigurimi rritet, dhe kur të ndryshoni pjesën e përbashkët të konfigurimit do të duhet të rregulloni të njëjtën gjë në shumë vende. Në këtë rast, është e lehtë të gabosh, dhe në përgjithësi parimi DRY (mos e përsërit veten) nuk është krijuar pa arsye.

Për të zgjidhur një problem të tillë, ekziston një strukturë si klasa.

Klasat

Klasa — janë një bllok i emëruar të kodit të Pappetit. Klasat nevojiten për ripërdorimin e kodit.

Së pari, klasën duhet ta përshkruani. Vetëm përshkrimi nuk shton asnjë burim diku. Klasa përshkruhet në manifes.

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

Pas kësaj, klasa mund të përdoret:

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

Shembulli nga detyra e mëparshme — do ta nxjerrim instalimin dhe konfigurimin e nginx në një klasë:

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

node 'server2.testdomain' {
    include nginx_example
}

Variablat

Klasa nga shembulli i mëparshëm nuk është aspak fleksibile, sepse ajo gjithmonë sjell të njëjtin konfigurim për nginx. Le të bëjmë që rruga për konfigurimin të bëhet variabël, atëherë kjo klasë mund të përdoret për të instaluar nginx me çdo konfigurim.

Kjo mund të bëhet me ndihmën e variablave.

Kujdes: variablat në Puppet janë të pandryshueshëm!

Për më tepër, mund të aksesoni një variabël vetëm pas se ajo është shpallur, përndryshe vlera e variablës do të jetë undef.

Shembulli i punës me variablat:

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

Në Puppet ka hapësira emërore, dhe variablat, përkatësisht, kanë fushën e dukshmërisë: një variabël me të njëjtin emër mund të përcaktohet në hapësira të ndryshme emrash. Kur përcaktohet vlera e një variabli, ai kërkohet në hapësirën aktuale emërtuese, pastaj në atë mbuluese, dhe kështu me radhë.

Shembuj të hapësirave emërtuese:

  • globale — këtu bien variablat përtej përshkrimit të klasës ose nodës;
  • hapësira emërtuese e nodës në përshkrimin e nodës;
  • hapësira emërtuese e klasës në përshkrimin e klasës.

Për të shmangur paqartësinë kur i referoheni një variabli, mund të specifikoni hapësirën emërtuese në emrin e variablit:

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

Marrim me mend se rruga për konfigurimin e nginx-it ndodhet në variablën $nginx_conf_source. Kështu klasa do të duket si në vijim:

class nginx_example {
    package { 'nginx':
        ensure => installed,
    }
    -> file { '/etc/nginx':
        ensure => directory,
        source => $nginx_conf_source,   # këtu përdorim variablën në vend të një stringu të qëndrueshëm
        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
}

Megjithatë, shembulli i dhënë është i keq sepse ka një "dije sekrete" në lidhje me atë që diku brenda klasës përdoret një variabël me këtë emër. Më e saktë do të ishte që ta bëni këtë dijeni të zakonshme - klasat mund të kenë parametra.

Parametrat e klasës — janë variabla në hapësirën emërtuese të klasës, ato përcaktohen në titullin e klasës dhe mund të përdoren si variabla të zakonshëm në trupin e klasës. Vlerat e parametrave specifikohen kur përdoret klasa në manifest.

Një parametri mund t'i jepet një vlerë default. Nëse parametri nuk ka një vlerë default dhe vlera nuk përcaktohet gjatë përdorimit, kjo do të shkaktojë një gabim kompilimi.

Le të parametrizojmë klasën nga shembulli i mësipërm dhe të shtojmë dy parametra: të parin, të detyrueshëm - rrugën për konfigurimin, dhe të dytin, të opsional - emrin e paketës me nginx (në Debian, për shembull, ka paketa 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',   # задаём параметры класса точно так же, как параметры для других ресурсов
  }
}

Në Puppet, variablat janë të tipizuara. Ekzistojnë shumë lloje të të dhënave. Llojet e të dhënave përdoren zakonisht për verifikimin e vlerave të parametrave, që kalohen në klasa dhe definicione. Nëse parametri i kaluar nuk i përputhet llojit të caktuar, do të ndodhë një gabim kompilimi.

Tipi shkruhet drejtpërdrejt përpara emrit të parametrave:

klasë shembuj (
  String $param1,
  Integer $param2,
  Array $param3,
  Hash $param4,
  Hash[String, String] $param5,
) {
  ...
}

Klasat: përfshirë emrin e klasës vs class{'emri-i-klasës':}

Çdo klasë është një burim i llojit class. Ashtu si në rastin e llojeve të tjera të burimeve, një nod nuk mund të ketë dy ekzemplarë të së njëjtës klasë.

Nëse përpiqeni të shtoni një klasë në të njëjtin nod dy herë me anë të class { 'emri-i-klasës':} (pa ndryshim, me parametra të ndryshëm ose të njëjtë), do të jetë një gabim kompilimi. Megjithatë, në rastin e përdorimit të klasës në stilin e burimit, mund të caktoni menjëherë të gjithë parametrat e saj në manifest.

Megjithatë, nëse përdorni include, atëherë klasa mund të shtohet sa herë që të dëshironi. Çështja është se include — një funksion idempotent që kontrollon nëse klasa është shtuar në katalog. Nëse klasa nuk është në katalog— e shton atë, dhe nëse tashmë ekziston, nuk bën asgjë. Por në rastin e përdorimit të include nuk mund të caktohen parametrat e klasës gjatë shpalljes së klasës— të gjithë parametrat e detyrueshëm duhet të caktohen në një burim të jashtëm të dhënash— Hiera ose ENC. Për ta diskutuar, do të flasim në artikullin e ardhshëm.

Definimet

Siç u tha në bllokun e mëparshëm, e njëjta klasë nuk mund të jetë e pranishme në një nod më shumë se një herë. Megjithatë, në disa raste, është e nevojshme të jesh në gjendje të aplikosh të njëjtin bllok kodi me parametra të ndryshëm në një nod. Në terma të tjerë, ekziston një nevojë për një lloj të vetin burimi.

Për shembull, për të instaluar një modul PHP, ne në Avito bëjmë si më poshtë:

  1. Instalojmë paketën me këtë modul.
  2. Krijojmë një skedë konfigurimi për këtë modul.
  3. Krijojmë një simlin për konfigurimin për php-fpm.
  4. Krijojmë një simlin për konfigurimin për php cli.

Në këto raste përdoret një konstrukcion i tillë si definimi (defino, tipi i përcaktuar, tipi i burimit të përcaktuar). Defini është si një klasë, por ka dallime: së pari, çdo definim është një tip burimi, jo një burim; së dyti, çdo definim ka një parametër të padukshëm $title, ku futet emri i burimit gjatë shpalljes së tij. Ashtu si me klasat, defini duhet të përshkruhet së pari, pas të cilit mund të përdoret.

Një shembull i thjeshtë me një modul për PHP:

defino php74::module (
  $php_module_name = $title,
  $php_package_name = "php7.4-${title}",
  $version = 'installed',
  $priority = '20',
  $data = "extension=${title}.son",
  $php_module_path = 'etc/php/7.4/mods-available',
) {
  package { $php_package_name:
    ensure          => $version,
    install_options => ['-o', 'DPkg::NoTriggers=true'],  # debian php packages automatically create symlinks and restart the php-fpm service - we don't need that, as we manage both symlinks and the service using 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' }
}

Në definim është më e lehtë të kapësh gabimin e Deklaratës së Dyfishte. Kjo ndodh nëse në definim ka një burim me emër konstant, dhe në një nodë ka dy ose më shumë instanca të këtij definimi.

Të mbrohemi nga kjo është e thjeshtë: të gjitha burimet brenda definimit duhet të kenë një emër që varet nga $title. Si alternativë — shtimi idempotent i burimeve, në rastin më të thjeshtë mjafton të nxjerrim burimet e përbashkëta për të gjitha instancat e definimit në një klasë të veçantë dhe ta përfshijmë këtë klasë në definim — funksioni include është idempotent.

Ka edhe mënyra të tjera për të arritur idempotencën në shtimin e burimeve, në veçanti duke përdorur funksionet defined dhe ensure_resources, por për këtë do të flas në serinë e ardhshme.

Varësitë dhe njoftimet për klasat dhe definimet

Klasat dhe definimet shtojnë rregullat në procesin e varësive dhe njoftimeve:

  • varësia nga klasa/definimi shton varësi nga të gjitha burimet e klasës/definimit;
  • varësia e klasës/definimit shton varësi për të gjitha burimet e klasës/definimit;
  • njoftimi i klasës/definimit njofton të gjitha burimet e klasës/definimit;
  • abonimi për klasën/definimin regjistron për të gjitha burimet e klasës/definimit.

Operatoret kushtore dhe selektorët

Dokumentacioni është këtu.

nëse

Këtu është gjithçka e thjeshtë:

if SHprehja1 {
  ...
} elsif SHprehja2 {
  ...
} else {
  ...
}

përndryshe

unless — është if-i për të kundërt: blloku i kodit do të ekzekutohet nëse shprehja është e pavërtetë.

unless SHprehja {
  ...
}

rast

Këtu gjithashtu nuk ka asgjë të komplikuar. Si vlera mund të përdoren vlera të zakonshme (stringje, numra dhe kështu me radhë), shprehje të rregullta, si dhe lloje të dhënash.

rast VLERËSIMI {
  VLERË1: { ... }
  VLERË2, VLERË3: { ... }
  default: { ... }
}

Seletorët

Seletori është një konstrukcion gjuhësor, i ngjashëm me rast, vetëm se në vend që të ekzekutojë një bllok kodi, ai kthen një vlerë.

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

Modulet

Kur konfigurimi është i vogël, është lehtë ta mbash në një manifest. Por sa më shumë përshkruajmë konfigurimin, aq më shumë klasa dhe node bëhen në manifest, ai rritet dhe bëhet e pakëndshme për t'u punuar.

Për më tepër, ka një problem të ri- përdorimit të kodit - kur të gjithë kodi është në një manifest, është e vështirë ta ndash këtë kod me të tjerët. Për t'u zgjidhur këto dy probleme, në Puppet ekziston një entitet i tillë, si modul.

Modulet modulet janë grupe klasash, definicionesh dhe entitetesh të tjera të Puppet, të nxjerra në një direktori të veçantë. Me fjalë të tjera, moduli është një copë të pavarur të logjikës së Puppet. Për shembull, mund të ketë një modul për të punuar me nginx, dhe në të do të ketë vetëm atë që nevojitet për të punuar me nginx, dhe mund të ketë një modul për të punuar me PHP, dhe kështu me radhë.

Modulet janë të versionuara, gjithashtu mbështesin varësitë e moduleve nga njëra-tjetra. Ka një depo të hapur moduli - Puppet Forge.

Në serverin e puppetit, modulet ndodhen në nën-direktorin modules të drejtorisë rrënjësore. Brenda çdo moduli, skema standarde e direktorive është - manifests, files, templates, lib dhe kështu me radhë.

Struktura e skedarëve në modul

Në rrënjën e modulit mund të jenë drejtoritë e mëposhtme me emra që flasin:

  • manifests - aty ndodhen manifestet
  • files - aty ndodhen skedarët
  • templates - aty ndodhen shabllonat
  • lib - aty ndodhet kodi Ruby

Ky nuk është një listë e plotë e direktorive dhe skedarëve, por për këtë artikull është mjaft.

Emrat e burimeve dhe emrat e skedarëve në modul

Dokumentacioni është këtu.

Burimet (klasat, definicionet) në modul nuk mund të quhen ashtu si të duash. Për më tepër, ka një përputhje të drejtpërdrejtë midis emrit të burimit dhe emrit të skedarit, në të cilin Puppet do të kërkojë për përshkrimin e këtij burimi. Nëse shkelni rregullat e emërimit, atëherë Puppet thjesht nuk do ta gjejë përshkrimin e burimeve dhe do të ketë një gabim në kompilim.

Rregullat janë të thjeshta:

  • Të gjitha burimet në modul duhet të jenë në emërësin e modulit. Nëse moduli quhet foo, atëherë të gjitha burimet në të duhet të quhen foo::, ose thjesht foo.
  • Burimi me emrin e modulit duhet të jetë në skedarin init.pp.
  • Për burimet e tjera, skema e emërimit të skedarëve është si më poshtë:
    • prefiksi me emrin e modulit hidhet
    • të gjitha dy pika, nëse ka, zëvendësohen me slashes
    • shtohet prapashtesa .pp

Do ta demonstroj me një shembull. Supozoni se po shkruaj një modull nginx. Ai ka burimet e mëposhtme:

  • klasa nginx përshkruar në manifest init.pp;
  • klasa nginx::service përshkruar në manifest service.pp;
  • definimi nginx::server përshkruar në manifest server.pp;
  • definimi nginx::server::location përshkruar në manifest server/location.pp.

Shabllonat

Sigurisht se edhe ju e dini se çfarë janë шаблoni, nuk do ta shpjegoj këtu në detaje. Por për çdo rast do të lë një lidhje në Wikipedia.

Si të përdorim шаблоните: vlera e шаблoni mund të zbulohet me anë të funksionit template, i cili merr një rrugë për në шаблон. Për burime si thotë përdorim së bashku me parametrin me mbështetje. Për shembull, kështu:

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

Rruga e formatit / nënkupton një skedar /modules//templates/.

Përveç kësaj, ka një funksion inline_template — i cili merr tekstin e шаблонit, jo emrin e skedarit.

Brenda шаблонit mund të përdoren të gjitha variablat e Puppet në fushën aktuale të dukshme.

Puppet mbështet шаблонet në formatin EPP dhe ERB:

Përmbledhje për ERB

Strukturat kontrolluese:

  • <%= ВЫРАЖЕНИЕ %> — fut vlerën e shprehjes
  • <% ВЫРАЖЕНИЕ %> — llogarit vlerën e shprehjes (pa e futur atë). Këtu përfshihen zakonisht operatorët kushtorë (if), ciklet (each).
  • <%# КОММЕНТАРИЙ %>

Shprehjet në ERB shkruhen në Ruby (në fakt, ERB është Embedded Ruby).

Për të aksesuar variablat nga manifesti duhet të shtohet @ në emrin e variablit. Për të hequr vijën e zbrazët që shfaqet pas strukturës kontrolluese, duhet të përdoret etiketa përmbyllëse -%>.

Shembulli i përdorimit të шаблонit

Supozoni se po shkruaj një modull për menaxhimin e ZooKeeper. Klasa që është përgjegjëse për krijimin e konfigurimit duket më pak kështu:

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

Dhe шаблонit përkatës zoo.cfg.erb duhet të jetë kështu:

0 -%>

server.=:::



dataDir=


=

Faktet dhe variablat e integruar

Shumë shpesh, një pjesë e caktuar e konfiguracionit varet nga ajo se çfarë ndodh në nodë në atë moment. Për shembull, në varësi të versionit të Debian-it që është instaluar, duhet të instalohet një version i caktuar i paketës. Mund të ndiqni të gjithë këtë manualisht, duke rishkruar manifestet në rast se ndodhin ndryshime në nodë. Por ky është një qasje e paarsyeshme, automatizimi është shumë më e mirë.

Për të marrë informacion në lidhje me nodat në Puppet, ekziston një mekanizëm i tillë si faktet. Faktet janë informacione rreth nodës, të disponueshme në manifest si variabla të zakonshme në hapësirën globale të emrave. Për shembull, emri i hostit, versioni i sistemit operativ, arkitektura e procesorit, lista e përdoruesve, lista e ndërfaqeve rrjetore dhe adresat e tyre, dhe shumë, shumë më tepër. Faktet janë të disponueshme në manifest dhe shabllone si variabla të zakonshme.

Shembull i punës me faktet:

notify { "Po ekzekutohet OS ${facts['os']['name']} version ${facts['os']['release']['full']}": }
# burimi i tipit notify thjesht printon një mesazh në log

Nëse flasim formalisht, çdo fakt ka një emër (string) dhe një vlerë (disponohen lloje të ndryshme: strings, array, dictionaries). Ekziston një grup faktesh të ndërtuar brenda. Gjithashtu, mund të shkruani të tuat të veçanta. Grumbujt e faktëve përshkruhen si funksione në Ruby, ose si skedarë ekzekutues.Gjithashtu, faktet mund të paraqiten në formën e skedarëve tekstorë me të dhëna në nodë.

Gjatë punës, agjenti i Puppet fillimisht kopjon nga serveri i Puppet të gjithë grumbujt e disponueshëm të faktëve në nodë, pastaj i ekzekuton ata dhe dërgon në server faktet e grumbulluara; vetëm pas kësaj serveri fillon kompilimin e katalogut.

Faktet në formën e skedarëve ekzekutues

Këto fakte vendosen në modulet në direktorinë facts.d. Sigurisht, skedarët duhet të jenë të ekzekutueshëm. Kur ekzekutohen, ata duhet të printojnë në stdout informacion ose në formatin YAML, ose në formatin 'çelës=vlerë'.

Mos harroni se faktet shtrihen mbi të gjitha nodet që janë nën menaxhimin e serverit Puppet, në të cilin po e lanconi modulin tuaj. Prandaj, në skenar duhet të siguroheni që në sistem të jenë të gjitha programet e nevojshme për funksionimin e faktit tuaj dhe skedarët.

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

Faktet në Ruby

Këto fakte vendosen në modulet në direktorinë 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

Faktet tekstuale

Këto fakte vendosen në nodet në direktorinë /etc/facter/facts.d në Puppet-in e vjetër ose /etc/puppetlabs/facts.d në Puppet-in e ri.

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

Qasja në fakte

Mund të kontaktoni faktet në dy mënyra:

  • nëpërmjet fjalorit $facts: $facts['fqdn'];
  • duke përdorur emrin e faktit si emër variabli: $fqdn.

Më mirë është të përdoret fjalori $facts, dhe madje më mirë të specifikohet hapësira globale e emrave ($::facts).

Këtu është seksioni i duhur i dokumentacionit.

Variablat e ndërtuar

Përveç faktëve, ka edhe disa variabla, të disponueshëm në hapësirën globale të emrave.

  • fakte të besuara — variablat që merren nga certifikata e klientit (pasi certifikata zakonisht lëshohet në serverin puppet, agjenti nuk mund ta ndryshojë thjesht certifikatën e tij, kështu që variablat janë "të besuara": emri i certifikatës, emri i hostit dhe domenit, zgjerimet nga certifikata.
  • fakte serveri — variablat që lidhen me informacionin për serverin — versioni, emri, adresa IP e serverit, mjedisi.
  • fakte agjenti — variablat e shtuar direkt nga puppet-agent’i, e jo nga facter’i — emri i certifikatës, versioni i agjentit, versioni i puppetit.
  • variablat master — variablat e puppet master (sic!). Ato përmbajnë më shumë ose më pak të njëjtat informacione, fakte serveri, plus janë të disponueshme vlerat e parametrave të konfigurimit.
  • variablat e kompilatorit — variablat e kompilatorit që ndryshojnë në çdo hapësirë të dukshmërisë: emri i modulit aktual dhe emri i modulit ku u thirr objekti aktual. Ato mund të përdoren, për shembull, për të kontrolluar që klasat tuaja private nuk përdoren drejtpërdrejt nga modula të tjera.

Shtesa 1: si ta ekzekutoni dhe debugoni gjithçka këtë?

Në artikull u paraqitën shumë shembuj të kodit puppet, por nuk u tregua si ta ekzekutoni këtë kod. Mirë, po e rregullojmë këtë.

Për të punuar me Puppet, mjafton agjenti, por për shumicën e rasteve do të nevojitet edhe serveri.

Agjenti

Të paktën që nga versioni i pestë, paketat puppet-agent nga repository zyrtar të Puppetlabs kanë të gjitha varësitë (ruby dhe gem-at e përshtatshëm), kështu që nuk ka asnjë vështirësi në instalim (po flas për distributivët e bazuar në Debian — ne nuk përdorim distribuenca të bazuara në RPM).

Në rastin më të thjeshtë, për të aplikuar konfigurimin puppet, mjafton të nisni agjentin në modin pa server: me kushte që kodi puppet të jetë kopjuar në nod, nisni 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

Më mirë, natyrisht, është të ngrini serverin dhe të запуска agents në nodes në mënyrë demonësh – atëherë çdo gjysmë ore ata do të aplikojnë konviksionin e shkarkuar nga serveri.

Mund të imitosh modelin push të punës – hy në node që të intereson dhe aktivizo sudo puppet agent -t. Çelësi -t (--test) në të vërtetë përfshin disa mundësi, të cilat mund të aktivizohen dhe ndaras. Nga këto mundësi janë:

  • të mos punojë në mënyrë demonësh (në parazgjedhje agjenti aktivizohet në mënyrë demonësh);
  • të përfundojë punën pas aplikimit të katalogut (në parazgjedhje agjenti do të vazhdojë punën dhe do të aplikojë konviksionin çdo gjysmë ore);
  • të shkruaj log të detajuar të punës;
  • të tregojë ndryshimet në skedarë.

Agjenti ka një mënyrë pune pa ndryshime – mund të përdoret kur nuk je i sigurt se ke shkruar konviksionin e saktë dhe dëshiron të verifikosh se çfarë do të ndryshojë agjenti gjatë punës. Kjo mënyrë aktivizohet me parametrin --noop në komandën e linjës: sudo puppet agent -t --noop.

Për më tepër, mund të aktivizosh logun debug të punës – në të puppet shkruan për të gjitha veprimet që ai kryen: për burimin që është duke u përpunuar momentalisht, për parametrat e këtij burimi, për programet që aktivizon. Sigurisht, ky është parametri --debug.

Server

Konfigurimi i plotë i papets serverit dhe deploy-i i kodit në të, nuk do ta shqyrtoj në këtë artikull, do të them vetëm se nga kutia ngrihet një version funksional i serverit, që nuk kërkon konfigurim të mëtejshëm për të punuar në kushte të numrit të vogël të nodes (tha, deri në njëqind). Një numër më i madh node do të kërkojë tuning – në parazgjedhje puppetserver aktivizohet me jo më shumë se katër punëtorë; për një performancë më të lartë është e nevojshme të rritet numri i tyre dhe të mos harrohet të rriten limitet e memories, përndryshe shumicën e kohës serveri do të bëjë garbage collect.

Deploy-i i kodit – nëse duhet shpejt dhe thjeshtë, shihni (në r10k)[https://github.com/puppetlabs/r10k], për instalime të vogla kjo duhet të jetë e mjaftueshme.

Shtesë 2: rekomandime për shkrimin e kodit

  1. Shkëputni të gjithë logjikën në klasa dhe defina.
  2. Mbani klaset dhe definet në modulet, jo në manifestet që përshkruajnë nodet.
  3. Përdorni të dhënat.
  4. Mos bëni if për emrat e hosteve.
  5. Mos hezitoni të shtoni parametra për klaset dhe definet - është më mirë sesa logjika e padukshme e fshehur në trupin e klasës/definit.

Pse rekomandoj ta bëni kështu - do ta shpjegoj në artikullin e ardhshëm.

Përfundim

Këtu do ta mbyllim me hyrjen. Në artikullin e ardhshëm do të flas për Hiera, ENC dhe PuppetDB.

Vetëm përdoruesit e regjistruar mund të marrin pjesë në anketë. Hyni, ju lutem.

Në të vërtetë, ka shumë më tepër material - mund të shkruaj artikuj mbi këto tema, votoni për çfarë do kishit dëshiruar të lexoni:

  • 59,1%Konstruksione të avancuara të puppet - disa gjëra në nivelin tjetër: ciklet, mapimi dhe shprehjet e tjera lambda, mbledhësit e burimeve, burimet e eksportuara dhe ndërveprimi ndërmjet hosteve përmes Puppet, etiketat, ofruesit, tipet abstrakte të të dhënave.
  • 31,8%«Unë jam admin nga nëna» ose si ne në Avito bashkuam disa serverë puppet të versioneve të ndryshme, po ashtu dhe një pjesë mbi administrimin e serverit puppet.
  • 81,8%Si shkruajmë kodin puppet: instrumentimi, dokumentimi, testimi, CI/CD.

22 përdorues votuan. 9 përdorues u përmbajtën.

Burimi: habr.com

Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS 🔥 Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS | ProHoster