ansible devops kodestil
Hej! Mit navn er jeg arbejder som ingeniør i udviklingsautomatiseringsafdelingen. Hver dag bliver nye applikationer udrullet pü hundreder af virksomhedens servere. I denne artikel deler jeg erfaringer med at bruge Ansible til disse formül.
Denne guide tilbyder en müde at organisere variabler i deployment. Guiden er beregnet til dem, der allerede bruger roller i deres playbooks og har lÌst , men støder pü lignende problemer:
- NĂĽr man finder en variabel i koden, er det umuligt at forstĂĽ, hvad den henviser til med det samme;
- Der er flere roller, og variablerne skal forbindes med Ên vÌrdi, men det kan ikke lade sig gøre;
- Der opstĂĽr vanskeligheder med at forklare andre, hvordan logikken for variabler fungerer i dine playbooks.
Vi har mødt disse problemer i projekter i vores virksomhed, hvilket har ført til, at vi har fastlagt regler for, hvordan variabler skal formateres i vores playbooks, som pü en eller anden müde har løst disse problemer.

Variabler i roller
En rolle er et separat objekt i deployment-systemet. Ligesom enhver anden objekt i systemet, skal det have et interface, der muliggør interaktion med resten af systemet. Dette interface er rollevariablerne.
Lad os tage for eksempel en rolle, apider installerer en Java-applikation pĂĽ serveren. Hvilke variabler kan den have?

Rollevariabler kan opdeles i to typer:
1. Egenskaber
a) uafhÌngige af miljøet
b) afhÌngige af miljøet
2. Relationer
a) lyttere
b) forespørgsler inden for systemet
c) forespørgsler til miljøet
Egenskabsvariabler â er variabler, der definerer adfĂŚrden for rollen.
Forespørgselsvariabler â er variabler, hvis vĂŚrdi bruges til at angive ressourcer, der er eksterne i forhold til rollen.
Lyttervariabler â er variabler, hvis vĂŚrdi bruges til at danne forespørgselsvariabler.
PĂĽ den anden side er 1a, 2a, 2b â variabler, der ikke er afhĂŚngige af miljøet (hardware, eksterne ressourcer osv.) og kan udfyldes med standardvĂŚrdier i rollens standarder. Dog er det umuligt at udfylde variablerne af type 1b og 2c med noget andet end 'example', da de vil variere fra stand til stand afhĂŚngigt af miljøet.
Kodestil
- Navnet pü variablen skal nødvendigvis starte med navnet pü rollen. Det vil gøre det lettere at forstü, hvilken rolle variablen kommer fra, og hvad den henviser til.
- Nür du bruger variabler i roller, skal du altid følge princippet om indkapsling og bruge variabler, der er defineret enten i selve rollen eller i de roller, som den nuvÌrende afhÌnger af.
Prøv ikke at bruge ordbøger til variabler. Ansible tillader ikke nemt at overskrive enkeltvÌrdier i en ordbog.
Eksempel pĂĽ en dĂĽrlig variabel:
myrole_user: login: admin password: adminHer er login en miljøuafhÌngig variabel, mens password er afhÌngig. Men
da de er samlet i en ordbog, bliver du nødt til altid at indtaste det helt
hvilket er meget besvĂŚrligt. Bedre sĂĽdan:myrole_user_login: admin myrole_user_password: admin
Variabler i deploymentsplaybooks
Nür du opretter en deploymentsplaybook (herefter playbook), følger vi reglen om, at den skal placeres i et separat repository. Ligesom rollerne: hver i sit eget git-repository. Dette gør det klart, at roller og playbook er forskellige uafhÌngige objekter i systemet, og Ìndringer i et objekt bør ikke püvirke det andet. Dette opnüs ved at Ìndre de standardvÌrdier, der anvendes for variabler.
NĂĽr du opretter en playbook, hvis vi skal opsummere, er der mulighed for at overskrive standardvĂŚrdierne for rollevariabler pĂĽ to steder: i playbook-variablerne og i inventarvariablerne.
mydeploy # Deploy-katalog
âââ deploy.yml # Deploy-playbook
âââ group_vars # Katalog til playbook-variabler
â  âââ all.yml # Fil til systemets forbindelsesvariabler
â  âââ myapi.yml # Fil til variabler for gruppen myapi
âââ inventories #
âââ prod # Katalog til miljøet prod
  âââ prod.ini # Inventarfil
  âââ group_vars # Katalog til inventarvariabler
    âââ myapi #
      âââ vars.yml # MiljøuafhĂŚngige variabler for gruppen myapi
      âââ vault.yml # Hemmeligheder (altid miljøafhĂŚngige) ** â
