Approccio sistemico alle variabili in Ansible

codice di stile devops ansible

Ciao! Mi chiamo Denis Kalujnyj lavoro come ingegnere nel dipartimento di automazione dei processi di sviluppo. Ogni giorno nuove versioni delle applicazioni vengono distribuite su centinaia di server dell'azienda. In questo articolo, condivido l'esperienza nell'uso di Ansible per questi scopi.

Questa guida offre un modo per organizzare le variabili nel deployment. È rivolta a chi utilizza già i ruoli nei propri playbook e ha letto BestPractices, ma si trova a fronteggiare problemi simili:

  • Trovare una variabile nel codice non consente di capire immediatamente a cosa serve;
  • Ci sono diversi ruoli e le variabili devono essere collegate a un unico valore, ma non ci riesco;
  • Ci sono difficoltà a spiegare agli altri come funziona la logica delle variabili nei tuoi playbook.

Abbiamo affrontato queste problematiche nei progetti della nostra azienda, da cui siamo giunti a delle regole per la formattazione delle variabili nei nostri playbook, che hanno risolto in parte queste problematiche.

Approccio sistemico alle variabili in Ansible

Variabili nei ruoli

Un ruolo è un oggetto separato del sistema di deployment. Come qualsiasi oggetto del sistema, deve avere un'interfaccia di interazione con il resto del sistema. Questa interfaccia sono le variabili del ruolo.

Prendiamo, per esempio, il ruolo api, che installa un'applicazione Java sul server. Quali variabili possono esserci?

Approccio sistemico alle variabili in Ansible

Le variabili del ruolo possono essere suddivise in 2 categorie per tipo:

1. Proprietà
    a) indipendenti dall'ambiente
    b) dipendenti dall'ambiente
2. Relazioni
    a) ascoltatori
    b) richieste interne al sistema
    c) richieste all'ambiente

Variabili proprietà — sono variabili che determinano il comportamento del ruolo.

Variabili richiesta — sono variabili, il cui valore è utilizzato per indicare risorse esterne rispetto al ruolo.

Variabili ascoltatori — sono variabili, il cui valore è utilizzato per generare variabili richiesta.

D'altra parte, 1a, 2a, 2b — sono variabili che non dipendono dall'ambiente (hardware, risorse esterne, ecc.) e possono essere compilate con valori predefiniti in defaults del ruolo. Tuttavia, variabili tipo 1b e 2c possono essere compilate solo con valori come ‘example’, poiché cambieranno da stand a stand a seconda dell'ambiente.

Stile del codice

  • Il nome della variabile deve iniziare necessariamente con il nome del ruolo. Questo faciliterà in seguito la comprensione da quale ruolo proviene la variabile e a cosa serve.
  • Quando si utilizzano variabili nei ruoli, è fondamentale seguire il principio dell'incapsulamento e utilizzare variabili definite o all'interno dello stesso ruolo o nei ruoli da cui quello attuale dipende.
  • Cerca di non utilizzare dizionari per le variabili. Ansible non consente di sovrascrivere comodamente singoli valori in un dizionario.

    Esempio di una cattiva variabile:

    myrole_user:
        login: admin
        password: admin

    Qui login è una variabile indipendente, mentre password è dipendente. Ma
    poiché sono raggruppate in un dizionario, dovrai definirla completamente
    ogni volta. Il che è molto scomodo. Meglio così:

    myrole_user_login: admin
    myrole_user_password: admin

Variabili nei playbook di deploy

Quando si compila un playbook di deploy (di seguito playbook), seguiamo la regola che deve essere collocato in un repository separato. Proprio come i ruoli: ognuno nel proprio repository git. Questo consente di comprendere che i ruoli e il playbook sono oggetti indipendenti del sistema di deployment e le modifiche in un oggetto non devono influire sul funzionamento dell'altro. Questo si ottiene modificando i valori predefiniti delle variabili.

Quando si crea un playbook, in sintesi, è possibile ridefinire i valori predefiniti delle variabili di ruolo in due luoghi: nelle variabili del playbook e nelle variabili di inventario.

mydeploy                        # Directory di deployment
├── deploy.yml                  # Playbook di deployment
├── group_vars                  # Directory delle variabili del playbook
│   ├── all.yml                 # File per le variabili relative all'intero sistema
│   └── myapi.yml               # File delle variabili per il gruppo myapi
└── inventories                 #
    └── prod                    # Directory dell'ambiente prod
      ├── prod.ini              # File di inventario
      └── group_vars            # Directory per le variabili di inventario
          └── myapi             #
              ├── vars.yml      # Variabili specifiche del gruppo myapi
              └── vault.yml     # Segreti (sempre specifici del proprio ambiente) *

* — Variabili e Vaults

La differenza è che le variabili del playbook vengono utilizzate sempre quando si chiamano i playbook che si trovano allo stesso livello. Questo significa che queste variabili sono perfette per modificare i valori predefiniti delle variabili che non dipendono dall'ambiente. Al contrario, le variabili di inventario verranno utilizzate solo per un ambiente specifico, il che è ideale per le variabili che dipendono dall'ambiente.

È importante notare che la priorità delle variabili non ti permetterà di sovrascrivere prima le variabili nel playbook e poi separatamente in un inventario.

Questo significa che già a questo stadio devi determinare se la variabile è dipendente dall'ambiente o meno e posizionarla nel posto giusto.

Ad esempio, in un progetto, una variabile che gestiva l'attivazione di SSL è stata a lungo dipendente dall'ambiente, poiché non potevamo attivare SSL per motivi a noi estranei su una delle installazioni. Dopo aver risolto questo problema, è diventata indipendente dall'ambiente ed è stata spostata nelle variabili del playbook.

Variabili delle proprietà per i gruppi

Espandiamo il nostro modello nell'immagine 1, aggiungendo 2 gruppi di server con una diversa applicazione Java, ma con impostazioni diverse.

Approccio sistemico alle variabili in Ansible

Immagina come apparirà il playbook in questo caso:

- hosts: myapi
  roles:
    - api

- hosts: bbauth
  roles:
    - auth

- hosts: ghauth
  roles:
    - auth

Abbiamo tre gruppi nel playbook, quindi si consiglia subito di creare altrettanti file di gruppo nelle variabili group_vars delle risorse inventari e del playbook. Un file di gruppo in questo caso descrive un componente dell'applicazione nel playbook. Aprendo il file di gruppo nelle variabili del playbook, puoi subito vedere tutte le differenze rispetto al comportamento predefinito dei ruoli impostati per il gruppo. Nelle variabili dell'inventario: le differenze nel comportamento del gruppo rispetto a quello di ogni ambiente.

Stile di Codice

  • Cerca di non utilizzare affatto le variabili host_vars, poiché non descrivono il sistema, ma solo un caso particolare, il che porterà a domande come: "Perché questo host è diverso dagli altri?", a cui non è sempre facile trovare risposta.

Variabili di connessione

Tuttavia, questo riguarda le variabili di proprietà, ma come si può affrontare le variabili di connessione?
La loro differenza sta nel fatto che devono avere lo stesso valore in diversi gruppi.

Inizialmente c'era idea utilizzare una costrizione mostruosa del tipo:
hostvars[groups['bbauth'][0]]['auth_bind_port'], ma subito si è rinunciato.
poiché presenta degli svantaggi. In primo luogo, la complessità. In secondo luogo, la dipendenza da un determinato host nel gruppo. In terzo luogo, è necessario raccogliere i dati da tutti gli host prima di iniziare il deployment, se non vogliamo incorrere in un errore di variabile non definita.

Alla fine, si è deciso di utilizzare le variabili di collegamento.

Variabili di connessione — sono variabili che appartengono al playbook e servono per collegare oggetti del sistema.

Le variabili di collegamento vengono riempite nelle variabili generali del sistema group_vars/all/vars e si formano estraendo tutte le variabili degli ascoltatori da ciascun gruppo e aggiungendo all'inizio della variabile il nome del gruppo da cui è stato estratto l'ascoltatore.

In questo modo si garantisce coerenza e non sovrapposizione dei nomi.

Proviamo a collegare le variabili dell'esempio sopra:

Approccio sistemico alle variabili in Ansible

Immaginiamo di avere variabili che dipendono l'una dall'altra:

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

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

Estraiamo nelle variabili generali group_vars/all/vars tutti gli ascoltatori e aggiungiamo al nome il nome del gruppo:

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

Ora, cambiando il valore del connettore, saremo certi che la richiesta si riferisca allo stesso luogo in cui si trova la porta.

Stile di Codice

  • Poiché ruoli e gruppi sono oggetti diversi nel sistema, devono avere nomi distinti, in modo che le variabili di collegamento mostrino chiaramente a quali gruppi di server appartengono, e non a un ruolo nel sistema.

File dipendenti dall'ambiente

Nei ruoli possono essere utilizzati file che differiscono da ambiente a ambiente.

