Systeembenadering van variabelen in Ansible

ansible devops-codestijl

Hoi! Mijn naam is Denis Kaljoezjny Ik werk als engineer op de afdeling ontwikkelprocesautomatisering. Elke dag worden er nieuwe applicatiebuilds uitgerold op honderden campagneservers. En in dit artikel deel ik mijn ervaring met het gebruik van Ansible voor deze doeleinden.

Deze handleiding biedt een manier om variabelen tijdens de implementatie te organiseren. Deze handleiding is bedoeld voor degenen die al rollen in hun draaiboeken gebruiken en hebben gelezen Beste praktijken, maar kampt met soortgelijke problemen:

  • Als je een variabele in de code hebt gevonden, is het onmogelijk om meteen te begrijpen waarvoor deze verantwoordelijk is;
  • Er zijn verschillende rollen en de variabelen moeten aan één waarde worden gekoppeld, maar dat werkt gewoon niet;
  • Moeite hebben om aan anderen uit te leggen hoe de logica van de variabelen in uw draaiboeken werkt

Deze problemen kwamen we tegen bij projecten in ons bedrijf, waardoor we in onze draaiboeken tot regels kwamen voor het ontwerpen van variabelen, waarmee deze problemen voor een deel werden opgelost.

Systeembenadering van variabelen in Ansible

Variabelen in rollen

Een rol is een afzonderlijk object van het implementatiesysteem. Zoals elk systeemobject moet het een interface hebben voor interactie met de rest van het systeem. Zo'n interface zijn rolvariabelen.

Laten we bijvoorbeeld de rol nemen api, waarmee een Java-applicatie op de server wordt geïnstalleerd. Welke variabelen zou het kunnen hebben?

Systeembenadering van variabelen in Ansible

Variabele rollen kunnen naar type worden onderverdeeld in 2 typen:

1. Свойства
    a) независимые от среды
    б) зависимые от среды
2. Связи
    a) слушатели 
    б) запросы внутри системы
    в) запросы в среду

Variabele eigenschappen zijn variabelen die het gedrag van een rol bepalen.

Variabelen opvragen - dit zijn variabelen waarvan de waarde wordt gebruikt om bronnen buiten de rol aan te duiden.

Variabele luisteraars - dit zijn variabelen waarvan de waarde wordt gebruikt om verzoekvariabelen te vormen.

Aan de andere kant zijn 1a, 2a, 2b variabelen die niet afhankelijk zijn van de omgeving (hardware, externe bronnen, enz.) en kunnen worden gevuld met standaardwaarden in de standaardrol. Het is echter onmogelijk om variabelen van type 1.b en 2.c te vullen met andere waarden dan 'example', aangezien deze afhankelijk van de omgeving van stand tot stand zullen veranderen.

Codestijl

  • De variabelenaam moet beginnen met de rolnaam. Dit maakt het in de toekomst gemakkelijk om erachter te komen welke rol de variabele speelt en waarvoor deze verantwoordelijk is.
  • Wanneer u variabelen in rollen gebruikt, moet u er zeker van zijn dat u het principe van inkapseling volgt en variabelen gebruikt die zijn gedefinieerd in de rol zelf of in de rollen waarvan de huidige afhankelijk is.
  • Vermijd het gebruik van woordenboeken voor variabelen. Met Ansible kun je niet gemakkelijk individuele waarden in een woordenboek overschrijven.

    Voorbeeld van een slechte variabele:

    myrole_user:
        login: admin
        password: admin

    Hier is login de onafhankelijke variabele en wachtwoord de afhankelijke variabele. Maar
    aangezien ze gecombineerd zijn in een woordenboek, zul je het volledig moeten specificeren
    Altijd. Dat is erg lastig. Beter zo:

    myrole_user_login: admin
    myrole_user_password: admin

Variabelen in implementatieplaybooks

Bij het samenstellen van een deployment playbook (hierna: het playbook) hanteren wij de regel dat deze in een aparte repository geplaatst dient te worden. Hetzelfde als rollen: elk in zijn eigen git-repository. Hierdoor begrijpt u dat rollen en draaiboek verschillende onafhankelijke objecten van het implementatiesysteem zijn, en dat wijzigingen in het ene object de werking van het andere object niet mogen beïnvloeden. Dit wordt bereikt door de standaardwaarden van variabelen te wijzigen.

Bij het samenstellen van een playbook is het, kort samengevat, mogelijk om de standaardwaarden van rolvariabelen op twee plaatsen te overschrijven: in playbookvariabelen en in inventarisvariabelen.

mydeploy                        # Каталог деплоя
├── deploy.yml                  # Плейбук деплоя
├── group_vars                  # Каталог переменных плейбука
│   ├── all.yml                 # Файл для переменных связи всей системы
│   └── myapi.yml               # Файл переменных свойств группы myapi
└── inventories                 #
    └── prod                    # Каталог окружения prod
        ├── prod.ini            # Инвентори файл
        └── group_vars          # Каталог для переменных инвентори
            └── myapi           #
                ├── vars.yml    # Средозависимые переменные группы myapi
                └── vault.yml   # Секреты (всегда средозависимы) *

