Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Approccio IaC (Infrastructure as Code) non consiste solo nel codice memorizzato nel repository, ma anche nelle persone e nei processi che circondano quel codice. È possibile riutilizzare approcci dallo sviluppo software nella gestione e descrizione dell'infrastruttura? Non sarebbe male tenere a mente questa idea mentre leggete l'articolo.

Versione italiana

Questa è la trascrizione del mio intervento in DevopsConf 2019-05-28.

Diapositive e video

Infrastruttura come cronologia bash

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Supponiamo che tu stia arrivando su un nuovo progetto, e ti dicono: «abbiamo Infrastructure as Code«.” In realtà risulta che Infrastruttura come cronologia bash oppure ad esempio Documentazione come cronologia bash. Questa è una situazione del tutto reale, ad esempio, un caso simile è stato descritto da Denis Lysenko nel suo intervento Come sostituire l'intera infrastruttura e ricominciare a dormire tranquilli, ha raccontato come dalla cronologia bash hanno ottenuto un'infrastruttura ben definita nel progetto.

Con un po' di volontà, si può dire che Infrastruttura come cronologia bash è come il codice:

  1. riproducibilità: puoi prendere la cronologia bash, eseguire i comandi da essa e, chissà, potresti ottenere una configurazione funzionante.
  2. versionamento: sai chi è entrato e cosa ha fatto, ma non è detto che questo ti porti a una configurazione funzionante.
  3. cronologia: storia di chi e cosa ha fatto. Tuttavia, non potrai utilizzarla se perdi il server.

Cosa fare allora?

Infrastructure as Code

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Anche un caso strano come Infrastruttura come cronologia bash può essere tirato per i capelli a Infrastructure as Code, ma quando vogliamo fare qualcosa di più complesso di un vecchio e caro server LAMP, arriveremo al punto in cui questo codice deve essere modificato, cambiato, perfezionato. Inoltre, vorremmo esaminare le analogie tra Infrastructure as Code e lo sviluppo software.

D.R.Y.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Nel progetto di sviluppo di sistemi di archiviazione dei dati, c'era un sotto-task di configurare periodicamente SDS: rilasciamo una nuova versione — deve essere distribuita per ulteriori test. L'operazione è estremamente semplice:

  • entra qui tramite ssh ed esegui il comando.
  • copia il file lì.
  • correggi la configurazione qui.
  • lancialo lì
  • PROFIT!

Per la logica descritta va più che bene bash, soprattutto nelle prime fasi del progetto, quando sta appena avviando. Non è male che tu usi bash, ma col passare del tempo emergono richieste per sviluppare qualcosa di simile, ma leggermente diverso. La prima cosa che viene in mente: copia e incolla. E così abbiamo già due script molto simili che fanno quasi la stessa cosa. Col tempo il numero di script è aumentato e ci siamo trovati di fronte al fatto che esiste una certa logica aziendale di distribuzione dell'installazione che deve essere sincronizzata tra diversi script, il che è abbastanza complicato.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Si scopre che esiste una pratica chiamata D.R.Y. (Don't Repeat Yourself). L'idea è quella di riutilizzare il codice esistente. Sembra semplice, ma non ci siamo arrivati subito. Nel nostro caso, è stata un'idea banale: separare i configuratori dagli script. Cioè, la logica aziendale di come viene distribuita l'installazione è separata, i configuratori sono separati.

S.O.L.I.D. per CFM

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Col passare del tempo, il progetto è cresciuto e la continuazione naturale è stata l'emergere di Ansible. La principale ragione della sua nascita è la presenza di competenze nel team e che bash non è progettato per logiche complesse. Ansible ha anche iniziato a contenere logiche complesse. Per evitare che logiche complesse si trasformino in caos, nella programmazione software esistono principi di organizzazione del codice S.O.L.I.D. Ad esempio, Grigory Petrov ha toccato nel suo discorso «Perché un IT manager ha bisogno di un brand personale» la questione che l'essere umano è costruito in modo tale che è più facile per lui operare con alcune entità sociali, e nella programmazione software questo significa oggetti. Se uniamo queste due idee e continuiamo a svilupparle, possiamo notare che anche nella descrizione dell'infrastruttura è possibile utilizzare S.O.L.I.D. per rendere più facile mantenere e modificare questa logica in futuro.