Un esempio di tali file potrebbe essere rappresentato dai certificati SSL. Conservare questi in forma testuale
in una variabile non è molto pratico. Tuttavia, è conveniente memorizzare il percorso all'interno della variabile.

Ad esempio, utilizziamo la variabile api_ssl_key_file: "/path/to/file".

Poiché è chiaro che il certificato della chiave cambierà da ambiente a ambiente, questa è una variabile dipendente dall'ambiente, e quindi deve trovarsi nel file
group_vars/myapi/vars dell'inventario delle variabili, e contenere il valore 'per esempio'.

È più conveniente in questo caso posizionare il file della chiave nel repository del playbook al percorso
files/prod/certs/myapi.key, quindi il valore della variabile sarà:
api_ssl_key_file: "prod/certs/myapi.key". La comodità risiede nel fatto che le persone responsabili del dispiegamento del sistema su una specifica postazione hanno anche il proprio spazio dedicato nel repository per memorizzare i propri file. Allo stesso tempo, rimane possibile specificare il percorso assoluto al certificato sul server, nel caso in cui i certificati siano forniti da un altro sistema.

Più postazioni in un ambiente

Spesso sorge la necessità di dispiegare più postazioni praticamente identiche in un ambiente con lievi differenze. In questo caso, suddividiamo le variabili dipendenti dall'ambiente in quelle che non cambiano all'interno di questo ambiente e in quelle che cambiano. E trasferiamo queste ultime direttamente nei file di inventario. Dopo questa operazione, diventa possibile creare un ulteriore inventario direttamente nella directory dell'ambiente.

Questo riutilizzerà le group_vars di inventario e avrà anche la possibilità di ridefinire alcune variabili direttamente per le proprie esigenze.

Struttura finale delle directory per il progetto di distribuzione:

mydeploy                        # Catalogo di deploy
├── deploy.yml                  # Playbook di deploy
├── files                       # Catalogo per i file di deploy
│   ├── prod                    # Catalogo per i file dipendenti dall'ambiente prod
│   │   └── certs               # 
│   │       └── myapi.key       #
│   └── test1                   # Catalogo per i file dipendenti dall'ambiente test1
├── group_vars                  # Catalogo delle variabili del playbook
│   ├── all.yml                 # File per le variabili generali di sistema
│   ├── myapi.yml               # File delle variabili del gruppo myapi
│   ├── bbauth.yml              # 
│   └── ghauth.yml              #
└── inventories                 #
    ├── prod                    # Catalogo dell'ambiente prod
    │   ├── group_vars          # Catalogo per le variabili di inventario
    │   │   ├── myapi           #
    │   │   │   ├── vars.yml    # Variabili dipendenti dall'ambiente del gruppo myapi
    │   │   │   └── vault.yml   # Segreti (sempre dipendenti dall'ambiente)
    │   │   ├── bbauth          # 
    │   │   │   ├── vars.yml    #
    │   │   │   └── vault.yml   #
    │   │   └── ghauth          #
    │   │       ├── vars.yml    #
    │   │       └── vault.yml   #
    │   └── prod.ini            # Inventario dell'ambiente prod
    └── test                    # Catalogo dell'ambiente test
        ├── group_vars          #
        │   ├── myapi           #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   ├── bbauth          #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   └── ghauth          #
        │       ├── vars.yml    #
        │       └── vault.yml   #
        ├── test1.ini           # Inventario dell'ambiente test1 nell'ambiente test
        └── test2.ini           # Inventario dell'ambiente test2 nell'ambiente test

Sintesi

Dopo aver organizzato le variabili secondo l'articolo: ogni file con variabili è responsabile di un compito specifico. E dato che ogni file ha determinati compiti, è stato possibile nominare un responsabile per la correttezza di ciascun file. Ad esempio, il responsabile per la corretta compilazione delle variabili del playbook diventa lo sviluppatore del deployment del sistema, mentre il riempimento delle variabili di inventario è responsabilità diretta dell'amministratore il cui stand è descritto nell'inventario.

I ruoli sono diventati un'unità di sviluppo autonoma con un'interfaccia propria, permettendo allo sviluppatore di un ruolo di sviluppare funzionalità, piuttosto che adattare il ruolo al sistema. Questo problema riguardava in particolare i ruoli comuni per tutti i sistemi dell'azienda.

Gli amministratori di sistema non devono più comprendere il codice di deployment. Tutto ciò che è richiesto per un deployment di successo è riempire i file delle variabili dipendenti dall'ambiente.

Letteratura

  1. Documentazione

Autore

Kalujniy Denis Alexandrovich

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster