Què he après provant 200 línies de codi d'infraestructura
Enfocament IaC (Infraestructura com a codi) consisteix no només en el codi que s'emmagatzema al repositori, sinó també en les persones i processos que envolten aquest codi. És possible reutilitzar enfocaments des del desenvolupament de programari fins a la gestió i descripció de la infraestructura? Seria una bona idea tenir aquesta idea en ment mentre llegiu l'article.
Suposem que arribes a un nou projecte i et diuen: “tenim La infraestructura com a codi". En realitat resulta La infraestructura com a història de bash o per exemple Documentació com a historial de bash. Aquesta és una situació molt real, per exemple, un cas similar va ser descrit per Denis Lysenko en un discurs Com substituir tota la infraestructura i començar a dormir tranquil, va explicar com van aconseguir una infraestructura coherent per al projecte a partir de la història de bash.
Amb una mica de ganes, ho podem dir La infraestructura com a història de bash això és com el codi:
reproductibilitat: Podeu agafar l'historial de bash, executar les ordres des d'allà i, per cert, podeu obtenir una configuració de treball com a sortida.
versionar: ja sabeu qui va entrar i què van fer, de nou, no és un fet que això us porti a una configuració de treball a la sortida.
història: la història de qui va fer què. només que no el podràs utilitzar si perds el servidor.
Què fer?
La infraestructura com a codi
Fins i tot un cas tan estrany com La infraestructura com a història de bash pots tirar-lo per les orelles La infraestructura com a codi, però quan volem fer alguna cosa més complicada que el bon servidor LAMP vell, arribarem a la conclusió que aquest codi s'ha de modificar, canviar, millorar d'alguna manera. A continuació, ens agradaria considerar els paral·lelismes entre ells La infraestructura com a codi i desenvolupament de programari.
SEC
En un projecte de desenvolupament de sistemes d'emmagatzematge, hi havia una subtasca configurar SDS periòdicament: estem llançant una nova versió; s'ha de llançar per a més proves. La tasca és extremadament senzilla:
inicieu sessió aquí mitjançant ssh i executeu l'ordre.
copieu el fitxer allà.
corregeix la configuració aquí.
començar el servei allà
...
BENEFICI!
Per a la lògica descrita, bash és més que suficient, sobretot en les primeres etapes del projecte, quan tot just comença. Això no està malament que utilitzis bash, però amb el temps hi ha peticions per desplegar alguna cosa semblant, però lleugerament diferent. El primer que em ve al cap és copiar i enganxar. I ara ja tenim dos guions molt semblants que fan gairebé el mateix. Amb el temps, el nombre d'scripts va créixer, i ens vam trobar davant del fet que hi ha una certa lògica de negoci per desplegar una instal·lació que cal sincronitzar entre diferents scripts, això és força complicat.
Resulta que hi ha una pràctica com DRY (No et repeteixis). La idea és reutilitzar el codi existent. Sembla senzill, però no hi vam arribar de seguida. En el nostre cas, va ser una idea banal: separar les configuracions dels scripts. Aquells. lògica de negoci de com es desplega la instal·lació per separat, les configuracions per separat.
SOLID per a CFM
Amb el temps el projecte va anar creixent i continuació natural va ser l'aparició d'Ansible. El motiu principal de la seva aparició és que hi ha experiència a l'equip i que bash no està dissenyat per a una lògica complexa. Ansible també va començar a contenir una lògica complexa. Per evitar que la lògica complexa es converteixi en un caos, hi ha principis per organitzar el codi en el desenvolupament de programari SÒLID També, per exemple, Grigory Petrov a l'informe "Per què un especialista informàtic necessita una marca personal" va plantejar la qüestió que una persona està dissenyada de manera que li sigui més fàcil operar amb algunes entitats socials, en el desenvolupament de programari aquests són objectes. Si combinem aquestes dues idees i les seguim desenvolupant, ens adonarem que també podem utilitzar SÒLID per facilitar el manteniment i la modificació d'aquesta lògica en el futur.
El principi de responsabilitat única
Cada classe només realitza una tasca.
No cal barrejar codi i fer monstres d'espaguetis divins monolítics. La infraestructura hauria de consistir en maons simples. Resulta que si dividiu el llibre de jugades d'Ansible en trossos petits, llegiu els rols d'Ansible, llavors són més fàcils de mantenir.
El principi obert tancat
Principi obert/tancat.
Obert a l'extensió: significa que el comportament d'una entitat es pot ampliar mitjançant la creació de nous tipus d'entitat.
Tancat al canvi: com a resultat d'ampliar el comportament d'una entitat, no s'ha de fer cap canvi al codi que utilitza aquestes entitats.
Inicialment, vam desplegar la infraestructura de prova en màquines virtuals, però com que la lògica empresarial del desplegament era independent de la implementació, vam afegir el desplegament a baremetall sense cap problema.
El principi de substitució de Liskov
Principi de substitució de Barbara Liskov. els objectes d'un programa han de ser reemplaçables per instàncies dels seus subtipus sense canviar l'execució correcta del programa
Si ho mirem de manera més àmplia, no és una característica de cap projecte en concret que s'hi pugui aplicar SÒLID, generalment es tracta de CFM, per exemple, en un altre projecte cal desplegar una aplicació Java en caixa a sobre de diversos Java, servidors d'aplicacions, bases de dades, SO, etc. Utilitzant aquest exemple, consideraré més principis SÒLID
En el nostre cas, hi ha un acord dins de l'equip d'infraestructura que si hem instal·lat el rol imbjava o oraclejava, llavors tenim un executable binari java. Això és necessari perquè Els rols aigües amunt depenen d'aquest comportament; esperen java. Al mateix temps, això ens permet substituir una implementació/versió de Java per una altra sense canviar la lògica de desplegament de l'aplicació.
El problema aquí rau en el fet que és impossible implementar-ho a Ansible, com a conseqüència del qual apareixen alguns acords dins de l'equip.
El principi de segregació de la interfície
Principi de separació d'interfícies: "Moltes interfícies específiques del client són millors que una interfície de propòsit general.
Inicialment, vam intentar posar tota la variabilitat del desplegament d'aplicacions en un llibre de jugades d'Ansible, però va ser difícil de suportar, i l'enfocament quan teníem una interfície externa especificada (el client espera el port 443), llavors es pot muntar una infraestructura des d'individus. maons per a una implementació específica.
El principi d'inversió de dependència
El principi d'inversió de dependència. Els mòduls de nivells superiors no haurien de dependre dels mòduls de nivells inferiors. Tots dos tipus de mòduls han de dependre d'abstraccions. Les abstraccions no haurien de dependre dels detalls. Els detalls han de dependre de les abstraccions.
Aquí l'exemple es basarà en un antipatró.
Un dels clients tenia un núvol privat.
Vam demanar màquines virtuals dins del núvol.
Però a causa de la naturalesa del núvol, el desplegament d'aplicacions estava lligat a quin hipervisor estava activat la VM.
Aquells. La lògica de desplegament d'aplicacions d'alt nivell fluïa amb dependències als nivells inferiors de l'hipervisor, i això va suposar problemes a l'hora de reutilitzar aquesta lògica. No facis així.
Interacció
La infraestructura com a codi no es tracta només de codi, sinó també de la relació entre codi i persones, de les interaccions entre els desenvolupadors d'infraestructures.
Factor bus
Suposem que teniu Vasya al vostre projecte. Vasya ho sap tot sobre la teva infraestructura, què passarà si Vasya desapareix de sobte? Aquesta és una situació molt real, perquè podria ser atropellat per un autobús. De vegades passa. Si això passa i el coneixement sobre el codi, la seva estructura, el seu funcionament, les aparences i les contrasenyes no es distribueix entre l'equip, és possible que us trobeu amb una sèrie de situacions desagradables. Per minimitzar aquests riscos i distribuir el coneixement dins de l'equip, podeu utilitzar diversos enfocaments
Parella Devopsing
No és com com a broma, que els administradors van beure cervesa, van canviar les contrasenyes i un anàleg de la programació de parelles. Aquells. dos enginyers s'asseuen a un ordinador, un teclat i comencen a configurar la vostra infraestructura junts: configurar un servidor, escriure una funció Ansible, etc. Sona bé, però no ens ha funcionat. Però casos especials d'aquesta pràctica van funcionar. Arriba un nou empleat, el seu mentor assumeix una tasca real juntament amb ell, treballa i transfereix coneixement.
Un altre cas especial és una trucada d'incident. Durant un problema, un grup de persones de servei i implicats es reuneix, es designa un líder, que comparteix la seva pantalla i expressa el fil del pensament. Altres participants segueixen els pensaments del líder, espien trucs des de la consola, comproven que no s'han perdut cap línia al registre i aprenen coses noves sobre el sistema. Aquest enfocament funcionava més sovint que no.
Revisió del codi
Subjectivament, va ser més efectiu difondre el coneixement sobre la infraestructura i el seu funcionament mitjançant la revisió de codi:
La infraestructura es descriu mitjançant codi al repositori.
Els canvis es produeixen en una branca separada.
Durant una sol·licitud de fusió, podeu veure el delta de canvis a la infraestructura.
El més destacat aquí va ser que els revisors van ser seleccionats un per un, segons un calendari, és a dir. amb cert grau de probabilitat pujaràs a una nova peça d'infraestructura.
Estil de codi
Amb el temps, van començar a aparèixer baralles durant les revisions, perquè... els revisors tenien el seu propi estil i la rotació dels revisors els va apilar amb diferents estils: 2 espais o 4, camelCase o snake_case. No va ser possible implementar-ho immediatament.
La primera idea va ser recomanar l'ús de linter, després de tot, tothom és enginyer, tothom és intel·ligent. Però diferents editors, SO, no són convenients
Això es va convertir en un bot que va escriure a slack per a cada commit problemàtic i va adjuntar la sortida de linter. Però en la majoria dels casos hi havia coses més importants a fer i el codi no es va solucionar.
Mestre de construcció verda
El temps passa i hem arribat a la conclusió que els compromisos que no superen determinades proves no es poden admetre al màster. Voila! Hem inventat Green Build Master, que s'ha practicat en el desenvolupament de programari durant molt de temps:
El desenvolupament està en marxa en una branca separada.
S'estan executant proves en aquest fil.
Si les proves fracassen, el codi no passarà al mestre.
Prendre aquesta decisió va ser molt dolorós, perquè... va causar molta polèmica, però va valdre la pena, perquè... Les revisions van començar a rebre sol·licituds de fusions sense diferències d'estil, i amb el temps el nombre d'àrees problemàtiques va començar a disminuir.
Proves IaC
A més de la comprovació d'estil, podeu utilitzar altres coses, per exemple, per comprovar que la vostra infraestructura realment es pot implementar. O comproveu que els canvis en la infraestructura no comportaran pèrdua de diners. Per què pot ser necessari això? La pregunta és complexa i filosòfica, és millor respondre amb una història que d'alguna manera hi havia un auto-escalador a Powershell que no va comprovar les condicions de límit => es van crear més màquines virtuals del necessari => el client va gastar més diners del previst. Això no és molt agradable, però seria molt possible detectar aquest error en etapes anteriors.
Un es podria preguntar, per què fer que una infraestructura complexa sigui encara més complexa? Les proves per a la infraestructura, igual que per al codi, no es refereixen a la simplificació, sinó a saber com ha de funcionar la vostra infraestructura.
Piràmide de proves IaC
Proves IaC: anàlisi estàtica
Si desplegueu tota la infraestructura alhora i comproveu que funciona, és possible que trobeu que triga molt de temps i requereix molt de temps. Per tant, la base ha de ser quelcom que funcioni ràpidament, n'hi ha molt, i cobreix molts llocs primitius.
Bash és complicat
Vegem un exemple trivial. seleccioneu tots els fitxers del directori actual i copieu-los a una altra ubicació. El primer que em ve al cap:
for i in * ; do
cp $i /some/path/$i.bak
done
Què passa si hi ha un espai al nom del fitxer? Bé, d'acord, som intel·ligents, sabem com utilitzar cometes:
for i in * ; do cp "$i" "/some/path/$i.bak" ; done
Ben fet? No! Què passa si no hi ha res al directori, és a dir. globbing no funcionarà.
find . -type f -exec mv -v {} dst/{}.bak ;
Ben fet ara? No... He oblidat què hi pot haver al nom del fitxer n.
touch x
mv x "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dir
Eines d'anàlisi estàtica
El problema del pas anterior es podria detectar quan ens oblidem de les cometes, per a això hi ha molts remeis a la natura Shellcheck, en general n'hi ha molts, i el més probable és que trobeu un linter per a la vostra pila sota el vostre IDE.
Com hem vist a l'exemple anterior, els linters no són omnipotents i no poden assenyalar totes les àrees problemàtiques. A més, per analogia amb les proves en desenvolupament de programari, podem recordar proves unitàries. El que em ve de seguida al cap és shunit, junit, rspec, pitest. Però què fer amb ansible, xef, saltstack i altres com ells?
Al principi n'hem parlat SÒLID i que la nostra infraestructura hauria de constar de petits maons. Ha arribat el seu moment.
La infraestructura es divideix en petits maons, per exemple, rols Ansible.
Es desplega algun tipus d'entorn, ja sigui docker o VM.
Apliquem la nostra funció Ansible a aquest entorn de prova.
Comprovem que tot ha funcionat com esperàvem (fem proves).
Decidim bé o no bé.
IaC Testing: eines de prova unitària
Pregunta, què són les proves per a CFM? Simplement podeu executar l'script, o podeu utilitzar solucions ja fetes per a això:
Exemple per testinfra, comprovant que els usuaris test1, test2 existeixen i estan en un grup 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
Què triar? La pregunta és complexa i ambigua, aquí teniu un exemple de canvis en projectes a github per al 2018-2019:
Marcs de proves IaC
Sorgeix la pregunta: com posar-ho tot junt i llançar-lo? Llauna agafa-ho i fes-ho tu mateix si hi ha un nombre suficient d'enginyers. O podeu prendre solucions ja fetes, encara que no n'hi ha gaires:
Per a 25-35 papers va funcionar 40-70 minuts, que va ser llarg.
El següent pas va ser la transició a jenkins/docker/ansible/molecule. Idiològicament tot és igual
Llibres de jocs de pelusa.
Alineeu els rols.
Contenidor de llançament
Aplicar rols Ansible.
Executeu testinfra.
Comproveu la idempotència.
La realització de 40 papers i les proves per a una dotzena van començar a trigar uns 15 minuts.
Què triar depèn de molts factors, com ara la pila utilitzada, l'experiència de l'equip, etc. aquí cadascú decideix per si mateix com tancar la pregunta de la prova d'unitat
Testing IaC: proves d'integració
El següent pas a la piràmide de proves d'infraestructura seran les proves d'integració. Són semblants a les proves unitàries:
La infraestructura es divideix en petits maons, per exemple rols Ansible.
Es desplega algun tipus d'entorn, ja sigui docker o VM.
Per a aquest entorn de prova s'aplica Conjunt de Rols Ansibles.
Comprovem que tot ha funcionat com esperàvem (fem proves).
Decidim bé o no bé.
A grans trets, no comprovem el rendiment d'un element individual del sistema com en les proves unitàries, comprovem com està configurat el servidor en conjunt.
Proves IaC: proves extrem a extrem
A la part superior de la piràmide ens reben les proves End to End. Aquells. No comprovem el rendiment d'un servidor separat, d'un script separat o d'un maó separat de la nostra infraestructura. Comprovem que molts servidors connectats entre si, la nostra infraestructura funciona com esperem. Malauradament, no he vist mai solucions ja fetes en caixa, probablement perquè... La infraestructura sovint és única i difícil de modelar i crear un marc per a la prova. Com a resultat, cadascú crea les seves pròpies solucions. Hi ha una demanda, però no hi ha resposta. Per tant, us diré què hi ha per empènyer els altres a pensar o fregar-me el nas pel fet que tot es va inventar fa molt abans que nosaltres.
Un projecte amb una rica història. S'utilitza en grans organitzacions i probablement cadascun de vosaltres s'hi ha creuat indirectament. L'aplicació admet moltes bases de dades, integracions, etc. Saber com podria semblar la infraestructura és un munt de fitxers docker-compose i saber quines proves s'executa en quin entorn és Jenkins.
Aquest esquema va funcionar durant força temps, fins a dins del marc investigació no hem intentat transferir-ho a Openshift. Els contenidors segueixen sent els mateixos, però l'entorn de llançament ha canviat (hola DRY de nou).
La idea d'investigació va anar més enllà, i en el torn obert van trobar una cosa com APB (Ansible Playbook Bundle), que us permet empaquetar coneixements sobre com desplegar la infraestructura en un contenidor. Aquells. hi ha un punt de coneixement repetible i provable sobre com desplegar la infraestructura.
Tot això va sonar bé fins que ens vam trobar amb una infraestructura heterogènia: necessitàvem Windows per a les proves. Com a resultat, el coneixement de què, on, com implementar i provar està a jenkins.