ansible devops kodstandard
Hej! Jag heter jag arbetar som ingenjör inom automatisering av utvecklingsprocesser. Varje dag distribueras nya applikationsversioner pÄ hundratals servrar i företaget. I den hÀr artikeln delar jag med mig av min erfarenhet av att anvÀnda Ansible för dessa ÀndamÄl.
Denna guide erbjuder ett sÀtt att organisera variabler i distributionen. Guiden Àr riktad till dem som redan anvÀnder roller i sina spelböcker och har lÀst , men stöter pÄ liknande problem:
- NÀr man hittar en variabel i koden Àr det svÄrt att förstÄ vad den stÄr för;
- Det finns flera roller och variabler som mÄste kopplas med ett vÀrde, men det gÄr inte;
- Det uppstÄr svÄrigheter i att förklara för andra hur logiken bakom variabler i dina spelböcker fungerar.
Vi har stött pÄ dessa problem i vÄra företags projekt, vilket ledde oss till att vi etablerade regler för hur vi formaterar variabler i vÄra spelböcker, vilket pÄ nÄgot sÀtt löste dessa problem.

Variabler i roller
En roll Àr ett separat objekt i distributionssystemet. Precis som vilket objekt som helst i systemet, mÄste den ha ett grÀnssnitt för interaktion med resten av systemet. Detta grÀnssnitt utgörs av rollvariabler.
LÄt oss ta exempelvis en roll api, som installerar en Java-applikation pÄ servern. Vilka variabler kan den ha?

Rollvariabler kan delas in i 2 typer:
1. Egenskaper
a) oberoende av miljön
b) beroende av miljön
2. Relationer
a) lyssnare
b) interna systemförfrÄgningar
c) externa förfrÄgningar
Egenskapsvariabler Àr variabler som definierar rollens beteende.
FörfrÄgningsvariabler Àr variabler vars vÀrden anvÀnds för att ange externa resurser i förhÄllande till rollen.
Lyssnarvariabler Àr variabler vars vÀrden anvÀnds för att skapa förfrÄgningsvariabler.
Ă andra sidan Ă€r 1a, 2a och 2b variabler som inte Ă€r beroende av miljön (hĂ„rdvara, externa resurser etc.) och kan fyllas med standardvĂ€rden i rollens defaults. Men variabler av typen 1b och 2c kan endast fyllas med vĂ€rden som âexempelâ, eftersom de kommer att variera frĂ„n miljö till miljö.
Kodstandard
- Variabelnamnet ska alltid börja med namnet pÄ rollen. Detta underlÀttar för att förstÄ vilken roll variabeln tillhör och vad den stÄr för.
- NÀr du anvÀnder variabler i roller mÄste du följa principen om inkapsling och anvÀnda variabler som definieras antingen i sjÀlva rollen eller i rollerna som den aktuella beror pÄ.
Försök att inte anvÀnda ordböcker för variabler. Ansible tillÄter inte enkel överskrivning av enskilda vÀrden i en ordbok.
Exempel pÄ en dÄlig variabel:
myrole_user: login: admin password: adminHÀr Àr login en miljöoberoende variabel, medan password Àr beroende. Men
eftersom de Àr sammanslagna i en ordbok mÄste du alltid ange den helt
vilket Àr mycket besvÀrligt. BÀttre sÄ hÀr:myrole_user_login: admin myrole_user_password: admin
Variabler i distributionsspelplaner
NÀr vi skriver en distributionsspelplan (hÀdanefter spelplan) följer vi regeln att den ska placeras i ett separat repository. Precis som roller: varje i sitt eget git-repository. Detta gör att vi inser att roller och spelplan Àr olika oberoende objekt i distributionssystemet, och Àndringar i ett objekt bör inte pÄverka det andra. Detta uppnÄs genom att Àndra standardvÀrdena för variabler.
NÀr vi skriver spelplanen finns det, sammanfattningsvis, möjlighet att överskrida standardvÀrdena för rollvariabler pÄ tvÄ stÀllen: i spelplanens variabler och i inventariens variabler.
mydeploy # Distributionskatalog
âââ deploy.yml # Distributionsspelplan
âââ group_vars # Katalog för spelplanens variabler
â âââ all.yml # Fil för systemets gemensamma variabler
â âââ myapi.yml # Fil för gruppens myapi-egenskapsvariabler
âââ inventories #
âââ prod # Katalog för prod-miljön
âââ prod.ini # Inventariefil
âââ group_vars # Katalog för inventariens variabler
âââ myapi #
âââ vars.yml # Miljöoberoende variabler för gruppen myapi
âââ vault.yml # Hemligheter (alltid miljöberoende) ** â
Skillnaden Àr att spelplansvariabler alltid anvÀnds vid anrop av spelplaner som ligger pÄ samma nivÄ. DÀrför passar dessa variabler utmÀrkt för att Àndra standardvÀrdena för miljöoberoende variabler. à andra sidan kommer inventariens variabler endast att anvÀndas för specifika miljöer, vilket Àr perfekt för miljöberoende variabler.
Det Àr viktigt att notera att prioritetsvariablerna inte tillÄter att du ÄsidosÀtter variabler först i playbook-variablerna och sedan separat i en inventering.
Detta innebÀr att du redan pÄ detta stadium mÄste bestÀmma om variabeln Àr miljöberoende eller inte och placera den pÄ rÀtt stÀlle.
Till exempel har en variabel i ett projekt, som ansvarade för att aktivera SSL, lÀnge varit miljöberoende eftersom vi inte kunde aktivera SSL av skÀl utanför vÄr kontroll pÄ en av miljöerna. NÀr vi löste det problemet blev den miljöoberoende och flyttades till playbook-variablerna.
Egenskapsvariabler för grupper
LÄt oss utvidga vÄr modell i figur 1 genom att lÀgga till 2 grupper av servrar med olika Java-applikationer, men med olika instÀllningar.

