Bazat e Ansible, pa të cilat playbook-et tuaja janë një grumbull makaronash të ngjitura

Shkruaj shumë rishikime për kodin e të tjerëve në Ansible dhe shkruaj shumë vetë. Gjatë analizës së gabimeve (të huaja dhe të mia), si dhe disa intervistash, kuptova gabimin kryesor që bëjnë përdoruesit e Ansible — ata përplasen në komplikuar, pa e zotëruar thelbin.

Për të korrigjuar këtë padrejtësi universale, vendosa të shkruaj një hyrje në Ansible për ata që tashmë e njohin. Paralajmëroj, kjo nuk është një përmbledhje e manualeve, por një artikull i gjatë me shumë shkronja dhe pa figura.

Niveli i pritur i lexuesit — t'i keni shkruar disa mijëra rreshta YAML, keni bërë diçka në prodhim, por "gjithçka duket paksa e çuditshme".

Emrat

Gabimi kryesor i përdoruesit të Ansible është të mos dijë si quhen gjërat. Nëse nuk e dini emrat, nuk mund të kuptoni atë që është shkruar në dokumentacion. Një shembull i gjallë: në një intervistë, një person, që duket se kishte thënë se kishte shkruar shumë në Ansible, nuk mundi të përgjigjej në pyetjen "nga cilat elemente përbëhet playbook?". Dhe kur unë sugjerova se "pritej që të përgjigjej se playbook përbëhet nga play", pasoi një koment shkatërrues "ne nuk e përdorim këtë". Njerëzit shkruajnë në Ansible për para dhe nuk e përdorin play. Në të vërtetë, e përdorin, por nuk dinë se çfarë është.

Pra, le të fillojmë me të thjeshtën: si quhet. Ndoshta e dini këtë, ndoshta jo, sepse nuk keni vënë re kur keni lexuar dokumentacionin.

ansible-playbook ekzekuton playbook. Playbook është një skedar me për extension yml/yaml, brenda të cilit diçka e tillë:

---
- hosts: group1
  roles:
    - role1

- hosts: group2,group3
  tasks:
    - debug:

Kemi kuptuar tashmë që i gjithë ky skedar është një playbook. Mund të tregojmë ku janë rolet (roles), ku janë detyrat (tasks). Por ku është play? Dhe çfarë e ndan play nga role ose playbook?

Kjo është e gjitha në dokumentacion. Dhe këto shpesh kalohen. Fillestarët — sepse ka shumë dhe nuk mund ta mbash mend gjithçka menjëherë. Të përvojshëm — sepse janë "çështje triviale". Nëse jeni të përvojshëm — rishikoni këto faqe të paktën një herë në gjashtë muaj dhe kodi juaj do të bëhet shumë më i mirë.

Kështu që mba mend: Playbook është një listë, e cila përbëhet nga play dhe import_playbook.
Kjo është një play:

- hosts: group1
  roles:
    - role1

dhe kjo është gjithashtu një play tjetër:

- hosts: group2,group3
  tasks:
    - debug:

Çfarë është play? Pse ekziston ajo?

Play është elementi kyç për playbook, sepse play dhe vetëm play lidh listën e roleve dhe/ose detyrave me listën e hosteve ku ato duhet të kryhen. Në thellësitë e dokumentacionit mund të gjeni përmendje për delegate_to, pluginet lokale të lookup, cilësimet specifike për network-cli, jump-hosts, etj. Ato lejojnë një ndryshim të vogël të vendndodhjes së ekzekutimit të detyrave. Por, harrojeni këtë. Çdo nga këto mundësi të sofistikuara ka aplikime shumë të veçanta, dhe ato me siguri nuk janë universale. Ne po flasim për gjërat bazë që duhet të dinë dhe përdorin të gjithë.

Nëse dëshironi të "bëni diçka" "ndokund" — shkruani play. Jo rol. Jo rol me module dhe delegata. Merrni dhe shkruani play. Në të cilin, në fushën e hosts përmendni ku do të ekzekutoni, ndërsa në roles/tasks — çfarë do të ekzekutoni.