* - Variabelen en kluizen

Het verschil is dat draaiboekvariabelen altijd worden gebruikt bij het aanroepen van draaiboeken die zich op hetzelfde niveau bevinden. Dit betekent dat deze variabelen uitstekend geschikt zijn voor het wijzigen van de standaardwaarden van omgevingsonafhankelijke variabelen. Omgekeerd zullen inventarisvariabelen alleen voor een specifieke omgeving worden gebruikt, wat ideaal is voor omgevingsspecifieke variabelen.

Het is belangrijk op te merken dat u met de variabeleprioriteit niet toestaat variabelen eerst in draaiboekvariabelen en vervolgens afzonderlijk in één inventaris te overschrijven.

Dit betekent dat het al in dit stadium nodig is om te beslissen of de variabele al dan niet omgevingsafhankelijk is en deze op de juiste plaats te plaatsen.

In één project was de variabele die verantwoordelijk was voor het inschakelen van SSL bijvoorbeeld lange tijd afhankelijk van de omgeving, omdat we SSL op een van de stands niet konden inschakelen om redenen buiten onze macht. Nadat we dit probleem hadden opgelost, werd het omgevingsonafhankelijk en verplaatst naar playbookvariabelen.

Eigenschapsvariabelen voor groepen

Laten we ons model in Figuur 1 uitbreiden door twee groepen servers toe te voegen met een andere Java-applicatie, maar met verschillende instellingen.

Systeembenadering van variabelen in Ansible

Laten we ons voorstellen hoe het draaiboek er in dit geval uit zal zien:

- hosts: myapi
  roles:
    - api

- hosts: bbauth
  roles:
    - auth

- hosts: ghauth
  roles:
    - auth

We hebben drie groepen in het draaiboek, dus het wordt onmiddellijk aanbevolen om hetzelfde aantal groepsbestanden te maken in de inventarisvariabelen van group_vars en het draaiboek. Eén groepsbestand is in dit geval een beschrijving van één onderdeel van de bovenstaande applicatie in het playbook. Wanneer u een groepsbestand opent in de draaiboekvariabelen, ziet u onmiddellijk alle verschillen met het standaardgedrag van de rollen die in de groep zijn geïnstalleerd. In inventarisvariabelen: verschillen in groepsgedrag van stand tot stand.

Code stijl

  • Probeer helemaal geen host_vars-variabelen te gebruiken, aangezien deze het systeem niet beschrijven, maar slechts een speciaal geval, dat in de toekomst tot vragen zal leiden: "Waarom is deze host anders dan de anderen?", Waarop het antwoord niet luidt altijd gemakkelijk te vinden.

Communicatievariabelen

Dat is echter waar het bij eigenschapsvariabelen om draait, maar hoe zit het met communicatievariabelen?
Hun verschil is dat ze in verschillende groepen dezelfde betekenis zouden moeten hebben.

In eerste instantie was dat zo идея gebruik een monsterlijke constructie zoals:
hostvars[groups['bbauth'][0]]['auth_bind_port'], maar ze wezen het onmiddellijk af
omdat het nadelen heeft. In de eerste plaats de omvang. Ten tweede de afhankelijkheid van een specifieke gastheer in de groep. Ten derde is het, voordat we met de implementatie beginnen, noodzakelijk om feiten van alle hosts te verzamelen als we geen fout willen krijgen van een ongedefinieerde variabele.

Als gevolg hiervan werd besloten om communicatievariabelen te gebruiken.

Communicatievariabelen - dit zijn variabelen die bij het draaiboek horen en nodig zijn om systeemobjecten met elkaar te verbinden.

Communicatievariabelen worden ingevuld in algemene systeemvariabelen group_vars/all/vars en worden gevormd door alle luisteraarvariabelen uit elke groep te verwijderen, en de naam van de groep waaruit de luisteraar is verwijderd toe te voegen aan het begin van de variabele.

Dit garandeert de uniformiteit en het niet overlappen van namen.

Laten we proberen de variabelen uit het bovenstaande voorbeeld te binden:

Systeembenadering van variabelen in Ansible

Laten we ons voorstellen dat we variabelen hebben die van elkaar afhankelijk zijn:

# roles/api/defaults:
# Переменная запроса
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"

# roles/auth/defaults:
# Переменная слушатель
auth_bind_port: "20000"

Laten we het in gemeenschappelijke variabelen plaatsen group_vars/all/vars alle luisteraars en voeg de naam van de groep toe aan de titel:

# 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 }}"

Door nu de waarde van de connector te wijzigen, weten we zeker dat het verzoek naar dezelfde plaats gaat als waar de poort zich bevindt.

Code stijl

  • Omdat rollen en groepen verschillende systeemobjecten zijn, moeten ze verschillende namen hebben. De linkvariabelen zullen dan nauwkeurig aangeven dat ze tot een specifieke groep servers behoren, en niet tot een rol in het systeem.

