
Approccio IaC (Infrastructure as Code) non consiste solo nel codice archiviato nel repository, ma anche nelle persone e nei processi che circondano quel codice. È possibile riutilizzare gli approcci dello sviluppo software nella gestione e nella descrizione dell'infrastruttura? Tenere a mente questa idea mentre leggete l'articolo non farebbe male.
Questa è la registrazione del mio con .
Diapositive e video
- Dry run 2019-04-24
Infrastructure as bash history

Immaginate di arrivare in un nuovo progetto e che vi dicono: “da noi Infrastructure as Code“. In realtà, si scopre che Infrastructure as bash history oppure ad esempio Documentation as bash history. Questa è una situazione del tutto reale, come descritto da Denis Lysenko nel suo intervento , ha raccontato come dalla bash history siano riusciti a ottenere una solida infrastruttura nel progetto.
Con un po' di volontà, si può dire che Infrastructure as bash history è come il codice:
- riproducibilità: puoi prendere la bash history, eseguire i comandi da lì e, a proposito, potresti ottenere una configurazione funzionante in uscita.
- versionamento: sai chi chi è entrato e cosa ha fatto, comunque non è sicuro che questo ti porti a una configurazione funzionante.
- storia: una cronologia di chi ha fatto cosa. ma non potrai usarla se perdi il server.
Cosa fare?
Infrastructure as Code

Persino un caso così strano come Infrastructure as bash history può essere forzato a Infrastructure as Code, ma quando vorrà fare qualcosa di più complesso di un vecchio e fidato server LAMP, arriveremo al punto in cui questo codice deve essere modificato, cambiato, migliorato. Inoltre, vorremmo esaminare le somiglianze tra Infrastructure as Code e lo sviluppo software.
D.R.Y.

Nel progetto per lo sviluppo di un sistema di archiviazione, c'era un sotto-compito : stiamo rilasciando una nuova versione — deve essere distribuita per ulteriori test. Il compito è estremamente semplice:
- collegati qui via ssh e esegui il comando.
- copia il file lì.
- qui modifica il config.
- lì avvia il servizio
- …
- PROFIT!
Per la logica descritta, bash è più che sufficiente, soprattutto nelle fasi iniziali del progetto, quando sta appena iniziando. Non è male che tu stia usando bash. , ma col passare del tempo emergono richieste per espandere qualcosa di simile, ma leggermente diverso. La prima cosa che viene in mente: copia e incolla. E ora 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 a una certa logica di business per il dispiegamento delle installazioni che deve essere sincronizzata tra gli script diversi, il che è piuttosto complesso.

Si scopre che esiste una pratica denominata D.R.Y. (Do not Repeat Yourself). L'idea è di riutilizzare il codice esistente. Sembra semplice, ma non ci siamo arrivati subito. Nel nostro caso è stata una semplice idea: separare le configurazioni dagli script. Cioè, la logica di business di come avviene il dispiegamento delle installazioni è separata, le configurazioni sono separate.
S.O.L.I.D. per CFM

Col passare del tempo il progetto è cresciuto e è stata l'emergere di Ansible. La principale ragione della sua nascita è la presenza di competenze nel team e che bash non è adatto per logiche complesse. Ansible ha cominciato a contenere logiche complesse. Affinché la logica complessa non si trasformasse in caos, nello sviluppo software esistono principi di organizzazione del codice. S.O.L.I.D. Ad esempio, Grigorij Petrov nel suo rapporto "Perché un IT manager ha bisogno di un marchio personale" ha sollevato la questione del fatto che gli esseri umani sono strutturati in modo tale da operare più facilmente con entità sociali, che nel contesto dello sviluppo software si traducono in 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 in futuro mantenere e modificare questa logica.
Il Principio di Responsabilità Singola

Ogni classe ha un solo compito.
Non è necessario mescolare il codice e creare mostri di pasta divina monolitici. L'infrastruttura dovrebbe essere costituita da semplici mattoni. Si scopre che se si suddivide un playbook di Ansible in piccole parti, leggasi ruoli di Ansible, è più facile mantenerli.
Il Principio di Apertura e Chiusura

Principio di apertura/chiusura.
- Aperto per estensione: significa che il comportamento di un'entità può essere esteso creando nuovi tipi di entità.
- Chiuso per modifica: di conseguenza, a seguito dell'estensione del comportamento di un'entità, non dovrebbero essere apportate modifiche al codice che utilizza tali entità.
Inizialmente abbiamo distribuito l'infrastruttura di test su macchine virtuali, ma poiché la logica aziendale di distribuzione era separata dall'implementazione, siamo stati in grado di aggiungere senza problemi il deployment su baremetal.
Il Principio di Sostituzione di Liskov

Il principio di sostituzione di Barbara Liskov afferma che gli oggetti in un programma devono essere sostituibili con istanze dei loro sottotipi senza modificare la correttezza dell'esecuzione del programma.
Se si guarda più in dettaglio, non è una caratteristica di un progetto specifico, ma qualcosa che può essere applicato in generale. S.O.L.I.D., in effetti riguarda CFM; ad esempio, in un altro progetto è necessario distribuire un'applicazione Java standard su vari server Java, server applicazioni, database, OS, ecc. In questo esempio esaminerò ulteriori principi. S.O.L.I.D.
Nel nostro caso, all'interno del team infrastrutturale, c'è un accordo che se installiamo il ruolo imbjava o oraclejava, abbiamo un file eseguibile binario java. Questo è necessario poiché i ruoli superiori dipendono da questo comportamento, si aspettano la presenza di java. Allo stesso tempo, questo ci permette di sostituire un'implementazione/versione di java con un'altra senza cambiare la logica di distribuzione dell'applicazione.
Il problema qui sta nel fatto che in Ansible non è possibile implementare simili deduzioni, per cui nella squadra emergono alcune intese.
Il principio di separazione delle interfacce

Il principio di separazione delle interfacce: "molte interfacce specificamente progettate per i clienti sono migliori di un'unica interfaccia generica".
Inizialmente abbiamo provato a concentrare tutta la variabilità di distribuzione dell'applicazione in un unico playbook di Ansible, ma era difficile da mantenere, mentre l'approccio in cui abbiamo specificato l'interfaccia esterna (il cliente si aspetta la porta 443) consente di comporre l'infrastruttura da singoli mattoni per la specifica implementazione.
Il principio di inversione delle dipendenze

Il principio di inversione delle dipendenze: i moduli di livello superiore non dovrebbero dipendere dai moduli di livello inferiore. Entrambi i tipi di moduli dovrebbero dipendere da astrazioni. Le astrazioni non dovrebbero dipendere dai dettagli. I dettagli devono dipendere dalle astrazioni.
In questo caso, l'esempio sarà basato su un antipattern.
- Uno dei nostri clienti aveva un cloud privato.
- All'interno del cloud, ordinavamo macchine virtuali.
- Ma a causa delle peculiarità del cloud, la distribuzione dell'applicazione era legata al tipo di hypervisor su cui si trovava la VM.
Cioè, la logica di alto livello per il deployment dell'applicazione, con le sue dipendenze, scende ai livelli sottostanti del hypervisor, e questo crea problemi nel riutilizzo di tale logica. Non farlo.
Interazione

L'infrastruttura come codice non riguarda solo il codice, ma anche le relazioni tra il codice e l'uomo, le interazioni tra gli sviluppatori dell'infrastruttura.
Fattore bus

Immagina di avere un progetto con Vasya. Vasya sa tutto sulla tua infrastruttura; cosa succede se Vasya improvvisamente scompare? Questa è una situazione molto reale, poiché potrebbe essere investito da un autobus. A volte succede. Se accade e la conoscenza del codice, della sua struttura, di come funziona, degli accessi e delle password non è distribuita all'interno del team, si possono affrontare una serie di situazioni spiacevoli. Per minimizzare questi rischi e distribuire la conoscenza nel team, si possono utilizzare diversi approcci.
DevOps in coppia

Non è come , che gli amministratori bevevano birra, cambiavano le password, e l'analogo della programmazione in coppia. Ovvero, due ingegneri si siedono a un computer, una tastiera e iniziano a configurare insieme la vostra infrastruttura: configurare il server, scrivere il ruolo Ansible, ecc. Suona bene, ma a noi non ha funzionato. Tuttavia, alcuni casi specifici di questa pratica hanno avuto successo. Quando è arrivato un nuovo dipendente, il suo mentore prende un compito reale e lavora con lui, trasferendo sapere.
Un altro caso specifico è la chiamata per incidenti. Durante un problema, si riunisce un gruppo di guardia e persone coinvolte, e viene nominato un leader che condivide il suo schermo e comunica il suo ragionamento. Gli altri partecipanti seguono il pensiero del leader, sbirciando trucchi dalla console, controllando se non ha saltato righe nei log e apprendendo cose nuove sul sistema. Questo approccio ha funzionato più che non.
Code Review

Soggettivamente, la diffusione delle conoscenze sull'infrastruttura e su come è strutturata è avvenuta in modo più efficace tramite le revisioni del codice:
- L'infrastruttura è descritta nel 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 forte era che i revisori venivano scelti a turno, secondo un programma, quindi con una certa probabilità avresti potuto esplorare una nuova parte dell'infrastruttura.
Stile di Codice

Col tempo, sono iniziate a sorgere delle liti durante le revisioni, poiché ogni revisore aveva il proprio stile e la rotazione dei revisori mischiava stili diversi: 2 spazi o 4, camelCase o snake_case. Non è stato facile implementare questa cosa.
- L'idea iniziale era di consigliare di utilizzare un linter, perché alla fine sono tutti ingegneri e intelligenti. Ma diversi editor, sistemi operativi, era scomodo.
- Questo si è evoluto in un bot che avvisava ogni volta che c'era un commit problematico in Slack, allegando l'output del linter. Ma nella maggior parte dei casi c'erano questioni più importanti e il codice rimaneva non corretto.
Green Build Master

Col tempo, siamo arrivati alla conclusione che non era possibile permettere commit in master che non passavano determinati test. Ecco! Abbiamo inventato il Green Build Master, che è già ampiamente praticato nello sviluppo software:
- Lo sviluppo avviene in un ramo separato.
- Su questo ramo vengono eseguiti i test.
- Se i test falliscono, il codice non entrerà nel master.
Prendere questa decisione è stato piuttosto doloroso, poiché ha sollevato molte controversie, ma ne è valsa la pena, poiché le richieste di fusione per la revisione sono iniziate a essere presentate senza disaccordi sullo stile e, nel tempo, il numero di punti problematici ha cominciato a diminuire.
Testing IaC

Oltre a controllare lo stile, si possono utilizzare anche altre cose, come verificare che la vostra infrastruttura possa effettivamente essere implementata. Oppure controllare che le modifiche all'infrastruttura non comportino perdite economiche. Perché potrebbe essere necessario? La domanda è complessa e filosofica; si può rispondere meglio con un aneddoto: c'era una volta un auto-scaler su Powershell che, non controllando le condizioni limite, creò più VM di quante ce ne volessero, e il cliente spese più denaro di quanto avesse programmato. Non è piacevole, ma questo errore avrebbe potuto essere catturato nelle fasi precedenti.
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 la consapevolezza di come deve funzionare la vostra infrastruttura.
Piramide di Testing IaC

Testing IaC: Analisi Statica
Se si decide di implementare subito tutta l'infrastruttura e verificare che funzioni, potrebbe rivelarsi molto dispendioso in termini di tempo. Per questo motivo, è essenziale avere qualcosa che funzioni in modo rapido, in grande quantità e che copra molte aree critiche.
Bash è complesso.
Ecco un esempio banale: selezionare tutti i file nella directory corrente e copiarli in un'altra posizione. La prima cosa che ci viene in mente è:
for i in * ; do
cp $i /some/path/$i.bak
doneE se il nome del file contiene uno spazio? Va bene, siamo intelligenti, sappiamo usare le virgolette:
for i in * ; do cp "$i" "/some/path/$i.bak" ; doneBravi? No! E se nella directory non ci fosse niente, cioè il globbing non funziona.
find . -type f -exec mv -v {} dst/{}.bak ;Ora siete bravi? No… Abbiamo dimenticato 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-dirStrumenti di analisi statica
Il problema del passo precedente sarebbe stato rilevato quando abbiamo dimenticato le virgolette; a questo scopo esistono numerosi strumenti. , ce ne sono molti, e probabilmente riuscirete a trovare un linter per il vostro stack nella vostra IDE.
Lingua
Strumento
bash
Ruby
python
ansible
Testing IaC: Test Unitari

Come abbiamo visto nell'esempio precedente, i linter non sono onnipotenti e non possono individuare tutti i problemi. A questo punto, in analogia con il testing nello sviluppo software, possiamo ricordare i test unitari. Qui ci viene subito in mente , , , . Ma cosa fare con ansible, chef, saltstack e simili?
All'inizio abbiamo parlato di S.O.L.I.D. e di come la nostra infrastruttura dovrebbe consistere in piccoli mattoni. È arrivato il loro momento.
- L'infrastruttura si frammenta in piccoli mattoni, ad esempio, ruoli di Ansible.
- Un certo ambiente viene implementato, che sia docker o una VM.
- Su questo ambiente di test applichiamo il nostro ruolo Ansible.
- Verifichiamo che tutto funzioni come ci aspettiamo (eseguiamo i test).
- Decidiamo se va bene o meno.
IaC Testing: strumenti per test unitari
La domanda è: cosa sono i test per CFM? possiam semplicemente eseguire uno script, oppure possiamo utilizzare soluzioni pronte per questo:
CFM
Strumento
Ansible
Chef
Chef
saltstack
Esempio per testinfra, verifichiamo che gli utenti test1, test2 esistano e appartengano al 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).groupsCosa scegliere? È una domanda complessa e non univoca; ecco un esempio di cambiamenti nei progetti su GitHub per il periodo 2018-2019:

Framework di test IaC
Come mettere tutto insieme e avviarlo? Si può se si ha un numero sufficiente di ingegneri. Oppure si possono adottare soluzioni pronte, anche se non ce ne sono molte:
CFM
Strumento
Ansible
Chef
Terraform
Esempio di cambiamenti nei progetti su GitHub per il periodo 2018-2019:

Molecule vs. Testkitchen

All'inizio abbiamo :
- Creare una VM in parallelo.
- Applicare i ruoli Ansible.
- Eseguire inspec.
Per 25-35 ruoli, questo impiegava 40-70 minuti, il che era lungo.

Il passo successivo è stato passare a Jenkins / Docker / Ansible / Molecule. Ideologicamente è tutto lo stesso.
- Lintare i playbook.
- Lintare i ruoli.
- Avviare il contenitore
- Applicare i ruoli Ansible.
- Eseguire testinfra.
- Verificare l'idempotenza.

Lintare per 40 ruoli e testare per una decina ora richiede circa 15 minuti.

La scelta dipende da molti fattori, come lo stack utilizzato, l'expertise del team ecc. Qui ognuno decide come affrontare la questione del testing unitario.
Testing IaC: Test di integrazione

Nella prossima fase della piramide di testing dell'infrastruttura, appariranno i test di integrazione. Sono simili ai test unitari:
- L'infrastruttura è suddivisa in piccoli mattoni, come i ruoli di Ansible.
- Un certo ambiente viene implementato, che sia docker o una VM.
- Questo ambiente di test applica molti ruoli di Ansible.
- Controlliamo che tutto funzioni come ci aspettiamo (eseguiamo test).
- Decidiamo se va bene o meno.
In poche parole, non verifichiamo il funzionamento di un singolo elemento del sistema come nei test unitari, ma controlliamo come è configurato il server nel suo complesso.
IaC Testing: Test End-to-End

In cima alla piramide ci attendono i test End-to-End. Cioè, non verifichiamo il funzionamento di un singolo server, di uno specifico script, o di un singolo mattone della nostra infrastruttura. Controlliamo che molti server, uniti insieme, funzionino come ci aspettiamo. Sfortunatamente, non ho mai visto soluzioni pronte all'uso, probabilmente perché l'infrastruttura è spesso unica e difficile da standardizzare e creare un framework per il suo testing. Come risultato, ognuno crea le proprie soluzioni. C'è domanda, ma non ci sono risposte. Pertanto, condividerò ciò che ho, affinché altri possano avere idee sensate o mi possono indicare che tutto è già stato inventato da tempo.

Un progetto con una storia ricca. Viene utilizzato in grandi organizzazioni e probabilmente ognuno di voi è venuto a contatto con esso in un modo o nell'altro. L'applicazione supporta molteplici database, integrazioni, ecc. La conoscenza di come può apparire l'infrastruttura è rappresentata da vari file docker-compose, mentre sapere quali test eseguire in quale ambiente è compito di Jenkins.

Questo schema ha funzionato per un lungo periodo, fino a quando nell'ambito non abbiamo provato a trasferirlo in Openshift. I container sono rimasti gli stessi, mentre l'ambiente di esecuzione è cambiato (salve D.R.Y. di nuovo).

Il pensiero della ricerca è andato oltre, e in Openshift abbiamo trovato qualcosa chiamato APB (Ansible Playbook Bundle), che consente di impacchettare la conoscenza su come distribuire l'infrastruttura in un container. Cioè, c'è un punto conoscitivo riproducibile e testabile su come distribuire l'infrastruttura.

Tutto ciò suonava bene, finché non ci siamo imbattuti in un'infrastruttura eterogenea: per i test abbiamo bisogno di Windows. Alla fine, la conoscenza su cosa, dove e come distribuire e testare è rimasta in Jenkins.
Conclusione

Infrastructure as Code è
- Codice nel repository.
- Interazione tra persone.
- Test dell'infrastruttura.
link
- Dry run 2019-04-24
- &
Fonte: habr.com