Il Principio della Responsabilità Unica

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Ogni classe svolge solo un compito.

Non bisogna mescolare il codice e creare mostri di spaghetti monolitici e divini. L'infrastruttura dovrebbe consistere in semplici mattoni. Si scopre che se si scomponesse un playbook di Ansible in pezzi più piccoli, leggere ruoli Ansible, sarebbe più facile mantenerli.

Il Principio di Apertura/Chiusura

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Principio di apertura/chiusura.

  • Aperto per estensioni: significa che il comportamento di un'entità può essere esteso creando nuovi tipi di entità.
  • Chiuso per modifiche: a seguito dell'estensione del comportamento di un'entità, non è necessario apportare modifiche al codice che utilizza queste entità.

Inizialmente abbiamo implementato l'infrastruttura di test su macchine virtuali, ma poiché la logica aziendale di distribuzione era separata dalla realizzazione, abbiamo facilmente aggiunto il deployment su bare metal.

Il Principio di Sostituzione di Liskov

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Il principio di sostituzione di Barbara Liskov. Gli oggetti nel programma devono poter essere sostituiti con istanze dei loro sottotipi senza alterare la correttezza dell'esecuzione del programma.

Se si guarda in modo più ampio, non è una peculiarità di un progetto specifico, ma qualcosa che può essere applicato in generale. S.O.L.I.D., riguarda in generale CFM; ad esempio, in un altro progetto è necessario distribuire un'applicazione Java standard sopra vari server Java, server di applicazioni, database, sistemi operativi, ecc. Su questo esempio esaminerò i principi successivi. S.O.L.I.D.

Nel nostro caso, all'interno del team infrastrutturale c'è un accordo che se abbiamo installato il ruolo imbjava o oraclejava, abbiamo un file binario eseguibile di java. Questo è necessario poiché i ruoli superiori dipendono da questo comportamento, si aspettano la presenza di java. Inoltre, questo ci consente di sostituire una realizzazione/versione di java con un'altra senza modificare la logica di distribuzione dell'applicazione.

Il problema qui risiede nel fatto che in Ansible non è possibile implementare ciò che porta al manifestarsi di alcune intese all'interno del team.

Il Principio di Segregazione delle Interfacce

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Il principio di segregazione delle interfacce: «molte interfacce, appositamente progettate per i client, sono migliori di un'unica interfaccia generica».

Inizialmente abbiamo provato a concentrare tutta la variabilità nella distribuzione dell'applicazione in un unico playbook di Ansible, ma è risultato difficile da mantenere; l'approccio in cui abbiamo specificato un'interfaccia esterna (il client si aspetta la porta 443) consente di assemblare l'infrastruttura per una realizzazione specifica a partire da mattoni separati.

Il Principio di Inversione delle Dipendenze

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Il principio di inversione delle dipendenze. I moduli di alto livello non devono dipendere dai moduli di basso livello. Entrambi i tipi di moduli devono dipendere dalle astrazioni. Le astrazioni non devono dipendere dai dettagli. I dettagli devono dipendere dalle astrazioni.

Questo esempio sarà basato su un antipattern.

  1. Uno dei clienti aveva un cloud privato.
  2. All'interno del cloud avevamo ordinato macchine virtuali.
  3. Ma a causa delle peculiarità del cloud, la distribuzione dell'applicazione era legata a quale hypervisor la VM fosse assegnata.

Cioè, la logica di alto livello per il deployment dell'applicazione e le dipendenze si sviluppava ai livelli sottostanti dell'iper-vistore, e questo significava problemi nel riutilizzare questa logica. Non è necessario.

Interazione

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