E thjeshtë, apo? Si mund të jetë ndryshe?

Një nga karakteristikat kur njerëzit ndiejnë dëshirën për ta bërë këtë ndryshe nga play, është "rol që konfiguroni gjithçka". Një dëshirë për të pasur një rol që konfiguroni dhe serverit të dy llojet e serverëve.

Një shembull arketipal është monitorimi. Do të ishte e dëshirueshme të kishte një rol monitorimi që do të konfigurojë monitorimin. Roli i monitorimit i jepet hosteve të monitorimit (në përputhje me play). Por, del se për monitorimin na nevojiten pakot në hostet që ne monitorojmë. Pse të mos përdorim delegat? Dhe gjithashtu, duhet të konfigurojmë iptables. Delegat? Dhe gjithashtu, duhet të shkruajmë/përmirësojmë konfigurimin për DBMS, në mënyrë që monitorimi të lejohet. Delegat! Dhe nëse kreativiteti fillon, mund të bëjmë delegimin. include_role në një cikël të brendshëm përmes një filtri të zgjuar për listën e grupeve, dhe brenda include_role mund të bëjmë gjithashtu delegate_to përsëri. Dhe fillon…

Një dëshirë e mirë është të kemi një rol të vetëm monitorimi, i cili "bën gjithçka" — na çon në një kaos të tmerrshëm nga i cili shpesh ka vetëm një dalje: të shkruajmë gjithçka nga fillimi.

Ku ndodhi gabimi? Në momentin kur zbuloni se për të kryer detyrën "x" në hostin X duhet të shkoni në hostin Y dhe të bëni atje "y", duhet të keni bërë një ushtrim të thjeshtë: të shkoni dhe të shkruani një play, e cila në hostin Y bën y. Të mos shtoni diçka në "x", por të shkruani nga fillimi. Edhe nëse është me variabla të ngurta.

Duket se, në paragrafët më sipër është thënë e gjitha saktë. Por ky nuk është rasti juaj! Sepse dëshironi të shkruani kod të ripërdorshëm, i cili është DRY dhe ngjan si një bibliotekë, dhe duhet të kërkoni një metodë se si ta bëni këtë.