Omgevingsafhankelijke bestanden

Rollen kunnen bestanden gebruiken die van omgeving tot omgeving verschillen.

Een voorbeeld van dergelijke bestanden zijn SSL-certificaten. Bewaar ze in tekstvorm
in een variabele is niet erg handig. Maar het is handig om het pad ernaartoe in een variabele op te slaan.

We gebruiken bijvoorbeeld de variabele api_ssl_key_file: "/path/to/file".

Omdat het duidelijk is dat het sleutelcertificaat van omgeving tot omgeving zal veranderen, is dit een omgevingsafhankelijke variabele, wat betekent dat deze zich in het bestand moet bevinden
group_vars/myapi/vars inventaris van variabelen, en bevatten de waarde 'bijvoorbeeld'.

De handigste manier in dit geval is om het sleutelbestand in de playbook-repository langs het pad te plaatsen
files/prod/certs/myapi.key, dan is de waarde van de variabele:
api_ssl_key_file: "prod/certs/myapi.key". Het gemak ligt in het feit dat de mensen die verantwoordelijk zijn voor het inzetten van het systeem op een specifieke stand ook een eigen ruimte in de repository hebben om hun bestanden op te slaan. Tegelijkertijd blijft het mogelijk om het absolute pad naar het certificaat op de server op te geven, voor het geval de certificaten door een ander systeem worden aangeleverd.

Meerdere stands in één omgeving

Vaak is er behoefte om meerdere vrijwel identieke stands in dezelfde omgeving in te zetten met minimale verschillen. In dit geval verdelen we omgevingsafhankelijke variabelen in variabelen die niet veranderen binnen deze omgeving en variabelen die wel veranderen. En deze laatste zetten wij direct over naar de inventarisbestanden zelf. Na deze manipulatie wordt het mogelijk om rechtstreeks in de omgevingsmap nog een inventaris aan te maken.

Het zal de group_vars-inventaris hergebruiken en zal ook enkele variabelen rechtstreeks voor zichzelf opnieuw kunnen definiëren.

De uiteindelijke mapstructuur voor het implementatieproject:

mydeploy                        # Каталог деплоя
├── deploy.yml                  # Плейбук деплоя
├── files                       # Каталог для файлов деплоя
│   ├── prod                    # Католог для средозависимых файлов стенда prod
│   │   └── certs               # 
│   │       └── myapi.key       #
│   └── test1                   # Каталог для средозависимых файлов стенда test1
├── group_vars                  # Каталог переменных плейбука
│   ├── all.yml                 # Файл для переменных связи всей системы
│   ├── myapi.yml               # Файл переменных свойств группы myapi
│   ├── bbauth.yml              # 
│   └── ghauth.yml              #
└── inventories                 #
    ├── prod                    # Каталог окружения prod
    │   ├── group_vars          # Каталог для переменных инвентори
    │   │   ├── myapi           #
    │   │   │   ├── vars.yml    # Средозависимые переменные группы myapi
    │   │   │   └── vault.yml   # Секреты (всегда средозависимы)
    │   │   ├── bbauth          # 
    │   │   │   ├── vars.yml    #
    │   │   │   └── vault.yml   #
    │   │   └── ghauth          #
    │   │       ├── vars.yml    #
    │   │       └── vault.yml   #
    │   └── prod.ini            # Инвентори стенда prod
    └── test                    # Каталог окружения test
        ├── group_vars          #
        │   ├── myapi           #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   ├── bbauth          #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   └── ghauth          #
        │       ├── vars.yml    #
        │       └── vault.yml   #
        ├── test1.ini           # Инвентори стенда test1 в среде test
        └── test2.ini           # Инвентори стенда test2 в среде test

Opsommen

Na het organiseren van de variabelen volgens het artikel: elk variabelenbestand is verantwoordelijk voor een specifieke taak. En omdat het dossier bepaalde taken heeft, werd het mogelijk om voor elk dossier iemand aan te wijzen die verantwoordelijk was voor de juistheid ervan. Zo wordt de ontwikkelaar van de systeemimplementatie verantwoordelijk voor het correct invullen van playbookvariabelen, terwijl de beheerder wiens standpunt in de inventarisatie wordt beschreven direct verantwoordelijk is voor het vullen van de inventaris van variabelen.

Rollen werden hun eigen ontwikkelingseenheid met hun eigen interface, waardoor de rolontwikkelaar capaciteiten kon ontwikkelen in plaats van de rol aan te passen aan het systeem. Dit probleem betrof vooral de gemeenschappelijke rollen voor alle systemen in de campagne.

Systeembeheerders hoeven de implementatiecode niet langer te begrijpen. Het enige dat van hen wordt verlangd voor een succesvolle implementatie is het invullen van de bestanden met omgevingsafhankelijke variabelen.

Literatuur

  1. Документация

Auteur

Kaljoezjni Denis Alexandrovitsj

Bron: www.habr.com

Voeg een reactie