L'infrastruttura come codice non riguarda solo il codice, ma anche i rapporti tra codice e persona, e le interazioni tra gli sviluppatori dell'infrastruttura.

Bus factor

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Supponiamo che nel tuo progetto ci sia Vasia. Vasia sa tutto sulla tua infrastruttura, cosa succederà se Vasia dovesse scomparire? È una situazione molto reale, poiché potrebbe essere investito da un autobus. A volte succede. Se ciò accade e la conoscenza del codice, della sua struttura, di come funziona, di login e password non è distribuita nel team, si possono affrontare diverse situazioni sgradevoli. Per minimizzare questi rischi e distribuire la conoscenza all'interno del team, è possibile utilizzare vari approcci.

Devops in coppia

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Non è come nella barzelletta, dove gli admin bevono birra, cambiano le password, e è l'equivalente della programmazione in coppia. Cioè, due ingegneri si siedono davanti a un computer, una tastiera e iniziano insieme a configurare la tua infrastruttura: configurano il server, scrivono un ruolo Ansible, ecc. Sembra bello, ma non ha funzionato per noi. Tuttavia, ci sono stati casi specifici di questa pratica che hanno funzionato. Un nuovo dipendente, il suo mentore prende un compito reale con lui, lavora e trasferisce la conoscenza.

Un altro caso specifico è la chiamata di incidente. Durante un problema, si riunisce un gruppo di persone di guardia e coinvolte, viene nominato un moderatore che condivide il suo schermo e espone il proprio ragionamento. Gli altri partecipanti seguono il ragionamento del moderatore, cercano trucchi nella console, controllano se è stata trascurata qualche riga nel log, scoprono cose nuove sul sistema. Questo approccio ha funzionato più spesso di no.

Code Review

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Soggettivamente, la diffusione della conoscenza riguardo all'infrastruttura e al suo funzionamento è avvenuta in modo più efficace attraverso le code review:

  • L'infrastruttura è descritta da codice nel repository.
  • Le modifiche avvengono in un ramo separato.
  • Durante la richiesta di merge, è possibile vedere la delta delle modifiche all'infrastruttura.

Il punto di forza qui era che i revisori venivano scelti a turno, secondo un programma, quindi con una certa probabilità ti scontravi con una nuova parte dell'infrastruttura.

Stile del codice

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Col tempo sono iniziate a sorgere delle controversie durante le revisioni, poiché i revisori avevano stili diversi e la rotazione dei revisori li metteva a confronto con stili differenti: 2 spazi o 4, camelCase o snake_case. Non è stato facile implementare questo cambiamento.

  • La prima idea è stata quella di consigliare di utilizzare un linter, visto che sono ingegneri e intelligenti. Ma i diversi editor, i sistemi operativi non lo rendevano comodo.
  • Ciò si è evoluto in un bot che in caso di commit problematici scriveva su Slack e allegava l'output del linter. Ma nella maggior parte dei casi, si presentavano questioni più importanti e il codice rimaneva non corretto.

Green Build Master

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Il tempo passa e si è giunti alla conclusione che non si possono permettere commit nel master che non superano determinati test. Ecco! Abbiamo inventato il Green Build Master, già da tempo praticato nello sviluppo software:

  • Lo sviluppo avviene in un ramo separato.
  • In questo ramo vengono eseguiti i test.
  • Se i test non superano, il codice non entrerà nel master.

Accettare questa decisione è stata un'esperienza dolorosa, poiché ha generato molte discussioni, ma ne è valsa la pena, poiché le richieste di merge iniziarono a arrivare senza disaccordi di stile e nel tempo il numero di posti problematici è diminuito.

IaC Testing

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Oltre al controllo dello stile, si possono utilizzare anche altre cose, ad esempio verificare che la vostra infrastruttura possa effettivamente essere distribuita. O controllare che le modifiche all'infrastruttura non portino a perdite di denaro. Perché potrebbe servire? È una domanda complessa e filosofica, ma posso risponderti con una storia: c'era un auto-scaler in Powershell che non controllava le condizioni limite => si crearono più VM di quanto necessario => il cliente spese più soldi di quanto pianificato. Non è piacevole, ma questo errore sarebbe stato facilmente rilevabile in fasi preliminari.