Këtu është fshehur një tjetër gabim i rëndë. Një gabim, i cili ka kthyer shumë projekte nga të shkruara përmbajtëse (mund të ishte më mirë, por gjithçka funksionon dhe është e lehtë për t'u shkruar më tepër) në një tmerr të plotë, ku edhe autori nuk mund ta kuptojë. Funksionon, por mbrapsht, ndihmoftë Zot që diçka të ndryshoni.

Ky gabim tingëllon kështu: roli është një funksion biblioteke. Kjo analogji ka shkatërruar aq shumë nisma të mira, saqë është thjesht e trishtueshme ta shohësh. Roli nuk është një funksion biblioteke. Ai nuk mund të bëjë llogaritje dhe nuk mund të marrë vendime në nivelin e play. Më kujto, çfarë vendimesh merr play?

Faleminderit, keni të drejtë. Play merr një vendim (më saktë, përmban informacion) mbi se cilat detyra dhe role duhet të kryhen në cilat host-e.

Nëse ngarkoni këtë zgjidhje si një rol, dhe madje me llogaritje, e dënon veten tuaj (dhe ata që do të përpiqen të kuptojnë kodin tuaj) në një ekzistencë të mjerueshme. Roli nuk vendos se ku do të ekzekutohet. Kjo zgjidhje vendoset nga play. Roli bën atë që i thoni, aty ku i thoni.

Pse është e rrezikshme të programoni në Ansible dhe pse COBOL është më i mirë se Ansible do të diskutojmë në kapitullin për variablat dhe jinja. Deri atëherë, le të themi një gjë — çdo llogaritje që bëni lë pas një gjurmë të pandashme nga ndryshimi i variablave globalë, dhe nuk mund të bëni asgjë në lidhje me këtë. Sapo dy 'gjurmë' të kryqëzohen — gjithçka është humbur.

Vërejtje për ata që janë kritikë: roli, pa dyshim, mund të ndikohet në kontrollin e rrjedhës. Ka delegate_to dhe ka aplikime të arsyeshme. Ka meta: end host/play. Por! Kujtoni, ne po mësojmë bazat? E keni harruar delegate_to. Po flasim për kodin më të thjeshtë dhe më të bukur në Ansible. I cili është e lehtë për t'u lexuar, lehtë për t'u shkruar, lehtë për t'u debuguar, lehtë për t'u testuar dhe lehtë për të shtuar. Pra, edhe një herë:

play dhe vetëm play vendos se në cilat hosts do të ekzekutohet çfarë.

Në këtë seksion ne kemi shqyrtuar përballjen midis play dhe role. Tani do të flasim për marrëdhëniet midis tasks dhe role.

Tasks dhe Roli

Le të shqyrtojmë play:

- hosts: somegroup
  pre_tasks:
    - some_tasks1:
  roles:
     - role1
     - role2
  post_tasks:
     - some_task2:
     - some_task3:

Supozoni se tuaj duhet të bëni foo. Dhe duket kështu foo: name=foobar state=present. Ku duhet ta shkruajmë? në pre? post? Të krijojmë rol?

… Dhe ku shkuan tasket?

Ne fillojmë përsëri me baza — struktura e play. Nëse po notoni në këtë temë, nuk mund të përdorni play si bazë për gjithçka tjetër, dhe rezultati juaj del "i paqëndrueshëm".

Struktura e play: direktiva hosts, konfigurimet e vetë play dhe seksionet pre_tasks, tasks, roles, post_tasks. Parametrat e tjerë për play nuk janë të rëndësishëm për ne tani.

Renditja e seksioneve të tyre me tasket dhe rolet: pre_tasks, roles, detyrat, post_tasks. Për sa i përket rendit semantik të ekzekutimit ndërmjet detyrat dhe roles nuk është e qartë, praktikat më të mira thonë se ne shtojmë seksionin detyrat, vetëm nëse nuk ka roles. Nëse ka roles, atëherë të gjitha tasket përkatëse vendosen në seksionet pre_tasks/post_tasks.

Rrinte vetëm ajo që është semantike e qartë: së pari pre_tasks, pastaj roles, pastaj post_tasks.

Por ne ende nuk kemi përgjigjur pyetjes: ku duhet të shkruhet thirrja e modulit foo ? A duhet të shkruajmë një rol të tërë për çdo modul? Apo është më mirë të kemi një rol të madh për gjithçka? Dhe nëse jo rol, ku duhet të shkruajmë — në pre apo në post?

Nëse nuk ka një përgjigje argumentuese për këto pyetje, kjo është një shenjë e mungesës së intuitës, pra ato "theme të pasigurta". Le të shqyrtojmë. Fillimisht, një pyetje kontrolli: Nëse play ka pre_tasks dhe post_tasks (dhe nuk ka as tasks, as roles), a mund të prishet diçka nëse e transferoj të parën task nga post_tasks në fund pre_tasks?

Natyrisht, formulimi i pyetjes sugjeron se do të prishet. Por çfarë saktësisht?

... Handlerat. Leximi i bazave zbulohet një fakt të rëndësishëm: të gjithë handlerat flush’ohen automatikisht pas çdo seksioni. Pra, përfundohen të gjitha tasks nga pre_tasks, pastaj të gjithë handlerat që ishin notify. Më pas përfundohen të gjitha rolet dhe të gjithë handlerat që ishin notify në rolet. Pastaj post_tasks dhe handlerat e tyre.

Pra, nëse e transferoni një task nga post_taskspre_tasks, potencialisht do ta kryeni atë para se të përfundojë handleri. Për shembull, nëse në pre_tasks instalohet dhe konfiguriohet server web, ndërsa në post_tasks diçka dërgohet në të, atëherë transferimi i kësaj task në seksionin pre_tasks do të çojë në faktin që në momentin e "dërgimit" serveri ende nuk do të jetë aktiv dhe gjithçka do të prishet.

Tani le të mendojmë sërish, përse na duhen pre_tasks dhe post_tasks? Например, для того, чтобы выполнить всё нужное (включая хэндлеры) до выполнения роли. А post_tasks do të na lejojë të punojmë me rezultatet e ekzekutimit të rolëve (përfshirë handlerat).

Një njohës i ngjashëm i Ansible do të na thotë se ka meta: flush_handlers, por çfarë na duhen flush_handlers, nëse mund të mbështetemi në rendin e ekzekutimit të seksioneve në play? Për më tepër, përdorimi i meta: flush_handlers mund të na sjellë surpriza me duplikim të handlers, duke na shkaktuar paralajmërime të çuditshme në rastin e përdorimit. when u bllok etj. Sa më shumë të njihni Ansible, aq më shumë nuanca do të jepni për "zgjidhjen e zgjuar". Një zgjidhje e thjeshtë — përdorimi i ndarjes natyrale midis pre/roles/post — nuk ka kompromise.

Dhe, po kthehemi te ‘foo’ tonë. Ku ta vendosim? Në pre, post ose në roles? Është e qartë se varet nga nëse na duhen rezultatet e punës së handler-it për foo. Nëse jo, atëherë foo nuk duhet të vendoset në asnjë nga ato — këto seksione kanë një kuptim të veçantë — ekzekutimi i task-eve para dhe pas grumbullit kryesor të kodit.

Tani, përgjigjja në pyetjen "rol apo task" reduktohet në atë që tashmë ekziston në play — nëse ka tasks, atëherë duhet ta shkruajmë në tasks. Nëse ka roles — duhet të krijojmë një rol (madje edhe nga një task). Ju kujtoj, tasks dhe roles nuk përdoren njëkohësisht.

Kuptimi i të dhënave themelore të Ansible-i ofron përgjigje të arsyeshme për pyetje që dukeshin si preferenca personale.

Tasks dhe roles (pjesa e dytë)

Tani, le të diskutojmë situatën kur po filloni të shkruani një playbook. Ju nevojitet të bëni foo, bar dhe baz. A janë këto tre detyra, një rol apo tre role? Për të përmbledhur pyetjen: kur duhet të filloni të shkruani rolet? Çfarë kuptimi ka të shkruani rolet, kur mund të shkruani detyrat?… Dhe çfarë është një rol?

Një nga gabimet më të mëdha (kam folur tashmë për këtë) është të mendoni se roli është si një funksion në një bibliotekë të programit. Si duket një përshkrim i përgjithësuar i funksionit? Ai merr argumente si hyrje, ndërvepron me shkakët anësorë, krijon efekte anësore dhe kthen një vlerë.

Tani, vëmendje. Çfarë nga kjo mund të bëhet në rol? Të krijosh efekte anësore — gjithmonë është e mundur, kjo është thelbi i gjithë Ansible — për të bërë efekte anësore. Të kesh shkakët anësorë? Elementare. Por me "të kalosh vlerë dhe ta kthesh atë" — këtu pikërisht nuk ka. Së pari, nuk mund ta kaloni vlerën në rol. Mund të vendosni një variabël globale me një jetëgjatësi sa play në seksionin vars për rolin. Mund të vendosni një variabël globale me jetëgjatësi në play brenda rolit. Ose madje me jetëgjatësi të playbook-ut (set_fact/register). Por nuk mund të keni "variabël lokale". Nuk mund të "pranon vlerën" dhe "ta kthesh atë".

Kështu që, e rëndësishme është: nuk mund të shkruash diçka në ansible pa shkaktuar efekte anësore. Ndryshimi i variablave global është gjithmonë një efekt anësor për funksionin. Në Rust, për shembull, ndryshimi i një variabli global është i pasigurt. Ndërsa në Ansible, mënyra e vetme për të ndikuar në vlerat për një rol. Kushtojini vëmendje fjalëve të përdorura: jo "të kalosh një vlerë në rol", por "të ndryshosh vlerat që përdor roli". Nuk ka izolim mes roleve. Nuk ka izolim mes detyrave dhe roleve.

Në përmbledhje: roli nuk është një funksion.

Çfarë ka të mirë në rol? Së pari, roli ka vlera të paracaktuara (/default/main.yaml), së dyti roli ka katalogë shtesë për ruajtjen e skedareve.

Çfarë është e mirë në vlerat e paracaktuara? Ato janë, në piramidën e Maslow, një tabelë relativisht e çuditshme e prioriteteve të variablave në Ansible, vlerat e paracaktuara të rolit janë më të pakta në prioritet (përveç parametrave të komandës së linjës së ansible). Kjo nënkupton se nëse ju nevojitet të ofroni vlera të paracaktuara dhe të mos shqetësoheni se do të zëvendësojnë vlerat nga inventari ose variablat grupore, atëherë vlerat e paracaktuara të rolit janë vendi i vetëm i duhur për ju. (Po, po, po them një gënjeshtër të vogël – ka edhe |d(your_default_here), por gjithsesi, nëse flasim për vendet stacionare — vetëm defoltet e roleve).

Çfarë tjetër është e mirë në role? Ato kanë kataloge të veta. Këto janë kataloge për variablat, si ata të përhershëm (dmth. të llogaritur për rol), ashtu si edhe për ato dinamike (ka një model të tillë ose anti-model — include_vars në bashkëpunim me {{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml). Këto janë kataloge për files/, templates/. Po ashtu, ato lejojnë të kenë modulet dhe plugins e veta (library/). Por, në krahasim me detyrat në playbook (të cilat gjithashtu mund të kenë gjithçka këtë), përfitimi këtu është vetëm ajo, që skedarët janë të ndarë në disa grupe të veçanta, jo në një grumbull të vetëm.

Një detaj tjetër: mund të përpiqemi të krijojmë role që do të jenë të disponueshme për ripërdorim (përmes galaxy). Pas shfaqjes së koleksioneve, shpërndarja e rolleve mund të konsiderohet pothuajse e harruar.

Pra, rolet kanë dy karakteristika të rëndësishme: ato kanë defoltet (karakteristika unike) dhe ato lejojnë strukturimin e kodit.

Kthehu te pyetja fillestare: kur të bëhen detyrat dhe kur rolet? Detyrat në playbook zakonisht përdoren ose si "llak" para/pas roleve, ose si një element ndërtues i pavarur (në këtë rast, kodi nuk duhet të ketë role). Një grumbull detyrash normale të përziera me rolet është një neglizhencë e dukshme. Duhet të qëndrohet te një stil specifik — ose detyra, ose role. Rolet ofrojnë ndarje entitetesh dhe defekte, detyrat lejojnë leximin më të shpejtë të kodit. Zakonisht në role del kodi më "stacionar" (i rëndësishëm dhe i komplikuar), ndërsa në stilin e detyrave shkruhen skenare ndihmës.

Ka mundësinë të bëni import_role si detyrë, por nëse e shkruani këtë, jini të gatshëm për një shpjegim për ndjesinë tuaj estetike, pse dëshironi ta bëni këtë.

Një lexues i ngulët mund të thotë se rolet mund të importojnë role, rolet mund të kenë varësi përmes galaxy.yml, dhe ka gjithashtu një të frikshme dhe të tmerrshme include_role — kujtoj, ne po rrisim aftësi në Ansible bazik, dhe jo në gimnasitikën rrethore.

Handlerët dhe detyrat

Le të diskutojmë për një tjetër gjë të dukshme: handler-at. Përdorimi i duhur i tyre është një art i vërtetë. Çfarë e ndan një handler nga një task?

Ndërsa po i kujtojmë bazat, ja një shembull:

- hosts: group1
  tasks:
    - foo:
      notify: handler1
  handlers:
     - name: handler1
       bar:

Roli i handler-ve ndodhet në rolename/handlers/main.yaml. Handler-at ndahen midis të gjithë pjesëmarrësve të play-it: pre/post_tasks mund të thërrasin handler-at e rolit, dhe roli mund të thërrasë handler-at nga play-i. Sidoqoftë, thirrjet "kryqërore" të handlerëve shkaktojnë shumë më tepër confuzion sesa përsëritja e një handler-i triviale. (Një tjetër element i praktikave më të mira është të përpiqemi të mos përsërisim emrat e handlerëve).

Dallimi kryesor është se një task ekzekutohet (në mënyrë idempotente) gjithmonë (plus/minus etiketat dhe when), dhe një handler — për ndryshimin e gjendjes (notify aktivizohet vetëm nëse ka pasur ndryshime). Çfarë do të thotë kjo? P.sh., që në një ripërsëritje, nëse nuk ka pasur ndryshime, nuk do të ketë as handler. Por pse ndonjëherë mund të nevojitet të ekzekutohet handler-i kur nuk ka pasur ndryshime në detyrën që ka krijuar? P.sh., për shkak se diçka ka dështuar dhe ka pasur ndryshime, por ekzekutimi nuk ka arritur te handler-i. P.sh., për shkak se rrjeta ka qenë përkohësisht e papunë. Konfigurimi është ndryshuar, shërbimi nuk është rinisur. Në ripërsëritjen e ardhshme konfigurimi nuk ndryshon më, dhe shërbimi mbetet me versionin e vjetër të konfigurimit.

Situata me konfigurimin nuk zgjidhet (saktësisht, mund të shpikim vetë një protokoll të veçantë rinisjeje me flamuj skedash etj., por kjo nuk është më ‘basic ansible’ në asnjë formë). Megjithatë, ka një histori tjetër të zakonshme: ne vendosëm aplikacionin, regjistruam .shërbim-dosja, dhe tani duam ta rifreskojmë demonin dhe statusi=në fillim. Dhe vendi natyror për këtë duket të jetë handler. Por nëse e bëjmë atë jo një handler, por një detyrë në fund të listës së detyrave ose një rol, ai do të ekzekutohet idempotent çdo herë. Edhe nëse playbook-u ka dështuar në mes. Kjo nuk zgjidh problemin e restarted (nuk mund të bëni një detyrë me atributin restarted, sepse humbet idempotencën), por padyshim ka vlerë të bëhet state=started, që rrit stabilitetin e përgjithshëm të playbook-eve, pasi zvogëlon numrin e lidhjeve dhe të gjendjeve dinamike.

Një tjetër pronë pozitive e handler-it është se ai nuk e mbingarkon daljen. Nuk kishte ndryshime – nuk ka skipped ose ok të panevojshme në dalje – më lehtë për t'u lexuar. Ky është gjithashtu një pronë negative – nëse gjeni një gabim në një task që ekzekutohet linear në provimin e parë, handler-at do të ekzekutohen vetëm kur ka ndryshime, dmth. nën disa kushte – shumë rrallë. Për shembull, hera e parë në jetë pas pesë vitesh. Dhe, natyrisht, aty do të ketë një gabim në emër dhe gjithçka do të prishë. Dhe herën e dytë ata nuk mund të iniciohen – nuk ka ndryshim.

Një temë e veçantë është disponueshmëria e variablave. Për shembull, nëse keni një notify për një detyrë me cikël, çfarë do të ndodhte me variablat? Mund të arrini një përfundim analitik, por nuk është gjithmonë e thjeshtë, sidomos kur variablat vijnë nga vende të ndryshme.

… Pra handler’ët janë shumë më pak të dobishëm dhe shumë më problematikë se sa duken. Nëse mund të shkruani diçka bukur (pa ngatërrime) pa përdorur handler’ë, është më mirë ta bëni pa ta. Nëse nuk arrini ta bëni bukur — është më mirë që t’i përdorni.

Një lexues i rëndësishëm vë re drejt që ne nuk e kemi diskutuar listen, që handler mund të thërrasë notify për një handler tjetër, që handler mund të përfshijë import_tasks (i cili mund të bëjë include_role me with_items), që sistemi i handler’ëve në Ansible është Turing-përfundimtar, që handler’ët nga include_role ndërthuren në mënyrë interesante me handler’ët nga play etj. — të gjitha këto nuk janë qartësisht "bazat").

Megjithëse është një WTF i caktuar që në të vërtetë është një veçori, dhe për të cilin duhet të kujtojmë. Nëse keni një detyrë që ekzekutohet me delegate_to dhe ajo ka notify, atëherë handler-i përkatës ekzekutohet pa delegate_to, dmth. në hostin ku është emëruar play. (Megjithatë, handler-i mund të ketë delegate_to edhe).

Së pari, dua të them disa fjalë mbi rolet e ripërdorshme. Para se të ishin koleksionet, kishte ideja që mund të krijoheshin role universale, që mund ansible-galaxy install dhe fillova. Funksionon në të gjitha OS-të, në të gjitha variantet dhe në të gjitha situatat. Pra, mendimi im është: kjo nuk funksionon. Çdo rol me mbështetje 100500 rastesh është i destinuar të ketë probleme të rastësishme. Ato mund të zgjidhen me testim të masiv, por si me çdo testim, ose keni një produkt të kartesian të vlerave hyrëse dhe një funksion total, ose keni "disa skenarë të mbuluar". Mendimi im është – është më mirë nëse roli është linear (kompleksiteti ciklomatik 1). include_vars, поддержкой 100500 случаев обречена на бездны corner case багов. Их можно затыкать массированным тестированием, но как с любым тестированием, либо у вас декартово произведение входных значений и тотальная функция, либо у вас "покрыты отдельные сценарии". Моё мнение — куда лучше, если роль линейная (цикломатическая сложность 1).

Sa më pak if'esh (të qarta ose deklarative – në formën when ose formën include_vars në përputhje me grupin e ndryshoreve), aq më mirë është roli. Ndonjëherë duhet të bëhen ndarje, por, e përsëris, sa më pak të jenë ato, aq më mirë. Pra, duket si një rol i mirë me galaxy (nuk funksionon!) me një sasi të madhe when mund të jetë më pak e preferuar se "roli i vet" nga pesë detyra. Momenti kur roli me galaxy është më i mirë - kur filloni të shkruani diçka. Momenti kur bëhet më keq - kur diçka shkatërrohet, dhe keni dyshime se kjo është për shkak të "rolit me galaxy". E hapni atë, dhe aty janë pesë përfshirje, tetë lista detyrash dhe një grumbull whentë... Dhe në këtë duhet të merret me të. Në vend të 5 detyrave në një listë lineare, ku s’ka asgjë për t’u prishur.

Në pjesët vijuese

  • Pak për inventarin, variablat gruporë, plugin host_group_vars, hostvars. Si të lidhni spaghetti për të krijuar një nyjë Gordiane. Rrethi dhe prioriteti i variablave, modeli i memories Ansible. "Pra, ku duhet ta ruaj emrin e përdoruesit për bazën e të dhënave?"
  • jinja: {{ jinja }} - nosql notype nosense plastelin i butë. Është kudo, madje edhe aty ku nuk e prisni. Pak për !!unsafe dhe YAML të shijshëm.

Burimi: habr.com

Bli një hosting të besueshëm për faqet me mbrojtje DDoS, VPS VDS serverë 🔥 Bli një hosting të besueshëm për faqet me mbrojtje DDoS, VPS VDS serverë | ProHoster