Forskellen er, at playbook-variabler altid bruges, nür der kaldes playbooks, der ligger pü samme niveau som dem. Det betyder, at disse variabler er perfekte til at Ìndre standardvÌrdier for variabler, der ikke afhÌnger af miljøet. Omvendt vil inventarvariabler kun blive brugt til et specifikt miljø, hvilket er ideelt til miljøafhÌngige variabler.
Det er vigtigt at bemÌrke, at prioriteringen af variabler ikke vil tillade dig at overskrive variabler først i playbook-variablerne og derefter separat i en inventar.
Dette betyder, at man allerede pü dette stadium skal afgøre, om variablen er miljøafhÌngig eller ej, og placere den det rette sted.
For eksempel var en variabel, der ansvarligt for aktivering af SSL i et projekt i lang tid miljøafhÌngig, da vi ikke kunne aktivere SSL af grunde uden for vores kontrol pü en af testmiljøerne. Efter vi havde løst dette problem, blev den miljøuafhÌngig og blev flyttet til playbook-variablerne.
Egenskabsvariabler for grupper
Lad os udvide vores model fra figur 1 ved at tilføje 2 grupper af servere med en anden Java-applikation, men med forskellige indstillinger.

Lad os forestille os, hvordan playbooken vil se ud i dette tilfĂŚlde:
- hosts: myapi
roles:
- api
- hosts: bbauth
roles:
- auth
- hosts: ghauth
roles:
- authVi har tre grupper i playbooken, sü det anbefales straks at oprette det samme antal gruppefiler i group_vars for inventarvariabler og playbook-variabler. En gruppefil beskriver i dette tilfÌlde en komponent af din applikation i playbooken. Nür du übner gruppefilen i playbook-variablerne, ser du straks alle forskelle fra standardadfÌrden for rollerne installeret pü gruppen. I inventarvariablerne: forskellene i gruppens adfÌrd fra miljø til miljø.
Kodedesign
- Forsøg at undgü at bruge host_vars variabler, da de ikke beskriver systemet, men kun et specifikt tilfÌlde, hvilket i lÌngden vil føre til spørgsmül som: "Hvorfor adskiller denne vÌrt sig fra de andre?", et svar som ikke altid er let at finde.
Relationsvariabler
Men hvad med relationsvariablerne?
Deres forskel er, at de skal have samme vĂŚrdi i forskellige grupper.
I starten var der at bruge en monstrøs konstruktion af typen:
hostvars[groups['bbauth'][0]]['auth_bind_port'], men den blev straks droppet
da den har ulemper. For det første, klodsede. For det andet, afhÌngighed af en bestemt vÌrt i gruppen. For det tredje, det er nødvendigt at indsamle fakta fra alle vÌrter inden deployment, hvis vi ikke vil fü en fejl om en udefineret variabel.
I sidste ende blev det besluttet at bruge relationsvariabler.
Relationsvariabler â dette er variabler, der tilhører playbooken, og som er nødvendige for at forbinde systemobjekter.
Forbindelsesvariabler udfyldes i systemets generelle variabler. group_vars/all/vars og dannes ved at flytte alle lytter-variabler fra hver gruppe og tilføje gruppens navn til starten af variablen, hvorfra lytteren blev flyttet.
PĂĽ den mĂĽde sikres der ensartethed og uoverensstemmelse i navngivningen.
Lad os prøve at forbinde variablerne fra eksemplet ovenfor:

Lad os forestille os, at vi har variabler, der afhĂŚnger af hinanden:
# roles/api/defaults:
# ĐĐľŃĐľĐźĐľĐ˝Đ˝Đ°Ń ĐˇĐ°ĐżŃĐžŃа
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"
# roles/auth/defaults:
# ĐĐľŃĐľĐźĐľĐ˝Đ˝Đ°Ń ŃĐťŃŃаŃоНŃ
auth_bind_port: "20000"Vi flytter til de generelle variabler group_vars/all/vars alle lyttere og tilføjer gruppens navn til navnet:
# 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 Ìndrer vÌrdien af forbindelsen, er vi sikre pü, at forespørgslen vil henvise til det samme sted, hvor porten er placeret.
Kodedesign
- Da roller og grupper er forskellige objekter i systemet, er det nødvendigt, at de har forskellige navne, sü forbindelsesvariablerne prÌcist viser, at de tilhører en bestemt servergruppe og ikke en rolle i systemet.
MiljøafhÌngige filer
I roller kan der bruges filer, der adskiller sig fra miljø til miljø.
Et eksempel pĂĽ sĂĽdanne filer kan vĂŚre SSL-certifikater. At opbevare dem i tekstform
i en variabel er ikke sĂŚrlig praktisk. Det er derimod praktisk at opbevare stien til dem inden i en variabel.
For eksempel, brug variabelen api_ssl_key_file: "/path/to/file".
Da det übenlyst er, at certifikatnøglen vil Ìndre sig fra miljø til miljø, er det en miljøafhÌngig variabel, og den skal derfor placeres i filen
group_vars/myapi/vars inventarvariablerne, og indeholde vĂŚrdien 'til eksempel'.
Det er lettest i dette tilfÌlde at placere nøglefilen i playbookens repository pü stien
files/prod/certs/myapi.key, sĂĽ vĂŚrdien af variablen bliver:
api_ssl_key_file: "prod/certs/myapi.key". Fordelen er, at de personer, der har ansvaret for at implementere systemet pĂĽ et konkret setup, ogsĂĽ har deres eget dedikerede sted i repository til at opbevare deres filer. Samtidig er der mulighed for at angive den absolute sti til certifikatet pĂĽ serveren, i tilfĂŚlde af at certifikaterne leveres af et andet system.
Flere setups i Êt miljø
Der er ofte behov for at implementere flere nÌsten identiske opsÌtninger i et enkelt miljø med minimale forskelle. I südanne tilfÌlde opdeler vi miljøafhÌngige variable i dem, der forbliver uÌndrede inden for dette miljø, og dem, der Ìndres. De sidstnÌvnte bringes direkte ind i selve inventarfilerne. Efter denne manipulation bliver det muligt at oprette endnu en inventar direkte i miljøkataloget.
Det vil genbruge inventar group_vars og ogsĂĽ have mulighed for at overskrive nogle variabler direkte til sig selv.
Den endelige katalogstruktur for deploy-projektet:
mydeploy # Deploy katalog
âââ deploy.yml # Deploy playbook
âââ files # Katalog til deploy filer
â  âââ prod # Katalog for miljøafhĂŚngige filer til prod opsĂŚtningen
â  â  âââ certs #
â  â  âââ myapi.key #
â  âââ test1 # Katalog for miljøafhĂŚngige filer til test1 opsĂŚtningen
âââ group_vars # Katalog for playbook variable
â  âââ all.yml # Fil for systemforbindelsesvariable
â  âââ myapi.yml # Fil for variable til myapi-gruppen
â  âââ bbauth.yml #
â  âââ ghauth.yml #
âââ inventories #
âââ prod # Katalog for prod miljø
â  âââ group_vars # Katalog for inventar variable
â  â  âââ myapi #
â  â  â  âââ vars.yml # MiljøafhĂŚngige variable for myapi-gruppen
â  â  â  âââ vault.yml # Hemmeligheder (altid miljøafhĂŚngige)
â  â  âââ bbauth #
â  â  â  âââ vars.yml #
â  â  â  âââ vault.yml #
â  â  âââ ghauth #
â  â  âââ vars.yml #
â  â  âââ vault.yml #
â  âââ prod.ini # Inventar for prod opsĂŚtningen
âââ test # Katalog for test miljø
âââ group_vars #
â  âââ myapi #
â  â  âââ vars.yml #
â  â  âââ vault.yml #
â  âââ bbauth #
â  â  âââ vars.yml #
â  â  âââ vault.yml #
â  âââ ghauth #
â  âââ vars.yml #
â  âââ vault.yml #
âââ test1.ini # Inventar for test1 opsĂŚtningen i test miljø
âââ test2.ini # Inventar for test2 opsĂŚtningen i test miljøOpsummering
Efter at have organiseret variablerne i henhold til artiklen: hver fil med variabler svarer til en bestemt opgave. Og da filen har bestemte opgaver, blev det muligt at udpege en ansvarlig for korrektheden af hver fil. For eksempel bliver udvikleren af systemets implementering ansvarlig for korrektheden af variablerne i playbooken, mens administratoren, hvis miljø er beskrevet i inventar, er ansvarlig for udfyldningen af inventarvariablerne.
Roller er blevet en selvstĂŚndig enhed i udviklingen med eget interface, hvilket har givet rolloveren mulighed for at udvikle funktioner i stedet for at tilpasse rollen til systemet. IsĂŚr var dette problem relevant for de fĂŚlles roller for alle systemer i kampagnen.
Systemadministratorer behøver ikke lÌngere at forstü implementeringskoden. Alt hvad de skal gøre for en succesfuld implementering, er at udfylde filerne med miljøafhÌngige variabler.
Litteratur
Forfatter
Denis Alexandrovich Kalyuzhny
Kilde: habr.com