Ci si potrebbe chiedere, perché complicare ulteriormente un'infrastruttura già complessa? I test per l'infrastruttura, così come per il codice, non riguardano la semplificazione, ma comprendere come dovrebbe funzionare la vostra infrastruttura.

IaC Testing Pyramid

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

IaC Testing: Static Analysis

Se si distribuisce subito l'intera infrastruttura e si verifica che funzioni, potrebbe rivelarsi un'operazione lunga e richiedere molto tempo. Pertanto, alla base ci dovrebbe essere qualcosa che funzioni rapidamente, ce n'è molto e copre molti aspetti primitiv.

Bash è complicato

Prendiamo un esempio semplice. scegliere tutti i file nella directory corrente e copiarli altrove. La prima cosa che viene in mente:

for i in * ; do 
    cp $i /some/path/$i.bak
done

E se ci sono spazi nel nome del file? Va bene, siamo intelligenti, sappiamo come usare le virgolette:

for i in * ; do cp "$i" "/some/path/$i.bak" ; done

Bravi? No! E se non ci fosse nulla nella directory, ovvero se il globbing non funziona.

find . -type f -exec mv -v {} dst/{}.bak ;

Adesso bravi? No… Ci siamo dimenticati che nel nome del file potrebbe esserci n.

touch x
mv x "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dir

Strumenti di analisi statica

Il problema del passaggio precedente potrebbe essere stato rilevato quando abbiamo dimenticato le virgolette, per questo ci sono molti strumenti disponibili Shellcheck, ce ne sono davvero molti, e probabilmente riuscirai a trovare un linter per il tuo stack nella tua IDE.

Linguaggio
Strumento

bash
Shellcheck

Ruby
RuboCop

python
Pylint

ansible
Ansible Lint

Testing IaC: Test unitari

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Come abbiamo visto nel precedente esempio, i linter non sono onnipotenti e non possono indicare tutti i punti problematici. In analogia con il testing nello sviluppo software, possiamo ricordare i test unitari. Qui ci vengono subito in mente shunit, junit, rspec, pytest. Ma cosa fare con ansible, chef, saltstack e simili?

Inizialmente abbiamo parlato di S.O.L.I.D. e del fatto che la nostra infrastruttura dovrebbe essere composta da piccoli mattoncini. È giunto il loro momento.

  1. L'infrastruttura si suddivide in piccoli mattoncini, ad esempio, ruoli Ansible.
  2. Viene creato un ambiente, sia esso docker o VM.
  3. Su questo ambiente di test applichiamo il nostro ruolo Ansible.
  4. Controlliamo che tutto abbia funzionato come previsto (eseguiamo i test).
  5. Decidiamo se va tutto bene o no.

Testing IaC: strumenti di test unitari

La domanda è, cosa sono i test per CFM? possiamo semplicemente eseguire uno script, oppure possiamo utilizzare soluzioni pronte per questo:

CFM
Strumento

Ansible
Testinfra

Chef
Inspec

Chef
Serverspec

saltstack
Goss

Esempio per testinfra, controlliamo che gli utenti test1, test2 esistano e facciano parte del gruppo sshusers:

def test_default_users(host):
    users = ['test1', 'test2']
    for login in users:
        assert host.user(login).exists
        assert 'sshusers' in host.user(login).groups

Cosa scegliere? la questione è complessa e non univoca, ecco un esempio di cambiamenti nei progetti su github dal 2018 al 2019:

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Framework di Testing IaC

Sorge quindi la questione di come mettere tutto insieme e farlo funzionare? Si può prendere e fare tutto da soli se si ha un numero sufficiente di ingegneri. Oppure si possono usare soluzioni pronte, anche se non ce ne sono molte:

