Systematiskt angreppssÀtt för variabler i Ansible

ansible devops kodstandard

Hej! Jag heter Denis Kalyuzhnyy 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 BestPractices, 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.

Systematiskt angreppssÀtt för variabler i Ansible

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?

Systematiskt angreppssÀtt för variabler i Ansible

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: admin

    HÀ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) *

* — Variabler och valv

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.

Systematiskt angreppssÀtt för variabler i Ansible

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:
    - auth

Vi 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 idé 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:

Systematiskt angreppssÀtt för variabler i Ansible

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

  1. Dokumentation

Författare

Kaljuzhny Denis Alexandrovich

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster