Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Questa è la trascrizione dell'esibizione con DevOps-40 2020-03-18:

A partire dal secondo commit, qualsiasi codice diventa legacy, poiché le idee iniziali iniziano a divergere dalla dura realtà. Non è né buono né cattivo, è una condizione con cui è difficile discutere e con la quale è necessario convivere. Parte di questo processo è il refactoring. Refactoring dell'Infrastructure as Code. Inizia la storia su come rifattorizzare Ansible in un anno senza perdere la testa.

Nascita del Legacy

Giorno n. 1: Il paziente zero

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

C'era una volta un progetto condizionale. Aveva un team di sviluppo Dev e ingegneri Ops. Entrambi cercavano di risolvere la stessa questione: come distribuire server e avviare l'applicazione. Il problema era che ciascun team affrontava questa questione a modo suo. Sul progetto si decise di utilizzare Ansible per sincronizzare le conoscenze tra i team Dev e Ops.

Giorno n. 89: Nascita del Legacy

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Senzi rendersene conto, volevano fare del loro meglio, ma è diventato legacy. Come è possibile?

  • Abbiamo un compito urgente, faremo un hack veloce — poi lo sistemeremo.
  • Non è necessario scrivere documentazione, è tutto chiaro su cosa sta succedendo qui.
  • So Ansible / Python / Bash / Terraform! Guardate come posso destreggiarmi!
  • Sono un Full Stack Overflow Developer e ho copiato questo da stackoverflow; non so come funzioni, ma sembra interessante e risolve il problema.

Alla fine si può ottenere un codice di aspetto strano, per il quale non esiste documentazione, non è chiaro cosa faccia, se sia necessario, ma il problema è che è necessario svilupparlo, apportare modifiche e aggiungere soluzioni palliative, peggiorando ulteriormente la situazione.

- hosts: localhost
  tasks:
    - shell: echo -n Z >> a.txt && cat a.txt
      register: output
      delay: 1
      retries: 5
      until: not output.stdout.find("ZZZ")

Giorno n. 109: Comprensione del problema

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Il modello IaC originariamente concepito e implementato smette di rispondere alle richieste degli utenti / del business / di altri team, il tempo per apportare modifiche all'infrastruttura smette di essere accettabile. In questo momento si comprende che è giunto il momento di agire.

Refactoring IaC

Giorno n. 139: Hai davvero bisogno di un refactoring?

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Prima di lanciarti nel refactoring devi rispondere a una serie di domande importanti:

  1. Perché hai bisogno di tutto questo?
  2. Hai tempo?
  3. Hai conoscenze sufficienti?

Se non sai come rispondere a queste domande, il refactoring potrebbe non mai iniziare o potrebbe semplicemente peggiorare. Poiché hai già avuto esperienze simili. Cosa ho appreso testando 200.000 righe di codice infrastrutturale.), è arrivata una richiesta dal progetto per aiutare a correggere i ruoli e coprirli con test.

Giorno n. 149: Preparazione del refactoring

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

La priorità è prepararsi. Stabilire cosa vogliamo fare. Per questo comunicamo, identifichiamo i punti problematici e valutiamo le possibili soluzioni. Fissiamo in qualche modo i concetti ottenuti, ad esempio con un articolo in Confluence, in modo da non perderci nel caso sorgessero domande su "come è meglio?" o "qual è la soluzione corretta?". Nel nostro caso abbiamo seguito l'idea dividi e conquista: scomponiamo l'infrastruttura in piccoli pezzi / mattoncini. Questo approccio consente di prendere un pezzo isolato dell'infrastruttura, capire cosa fa, coprirlo con test e modificarlo senza temere di rompere qualcosa.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Di conseguenza, il testing dell'infrastruttura diventa la pietra angolare e qui vale la pena menzionare la piramide del testing dell'infrastruttura. Proprio come nell'ambito dello sviluppo, ma per l'infrastruttura: partiamo da test rapidi e poco costosi che verificano semplici aspetti, come i margini, fino a test completi e costosi che distribuiscono un'infrastruttura intera.

Tentativi di testing Ansible

Prima di descrivere come abbiamo testato Ansible nel progetto, descriverò i tentativi e gli approcci che ho dovuto utilizzare in precedenza per capire il contesto delle decisioni prese.

Giorno n° -997: Provisionamento SDS

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

La prima volta che ho testato Ansible è stata in un progetto di sviluppo SDS (Software Defined Storage). Esiste un articolo separato su questo argomento.
Come rompere biciclette sopra stampelle durante il test della propria distribuzione, ma per dirla brevemente, abbiamo ottenuto una piramide rovesciata di test e spendevamo dai 60 ai 90 minuti su un singolo ruolo, il che è lungo. La base era composta da test e2e, ovvero implementavamo un'installazione completa e poi la testavamo. Inoltre, pesava il fatto che stessimo inventando la nostra bicicletta. Ma devo ammettere che questa soluzione funzionava e permetteva di rilasciare in modo stabile.

Giorno n° -701: Ansible e test kitchen

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Lo sviluppo dell'idea di testare Ansible ha portato all'uso di strumenti pronti, in particolare test kitchen / kitchen-ci e inspec. La scelta è stata influenzata dalla conoscenza di Ruby (più dettagli nell'articolo su Habr: I programmatori YML sognano di testare Ansible?) funzionava più velocemente, circa 40 minuti per 10 ruoli. Creavamo un insieme di macchine virtuali e all'interno eseguivamo i test.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

In generale, la soluzione funzionava, ma c'era un certo malessere a causa dell'eterogeneità. Quando abbiamo aumentato il numero di test di 13 ruoli di base e 2 meta-ruoli combinando ruoli più piccoli, i test sono impazziti, durando 70 minuti, quasi il doppio. Era difficile parlare di pratiche di XP (extreme programming) poiché nessuno vorrebbe aspettare 70 minuti. Questo ha portato a un cambiamento di approccio.

Giorno n° -601: Ansible e molecule

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Concettualmente è simile a testkitchen, solo che abbiamo trasferito il test dei ruoli in docker e cambiato stack. Di conseguenza, il tempo si è ridotto a stabili 20-25 minuti per 7 ruoli.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Aumentando il numero dei ruoli testati a 17 e il linting di 45 ruoli, siamo riusciti a eseguire tutto in 28 minuti su 2 jenkins slave.

Giorno n° 167: Aggiungiamo test Ansible al progetto

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Affrontare subito la refactoring del task, probabilmente non sarà possibile. Il task deve essere misurabile, in modo da poterlo suddividere in pezzi più piccoli e mangiare l'elefante a piccoli bocconi. È importante capire se si sta muovendosi nella giusta direzione e quanto lungo sarà il percorso.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

In generale, non è così importante come venga fatto, si possono scrivere appunti, attaccare post-it all'armadio, creare task in jira oppure utilizzare Google Docs per annotare lo stato attuale. Il punto è che il processo non è immediato, sarà lungo e noioso. È improbabile che qualcuno desideri che, durante il refactoring, tu possa esaurire le idee, stancarti e rinunciare.

Il refactoring è semplice:

  • Mangia.
  • Riposa.
  • Codifica.
  • Test IaC.
  • Ripeti.

E così continuiamo finché non raggiungiamo l'obiettivo.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Potrebbe non essere possibile iniziare a testare tutto subito, quindi il nostro primo compito è stato cominciare con il linting e il controllo della sintassi.

Giorno n. 181: Green Build Master

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Il linting è un piccolo primo passo verso il Green Build Master. Non romperà quasi nulla, ma aiuterà a perfezionare i processi e a ottenere build verdi in Jenkins. L'idea è di sviluppare abitudini nel team:

  • I test rossi sono un problema.
  • Se arrivi a correggere qualcosa, migliora anche il codice, rendendolo un po' migliore rispetto a com'era prima.

Giorno n. 193: Dal linting ai test unitari.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Stabilendo il processo di deployment del codice, si può avviare il processo di miglioramento graduale: sostituendo il linting con l'esecuzione dei ruoli, anche senza idempotenza. È fondamentale comprendere come applicare i ruoli e come funzionano.

Giorno n. 211: Dai test unitari ai test di integrazione

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Quando la maggior parte dei ruoli è coperta da test unitari e tutto è correttamente lintato, si può passare all'aggiunta dei test di integrazione. Ossia, testare non un singolo mattone dell'infrastruttura, ma le loro combinazioni, per esempio una configurazione completa di un'istanza.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Su Jenkins abbiamo generato molte fasi che lintano i ruoli/ playbook in parallelo, poi i test unitari nei container e alla fine i test di integrazione.

Jenkins + Docker + Ansible = Test

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

  1. Controlla il repo e genera le fasi di build.
  2. Esegui le fasi di linting dei playbook in parallelo.
  3. Esegui le fasi di linting dei ruoli in parallelo.
  4. Esegui le fasi di controllo della sintassi dei ruoli in parallelo.
  5. Esegui le fasi di test dei ruoli in parallelo.
    1. Lint del ruolo.
    2. Controlla le dipendenze dagli altri ruoli.
    3. Controlla la sintassi.
    4. Crea un'istanza Docker
    5. Esegui molecule/default/playbook.yml.
    6. Controlla l'idempotenza.
  6. Esegui i test di integrazione
  7. Fine

Giorno n. 271: Bus Factor

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Inizialmente, un piccolo gruppo di persone si occupava del refactoring. Effettuavano revisioni del codice nel master. Con il tempo, il team ha sviluppato competenze su come scrivere codice e le revisioni hanno contribuito alla diffusione delle conoscenze sull'infrastruttura e su come è strutturata. La peculiarità era che i revisori venivano selezionati a turno, secondo un calendario, cioè con una certa dose di probabilità si finiva per lavorare su una nuova area dell'infrastruttura.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

E qui deve essere comodo. Comodo fare revisioni, vedere in quale compito sono state effettuate, la cronologia delle discussioni. Abbiamo integrato jenkins + bitbucket + jira.

Ma la revisione di per sé non è una panacea. Ad un certo punto, è passato nel master un codice che ci ha causato test intermittenti:

- get_url:
    url: "{{ actk_certs }}/{{ item.1 }}"
    dest: "{{ actk_src_tmp }}/"
    username: "{{ actk_mvn_user }}"
    password: "{{ actk_mvn_pass }}"
  with_subelements:
    - "{{ actk_cert_list }}"
    - "{{ actk_certs }}"
  delegate_to: localhost

- copy:
    src: "{{ actk_src_tmp }}/{{ item.1 }}"
    dest: "{{ actk_dst_tmp }}"
  with_subelements:
    - "{{ actk_cert_list }}"
    - "{{ actk_certs }}"

Poi è stato corretto, ma è rimasto un retrogusto amaro.

get_url:
    url: "{{ actk_certs }}/{{ actk_item }}"
    dest: "{{ actk_src_tmp }}/{{ actk_item }}"
    username: "{{ actk_mvn_user }}"
    password: "{{ actk_mvn_pass }}"
  loop_control:
    loop_var: actk_item
  with_items: "{{ actk_cert_list }}"
  delegate_to: localhost

- copy:
    src: "{{ actk_src_tmp }}/{{ actk_item }}"
    dest: "{{ actk_dst_tmp }}"
  loop_control:
    loop_var: actk_item
  with_items: "{{ actk_cert_list }}"

Giorno n. 311: Acceleriamo i test

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Con il tempo i test sono aumentati, e i build rallentavano fino a un'ora in situazioni negative. Durante uno dei retro, c'era una frase del tipo "è bello avere test, ma sono lenti". Alla fine abbiamo abbandonato i test di integrazione su macchine virtuali e ci siamo adattati a Docker per velocizzare il processo. Abbiamo anche sostituito Testinfra con Ansible Verifier per ridurre il numero di strumenti utilizzati.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

A rigor di termini, qui sono state adottate una serie di misure:

  1. Passaggio a Docker.
  2. Eliminare il testing dei ruoli, che si duplicava a causa delle dipendenze.
  3. Aumentare il numero di slave.
  4. Ordine di esecuzione dei test.
  5. Possibilità di lintare TUTTO localmente con un solo comando.

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Alla fine, il pipeline su Jenkins è diventato unificato.

  1. Generare fasi di build.
  2. Lintare tutto in parallelo.
  3. Esegui le fasi di test dei ruoli in parallelo.
  4. Finito.

Lezioni apprese

Evitare variabili globali

Ansible utilizza variabili globali, esiste una parziale soluzione tramite private_role_vars, ma non è una panacea.

Farò un esempio. Supponiamo di avere role_a e role_b

# cat role_a/defaults/main.yml
---
msg: a

# cat role_a/tasks/main.yml
---
- debug:
    msg: role_a={{ msg }}

# cat role_b/defaults/main.yml
---
msg: b

# cat role_b/tasks/main.yml
---
- set_fact:
    msg: b
- debug:
    msg: role_b={{ msg }}

- hosts: localhost
  vars:
    msg: hello
  roles:
    - role: role_a
    - role: role_b
  tasks:
    - debug:
        msg: play={{msg}}

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

La cosa divertente è che il risultato di esecuzione dei playbook dipenderà da fattori non sempre evidenti, come l'ordine delle dichiarazioni delle role. Sfortunatamente, questo è nella natura di Ansible, e la cosa migliore che si può fare è utilizzare alcune convenzioni, come ad esempio utilizzare solo variabili definite all'interno della role.

BAD: utilizzare una variabile globale.

# cat roles/some_role/tasks/main.yml
---
debug:
  var: java_home

GOOD: In defaults definire le variabili necessarie e poi utilizzare solo quelle.

# cat roles/some_role/defaults/main.yml
---
r__java_home:
 "{{ java_home | default('/path') }}"

# cat roles/some_role/tasks/main.yml
---
debug:
  var: r__java_home

Prefix role variables

BAD: utilizzare una variabile globale.

# cat roles/some_role/defaults/main.yml
---
db_port: 5432

GOOD: Nella role, utilizzare variabili con un prefisso di nome della role rende più facile comprendere cosa sta succedendo guardando l'inventario.

# cat roles/some_role/defaults/main.yml
---
some_role__db_port: 5432

Use loop control variable

BAD: Utilizzare nella loops la variabile standard item, se questo task/playbook fosse incluso altrove, potrebbe portare a comportamenti imprevisti.

---
- hosts: localhost
  tasks:
    - debug:
        msg: "{{ item }}"
      loop:
        - item1
        - item2

GOOD: Ridefinire la variabile in un ciclo tramite loop_var.

---
- hosts: localhost
  tasks:
    - debug:
        msg: "{{ item_name }}"
      loop:
        - item1
        - item2
      loop_control:
        loop_var: item_name

Verifica le variabili di input

Abbiamo concordato di utilizzare i prefissi delle variabili; è utile verificare che siano definiti come ci si aspetta e, ad esempio, non siano stati sovrascritti con un valore vuoto.

GOOD: Controllare le variabili.

- name: "Verifica che le variabili di stringa richieste siano definite"
  assert:
    that: ahs_var is defined and ahs_var | length > 0 and ahs_var != None
    fail_msg: "{{ ahs_var }} deve essere impostata affinché il ruolo funzioni"
    success_msg: "Le variabili richieste {{ ahs_var }} sono definite"
  loop_control:
    loop_var: ahs_var
  with_items:
    - ahs_item1
    - ahs_item2
    - ahs_item3

Evitare i dizionari hash, utilizzare una struttura piatta.

Se il ruolo si aspetta un hash/dizionario in uno dei parametri, se vogliamo modificare uno dei parametri secondari, dovremo ridefinire l'intero hash/dizionario, il che aumenterà la complessità della configurazione.

BAD: Utilizzare hash/dizionario.

---
user:
  name: admin
  group: admin

GOOD: Utilizzare una struttura piatta per le variabili.

---
user_name: admin
user_group: "{{ user_name }}"

Crea playbook e ruoli idempotenti.

I ruoli e i playbook devono essere idempotenti poiché riducono la deriva della configurazione e il timore di rompere qualcosa. Tuttavia, se si utilizza Molecule, questo comportamento è predefinito.

Evitare l'uso dei moduli shell dei comandi.

L'uso del modulo shell porta a una descrizione imperativa, invece di quella dichiarativa, che è fondamentale per Ansible.

Testa i tuoi ruoli tramite Molecule.

Molecule è uno strumento piuttosto flessibile; vediamo alcuni scenari.

Molecule istanze multiple

In molecule.yml nella sezione piattaforme è possibile descrivere più host da distribuire.

---
    driver:
      name: docker
    platforms:
      - name: postgresql-instance
        hostname: postgresql-instance
        image: registry.example.com/postgres10:latest
        pre_build_image: true
        override_command: false
        network_mode: host
      - name: app-instance
        hostname: app-instance
        pre_build_image: true
        image: registry.example.com/docker_centos_ansible_tests
        network_mode: host

Di conseguenza, questi host possono essere poi usati in converge.yml utilizzare:

---
- name: Convergere tutto
  hosts: all
  vars:
    ansible_user: root
  roles:
    - role: some_role

- name: Convergere db
  hosts: db-instance
  roles:
    - role: some_db_role

- name: Convergere app
  hosts: app-instance
  roles:
    - role: some_app_role

Verificatore Ansible

In molecule c'è la possibilità di utilizzare ansible per verificare che l'istanza sia stata configurata correttamente; inoltre, questo è attivo di default dalla versione 3. Questo non è flessibile come testinfra/inspec, ma si possono verificare le aspettative relative al contenuto del file:

---
- name: Verifica
  hosts: all
  tasks:
    - name: copia config
      copy:
        src: expected_standalone.conf
        dest: /root/wildfly/bin/standalone.conf
        mode: "0644"
        owner: root
        group: root
      register: config_copy_result

    - name: Certifica che standalone.conf sia cambiato
      assert:
        that: not config_copy_result.changed

Oppure puoi avviare il servizio, attendere la sua disponibilità e effettuare un test di smoke:

---
  - name: Verifica
    hosts: solr
    tasks:
      - command: /blah/solr/bin/solr start -s /solr_home -p 8983 -force
      - uri:
          url: http://127.0.0.1:8983/solr
          method: GET
          status_code: 200
        register: uri_result
        until: uri_result is not failed
        retries: 12
        delay: 10
      - name: Invia documenti a solr
        command: /blah/solr/bin/post -c master /exampledocs/books.csv

Metti la logica complessa in moduli e plugin

Ansible adotta un approccio dichiarativo, quindi quando effettui ramificazioni nel codice, trasformazioni dei dati o utilizzi moduli shell, il codice diventa difficile da leggere. Per affrontare questa complessità e mantenerlo comprensibile, non è superfluo combattere contro di essa creando i propri moduli.

Riepiloga suggerimenti e trucchi

  1. Evita le variabili globali.
  2. Aggiungi un prefisso alle variabili di ruolo.
  3. Usa variabili di controllo del ciclo.
  4. Controlla le variabili di input.
  5. Evita le strutture dizionario hash, usa una struttura piatta.
  6. Crea playbook e ruoli idempotenti.
  7. Evita di usare moduli di shell per i comandi.
  8. Testa i tuoi ruoli tramite molecule.
  9. Metti la logica complessa in moduli e plugin.

Conclusione

Come iniziare a testare Ansible, rifattorizzare un progetto in un anno e non perdere la bussola.

Non è possibile semplicemente rifattorizzare l'infrastruttura di un progetto, anche se hai IaC. È un processo lungo che richiede pazienza, tempo e conoscenze.

UPD1 2020.05.01 20:30 — Per la profilazione iniziale dei playbook è possibile utilizzare callback_whitelist = profile_tasks per capire cosa sta impiegando più tempo. Dopodiché, esaminiamo la classica ottimizzazione di Ansible. Si può provare mitogen
UPD2 2020.05.03 16:34Versione in inglese

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