CFM
Strumento

Ansible
Molecule

Chef
Test Kitchen

Terraform
Terratest

Esempio di cambiamento nei progetti su github dal 2018 al 2019:

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Molecule vs. Testkitchen

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Inizialmente abbiamo provato a usare testkitchen:

  1. Creare VM in parallelo.
  2. Applicare i ruoli Ansible.
  3. Eseguire inspec.

Per 25-35 ruoli ha impiegato 40-70 minuti, il che era lungo.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Il passo successivo è stato passare a Jenkins / Docker / Ansible / Molecule. Ideologicamente è tutto lo stesso.

  1. Lintare i playbook.
  2. Lintare i ruoli.
  3. Avviare il contenitore.
  4. Applicare i ruoli Ansible.
  5. Eseguire testinfra.
  6. Verificare l'idempotenza.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Il linting per 40 ruoli e i test per una dozzina hanno preso circa 15 minuti.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Cosa scegliere dipende da molti fattori, come lo stack utilizzato, la competenza del team, ecc. Qui ognuno decide da solo come affrontare la questione del testing unitario.

Testing IaC: Test di integrazione.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Nel prossimo livello della piramide di testing dell'infrastruttura si trovano i test di integrazione. Sono simili ai test unitari:

  1. L'infrastruttura è suddivisa in piccoli mattoncini, come i ruoli Ansible.
  2. Viene creato un ambiente, sia esso docker o VM.
  3. A questo ambiente di test si applicano numerose i ruoli Ansible.
  4. Verifichiamo che tutto abbia funzionato come ci si aspettava (eseguiamo i test).
  5. Decidiamo se va tutto bene o no.

In parole povere, non verifichiamo la funzionalità di un singolo elemento del sistema come nei test unitari, ma verifichiamo come il server è configurato nel suo complesso.

Testing IaC: Test End to End.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

In cima alla piramide ci sono i test End to End. Cioè, non verifichiamo la funzionalità di un singolo server, di un singolo script, di un singolo mattoncino della nostra infrastruttura. Verifichiamo che un insieme di server, uniti insieme, stia funzionando come ci aspettiamo. Sfortunatamente non ho mai visto soluzioni pronte all'uso, immagino perché l'infrastruttura è spesso unica e difficile da standardizzare per creare un framework di testing. Di conseguenza, tutti creano le proprie soluzioni. C'è richiesta, ma non ci sono risposte. Pertanto, racconterò cosa esiste, per stimolare altri a riflessioni sensate o per farmi dire che tutto è già stato inventato.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Un progetto con una lunga storia. Utilizzato in grandi organizzazioni e probabilmente ognuno di voi ha avuto indirettamente a che fare. L'applicazione supporta molte basi di dati, integrazioni ecc. La conoscenza di come può apparire l'infrastruttura è costituita da numerosi file docker-compose, e la conoscenza di quali test eseguire in quale ambiente è gestita da Jenkins.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Questo schema ha funzionato abbastanza a lungo, finché nel corso la ricerca non abbiamo provato a trasferirlo in Openshift. I contenitori sono rimasti gli stessi, ma l'ambiente di esecuzione è cambiato (ciao D.R.Y. di nuovo).

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Il pensiero della ricerca è andato oltre, e in openshift è stata trovata una cosa chiamata APB (Ansible Playbook Bundle), che consente di racchiudere nel container la conoscenza su come distribuire l'infrastruttura. Cioè, esiste un punto di conoscenza riproducibile e testabile su come distribuire l'infrastruttura.

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Tutto ciò suonava bene, finché non ci siamo imbattuti in un'infrastruttura eterogenea: per i test ci serviva Windows. Alla fine, la conoscenza su cosa distribuire, dove e come testare, risiede in jenkins.

Conclusione

Cosa ho imparato testando 200.000 righe di codice infrastrutturale

Infrastructure as Code è

  • Codice nel repository.
  • Interazione tra le persone.
  • Testare l'infrastruttura.

link

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