LÄt oss förestÀlla oss hur playbooken kommer att se ut i det hÀr fallet:
- hosts: myapi
roles:
- api
- hosts: bbauth
roles:
- auth
- hosts: ghauth
roles:
- authVi har tre grupper i playbooken, sÄ det rekommenderas omedelbart att skapa lika mÄnga gruppfiler i group_vars i bÄde inventeringsvariablerna och playbooken. En gruppfil i det hÀr fallet fungerar som en beskrivning av en komponent i den övergripande applikationen i playbooken. NÀr du öppnar gruppfilen i playbookens variabler ser du genast alla avvikelser frÄn standardbeteendet för roller som Àr installerade pÄ gruppen. I inventeringsvariablerna: avvikelser i gruppens beteende frÄn miljö till miljö.
Kodstil
- Försök att överhuvudtaget inte anvÀnda host_vars-variabler, eftersom de inte beskriver systemet, utan bara ett specifikt fall, vilket i framtiden kan leda till frÄgan: "Varför skiljer sig denna vÀrd frÄn de andra?" vilket svar inte alltid Àr lÀtt att hitta.
Relationsvariabler
Men det gÀller relationsvariabler, hur ska vi hantera dem?
Deras skillnad Àr att de mÄste ha samma vÀrde i olika grupper.
I början var att anvÀnda en monstruös konstruktion av typen:
hostvars[groups['bbauth'][0]]['auth_bind_port'], men den övergavs omedelbart
eftersom den har nackdelar. För det första, otympligheten. För det andra, beroendet av en specifik vÀrd i gruppen. För det tredje, det Àr nödvÀndigt att samla in fakta frÄn alla vÀrdar innan distribution om vi inte vill ha felmeddelandet om att variabeln Àr obestÀmd.
Slutligen beslutades det att anvÀnda relationsvariabler.
Relationsvariabler â det Ă€r variabler som tillhör playbooken och behövs för att koppla samman systemobjekt.
Variabler för kopplingar fylls i de gemensamma systemvariablerna group_vars/all/vars och bildas genom att extrahera alla lyssnare frÄn varje grupp och lÀgga till grupnamnet i början av variabeln som lyssnaren extraherades frÄn.
PÄ sÄ sÀtt sÀkerstÀlls enhetlighet och ingen överlappning av namn.
LÄt oss koppla variablerna frÄn exemplet ovan:

TÀnk dig att vi har variabler som Àr beroende av varandra:
# roles/api/defaults:
# ĐĐ”ŃĐ”ĐŒĐ”ĐœĐœĐ°Ń Đ·Đ°ĐżŃĐŸŃа
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"
# roles/auth/defaults:
# ĐĐ”ŃĐ”ĐŒĐ”ĐœĐœĐ°Ń ŃĐ»ŃŃаŃДлŃ
auth_bind_port: "20000"LÄt oss flytta ut alla lyssnare till gemensamma variabler group_vars/all/vars och lÀgga till gruppnamnet i titeln:
# group_vars/all/vars
bbauth_auth_bind_port: "20000"
ghauth_auth_bind_port: "30000"
# group_vars/bbauth/vars
auth_bind_port: "{{ bbauth_auth_bind_port }}"
# group_vars/ghauth/vars
auth_bind_port: "{{ ghauth_auth_bind_port }}"
# group_vars/myapi/vars
api_auth1_address: "http://{{ bbauth_auth_service_name }}:{{ bbauth_auth_bind_port }}"
api_auth2_address: "http://{{ ghauth_auth_service_name }}:{{ ghauth_auth_bind_port }}"Nu, nÀr vi Àndrar vÀrdet pÄ anslutningen, kan vi vara sÀkra pÄ att förfrÄgan kommer att gÄ till samma plats dÀr porten Àr belÀgen.
Kodstil
- Eftersom roller och grupper Àr olika objekt i systemet, mÄste de ha olika namn för att variablerna för kopplingar tydligt ska visa att de tillhör en specifik servergrupp och inte en roll i systemet.
Miljöberoende filer
I roller kan filer anvÀndas som skiljer sig Ät mellan olika miljöer.
Exempel pÄ sÄdana filer Àr SSL-certifikat. Att lagra dem i textformat
i en variabel Àr inte sÀrskilt praktiskt. Men det Àr bekvÀmt att lagra sökvÀgen till dem inuti en variabel.
Till exempel kan vi anvÀnda variabeln api_ssl_key_file: "/path/to/file".
Eftersom det Àr uppenbart att certifikatsnyckeln kommer att variera mellan miljöer, Àr det en miljöberoende variabel och mÄste dÀrför placeras i filen
group_vars/myapi/vars inventories av variabler, och innehÄlla vÀrdet 'för exempel'.
Det Àr mest bekvÀmt att lÀgga nyckelfilen i playbook-repositoriet pÄ vÀgen
files/prod/certs/myapi.key, dÄ blir variabelns vÀrde:
api_ssl_key_file: "prod/certs/myapi.key". BekvÀmligheten ligger i att de personer som ansvarar för att rulla ut systemet pÄ en specifik installation ocksÄ har ett eget dedikerat utrymme i repositoriet för att lagra sina filer. Samtidigt finns det möjlighet att ange en absolut sökvÀg till certifikatet pÄ servern, ifall certifikaten tillhandahÄlls av ett annat system.
Flera installationer i samma miljö
Det uppstÄr ofta behov av att distribuera flera nÀstan identiska miljöer med minimala skillnader. I detta fall delar vi upp miljöberoende variabler i de som inte Àndras inom denna miljö och de som Àndras. Vi tar ut de senaste direkt till inventariefilerna. Efter denna ÄtgÀrd blir det möjligt att skapa en ny inventariefil direkt i miljökatalogen.
Den kommer att ÄteranvÀnda inventariegroupegenskaper, samt ha möjlighet att överskrida vissa variabler direkt för sig sjÀlv.
Den slutliga katalogstrukturen för distributionsprojektet:
mydeploy # Distributionskatalog
âââ deploy.yml # Distributionsspelbok
âââ files # Katalog för distributionsfiler
â  âââ prod # Katalog för miljöberoende filer av prod-stand
â  â  âââ certs #
â  â  âââ myapi.key #
â  âââ test1 # Katalog för miljöberoende filer av test1-stand
âââ group_vars # Katalog för spelvariabler
â  âââ all.yml # Fil för systemövergripande variabler
â  âââ myapi.yml # Fil för gruppmyapi variabler
â  âââ bbauth.yml #
â  âââ ghauth.yml #
âââ inventories #
âââ prod # Katalog för prod-miljö
â  âââ group_vars # Katalog för inventarievillkor
â  â  âââ myapi #
â  â  â  âââ vars.yml # Miljöberoende variabler för grupp myapi
â  â  â  âââ vault.yml # Hemligheter (alltid miljöberoende)
â  â  âââ bbauth #
â  â  â  âââ vars.yml #
â  â  â  âââ vault.yml #
â  â  âââ ghauth #
â  â  âââ vars.yml #
â  â  âââ vault.yml #
â  âââ prod.ini # Inventariefil för prod-stand
âââ test # Katalog för test-miljö
âââ group_vars #
â  âââ myapi #
â  â  âââ vars.yml #
â  â  âââ vault.yml #
â  âââ bbauth #
â  â  âââ vars.yml #
â  â  âââ vault.yml #
â  âââ ghauth #
â  âââ vars.yml #
â  âââ vault.yml #
âââ test1.ini # Inventariefil för test1-stand i test-miljö
âââ test2.ini # Inventariefil för test2-stand i test-miljöSammanfattning
Efter att ha organiserat variablerna enligt artikeln: varje fil med variabler ansvarar för en viss uppgift. Eftersom filen har specifika uppgifter har det blivit möjligt att utse en ansvarig för riktigheten av varje fil. Till exempel, för korrektheten av variablerna i spelboken blir utvecklaren av systemets distribueringsprocess ansvarig, medan administratören för den beskrivna stÄndpunkten i inventariet ansvarar för ifyllnaden av inventarieveckans variabler.
Rollerna har blivit en sjÀlvstÀndig enhet inom utvecklingen med ett eget grÀnssnitt, vilket möjliggör för rollerutvecklaren att utveckla funktioner istÀllet för att anpassa rollen till systemet. SÀrskilt var detta problem relevant för gemensamma roller för alla system inom företaget.
Systemadministratörer behöver inte lÀngre förstÄ sig pÄ distributionskoden. Allt som krÀvs av dem för en framgÄngsrik distribution Àr att fylla i filerna för miljöberoende variabler.
Litteratur
Författare
Kaljuzhny Denis Alexandrovich
KĂ€lla: habr.com
