
Aquesta és la transcripció en :
A partir del segon commit, qualsevol codi es converteix en llegat, perquè les idees inicials comencen a divergir de la dura realitat. Això no és ni bo ni dolent, és un fet difícil de discutir i amb el qual s'ha de viure. Part d'aquest procés és la refactorització. Refactorització de la infraestructura com a codi. Que comenci la història sobre com refactoritzar Ansible en un any i no tornar-se boig.
El naixement del llegat
Dia #1: Pacient Zero

Hi havia una vegada un projecte condicional. Tenia un equip de desenvolupament de desenvolupament i enginyers d'operacions. Estaven resolent el mateix problema: com desplegar servidors i executar una aplicació. El problema era que cada equip resolia aquest problema a la seva manera. En el projecte, es va decidir utilitzar Ansible per sincronitzar el coneixement entre els equips de desenvolupament i operacions.
Dia #89: El naixement del llegat

Sense adonar-se'n ells mateixos, van voler fer-ho de la millor manera possible, però va resultar llegat. Com passa això?
- Tenim una tasca urgent aquí, fem un pirateig brut i després arreglem-ho.
- No cal escriure documentació i tot està clar què passa aquí.
- Conec Ansible/Python/Bash/Terraform! Mira com puc esquivar!
- Sóc un desenvolupador de Full Stack Overflow i ho vaig copiar de stackoverflow, no sé com funciona, però sembla genial i resol el problema.
Com a resultat, pots aconseguir un tipus de codi incomprensible del qual no hi ha documentació, no està clar què fa, si és necessari, però el problema és que cal desenvolupar-lo, modificar-lo, afegir crosses i suports. , empitjorant encara més la situació.
- hosts: localhost
tasks:
- shell: echo -n Z >> a.txt && cat a.txt
register: output
delay: 1
retries: 5
until: not output.stdout.find("ZZZ")Dia #109: Consciència del problema

El model IaC concebut i implementat inicialment ja no compleix els requisits dels usuaris/empresa/altres equips, i el temps per fer canvis a la infraestructura deixa de ser acceptable. En aquest moment, s'entén que és hora d'actuar.
Refactorització de IaC
Dia #139: realment necessites refactorització?

Abans d'apressar-vos a refactoritzar, heu de respondre una sèrie de preguntes importants:
- Per què necessites tot això?
- Tens temps?
- És suficient el coneixement?
Si no sabeu com respondre a les preguntes, aleshores la refactorització s'acabarà abans que comenci, o potser només empitjorarà. Perquè tenia experiència ( ), aleshores el projecte va rebre una sol·licitud d'ajuda per solucionar els rols i cobrir-los amb proves.
Dia #149: Preparant la refactorització

El primer és preparar. Decidiu què farem. Per fer-ho, ens comuniquem, busquem àrees problemàtiques i busquem maneres de resoldre'ls. Enregistrem els conceptes resultants d'alguna manera, per exemple un article en confluència, de manera que quan sorgeixi la pregunta "què és el millor?" o "Quin és correcte?" No hem perdut el camí. En el nostre cas, vam seguir la idea divideix i governa: dividim la infraestructura en petits trossos/maons. Aquest enfocament permet agafar una peça aïllada d'infraestructura, entendre què fa, cobrir-la amb proves i canviar-la sense por de trencar res.

Resulta que les proves d'infraestructura es converteixen en la pedra angular i aquí val la pena esmentar la piràmide de proves d'infraestructures. Exactament la mateixa idea que està en desenvolupament, però per a la infraestructura: estem passant de proves ràpides barates que comproven coses senzilles, com ara el sagnat, a proves cares i completes que despleguen tota la infraestructura.
Intents de prova Ansible
Abans d'anar a descriure com vam cobrir les proves d'Ansible al projecte, descriuré els intents i els enfocaments que vaig tenir l'oportunitat d'utilitzar anteriorment per entendre el context de les decisions preses.
Dia núm. -997: subministrament SDS

La primera vegada que vaig provar Ansible va ser en un projecte per desenvolupar SDS (Software Defined Storage). Hi ha un article separat sobre aquest tema
, però en resum, vam acabar amb una piràmide de proves invertida i vam passar entre 60 i 90 minuts en un paper, que és molt de temps. La base eren les proves e2e, és a dir. vam desplegar una instal·lació completa i després la vam provar. El que va ser encara més agreujant va ser la invenció de la seva pròpia bicicleta. Però he d'admetre que aquesta solució va funcionar i va permetre un llançament estable.
Dia # -701: Ansible i cuina de prova

El desenvolupament de la idea de proves Ansible va ser l'ús d'eines ja fetes, és a dir, prova cuina / cuina-ci i inspecció. L'elecció va ser determinada pel coneixement de Ruby (per a més detalls, vegeu l'article sobre Habré: ) va funcionar més ràpid, uns 40 minuts per a 10 papers. Vam crear un paquet de màquines virtuals i vam fer proves dins.

En general, la solució va funcionar, però hi havia una mica de sediment per heterogeneïtat. Quan el nombre de persones provades es va augmentar a 13 rols bàsics i 2 rols meta combinant rols més petits, de sobte les proves van començar a executar-se durant 70 minuts, que és gairebé 2 vegades més llarg. Era difícil parlar de pràctiques de XP (programació extrema) perquè... ningú vol esperar 70 minuts. Aquest va ser el motiu del canvi d'enfocament
Dia # -601: Ansible i molècula

Conceptualment, això és similar a testkitchen, només que vam traslladar les proves de rol a Docker i vam canviar la pila. Com a resultat, el temps es va reduir a uns 20-25 minuts estables per a 7 rols.

En augmentar el nombre de rols provats a 17 i amb 45 rols, ho vam executar en 28 minuts amb 2 esclaus Jenkins.
Dia #167: Afegint proves Ansible al projecte

Molt probablement, no serà possible fer la tasca de refactorització amb pressa. La tasca ha de ser mesurable perquè pugueu trencar-la en trossos petits i menjar l'elefant peça per peça amb una culleradeta. Hi ha d'haver una comprensió de si s'està movent en la direcció correcta, quant més temps queda per recórrer.

En general, no importa com es farà, pots escriure en un paper, pots posar adhesius a l'armari, pots crear tasques a Jira, o pots obrir Google Docs i anotar l'estat actual. allà. Les cames creixen pel fet que el procés no és immediat, serà llarg i tediós. És poc probable que algú vulgui que us esgoteu les idees, us canseu i us desbordeu durant la refactorització.
La refactorització és senzilla:
- Menjar.
- Somni.
- Codi.
- Prova IaC.
- Repetir
i ho repetim fins a arribar a l'objectiu previst.

És possible que no sigui possible començar a provar-ho tot immediatament, de manera que la nostra primera tasca va ser començar amb llisting i comprovar la sintaxi.
Dia #181: Mestre de construcció verda

Linting és un petit primer pas cap a Green Build Master. Això no trencarà gairebé res, però us permetrà depurar processos i fer construccions verdes a Jenkins. La idea és desenvolupar hàbits entre l'equip:
- Les proves vermelles són dolentes.
- Vaig venir a arreglar alguna cosa i, al mateix temps, fer el codi una mica millor del que era abans.
Dia #193: De la pelusa a les proves unitàries

Després d'haver creat el procés d'incorporació del codi al mestre, podeu començar el procés de millora pas a pas: substituint el filting per rols de llançament, fins i tot podeu fer-ho sense idempotència. Cal entendre com aplicar els rols i com funcionen.
Dia #211: De les proves unitàries a les proves d'integració

Quan la majoria de funcions es cobreixen amb proves unitàries i tot està enganxat, podeu passar a afegir proves d'integració. Aquells. provant no un sol maó a la infraestructura, sinó una combinació d'ells, per exemple, una configuració d'instància completa.

Mitjançant jenkins, vam generar moltes etapes que enfilaven rols/playbooks en paral·lel, després proves unitàries en contenidors i, finalment, proves d'integració.
Jenkins + Docker + Ansible = Proves

- Fes un repo de compra i genera etapes de construcció.
- Executeu les etapes del llibre de pelusa en paral·lel.
- Executeu les etapes de rol de pelusa en paral·lel.
- Executeu les etapes del rol de comprovació de sintaxi en paral·lel.
- Executeu fases de rol de prova en paral·lel.
- Paper de pelusa.
- Comproveu la dependència d'altres rols.
- Comproveu la sintaxi.
- Crea una instància de Docker
- Executeu molecule/default/playbook.yml.
- Comproveu la idempotència.
- Executar proves d'integració
- Finish
Dia #271: Bus Factor

Al principi, la refactorització la feia un petit grup de dues o tres persones. Van revisar el codi al màster. Amb el temps, l'equip va desenvolupar coneixements sobre com escriure codi i la revisió del codi va contribuir a la difusió del coneixement sobre la infraestructura i el seu funcionament. 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.

I aquí hauria de ser còmode. És convenient fer una revisió, veure en el marc de quina tasca es va fer i l'historial de les discussions. Hem integrat jenkins + bitbucket + jira.
Però, com a tal, una revisió no és una panacea, ens vam endinsar en el codi mestre, que ens va fer proves de fracàs:
- 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 }}"Després ho van arreglar, però el sediment va quedar.
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 }}"Dia #311: Acceleració de les proves

Amb el temps, hi va haver més proves, les compilacions van anar més lenta, fins a una hora en el pitjor dels casos. En un dels retros hi havia una frase com "està bé que hi hagi proves, però són lentes". Com a resultat, vam abandonar les proves d'integració a les màquines virtuals i les vam adaptar a Docker perquè fos més ràpid. També hem substituït testinfra per un verificador ansible per reduir el nombre d'eines utilitzades.

En sentit estricte, hi havia un conjunt de mesures:
- Canvia a Docker.
- Elimineu la prova de rol, que es duplica a causa de les dependències.
- Augmentar el nombre d'esclaus.
- Ordre d'execució de prova.
- Capacitat de deixar pelusa TOTS localment amb una comanda.

Com a resultat, Pipeline on jenkins també es va unificar
- Generar etapes de construcció.
- Pelusa tot en paral·lel.
- Executeu fases de rol de prova en paral·lel.
- Finalitza.
Lliçons apreses
Eviteu les variables globals
Ansible utilitza variables globals, hi ha una solució parcial al formulari , però això no és una panacea.
Permeteu-me que us posi un exemple. Deixa'ns tenir role_a и 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}}
El més curiós és que el resultat dels playbooks dependrà de coses que no sempre són evidents, com ara l'ordre en què s'enumeren els papers. Malauradament, aquesta és la naturalesa d'Ansible i el millor que es pot fer és utilitzar algun tipus d'acord, per exemple, dins d'un rol, utilitzar només la variable descrita en aquest rol.
BAD: utilitza una variable global.
# cat roles/some_role/tasks/main.yml
---
debug:
var: java_homeBONA: EN defaults definir les variables necessàries i després utilitzar-les només.
# 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
Prefixar variables de rol
BAD: utilitza una variable global.
# cat roles/some_role/defaults/main.yml
---
db_port: 5432BONA: En els rols per a variables, utilitzeu variables amb el prefix del nom de la funció, això, mirant l'inventari, facilitarà la comprensió del que està passant.
# cat roles/some_role/defaults/main.yml
---
some_role__db_port: 5432Utilitzeu la variable de control de bucle
BAD: Utilitzeu la variable estàndard en bucles item, si aquesta tasca o llibre de jocs s'inclou en algun lloc, això pot provocar un comportament inesperat
---
- hosts: localhost
tasks:
- debug:
msg: "{{ item }}"
loop:
- item1
- item2
BONA: Redefinir una variable en un bucle via loop_var.
---
- hosts: localhost
tasks:
- debug:
msg: "{{ item_name }}"
loop:
- item1
- item2
loop_control:
loop_var: item_name
Comproveu les variables d'entrada
Vam acceptar utilitzar prefixos variables no seria superflu comprovar que es defineixen com esperàvem i, per exemple, no s'han substituït per un valor buit;
BONA: Comprova les variables.
- name: "Verify that required string variables are defined"
assert:
that: ahs_var is defined and ahs_var | length > 0 and ahs_var != None
fail_msg: "{{ ahs_var }} needs to be set for the role to work "
success_msg: "Required variables {{ ahs_var }} is defined"
loop_control:
loop_var: ahs_var
with_items:
- ahs_item1
- ahs_item2
- ahs_item3Eviteu els diccionaris de hashes, utilitzeu una estructura plana
Si un rol espera un hash/diccionari en un dels seus paràmetres, aleshores si volem canviar un dels paràmetres secundaris, haurem d'anul·lar tot el hash/diccionari, la qual cosa augmentarà la complexitat de la configuració.
BAD: Utilitzeu hash/diccionari.
---
user:
name: admin
group: adminBONA: Utilitzeu una estructura variable plana.
---
user_name: admin
user_group: "{{ user_name }}"Crea llibres de joc i rols idempotents
Els rols i els llibres de joc han de ser idempotents, perquè redueix la deriva de la configuració i la por a trencar alguna cosa. Però si utilitzeu molècula, aquest és el comportament predeterminat.
Eviteu utilitzar mòduls de l'intèrpret d'ordres
L'ús d'un mòdul d'intèrpret d'ordres dóna com a resultat un paradigma de descripció imperatiu, en lloc d'un de declaratiu, que és el nucli d'Ansible.
Posa a prova els teus rols mitjançant molècules
La molècula és una cosa molt flexible, mirem alguns escenaris.
Molècula Múltiples instàncies
В molecule.yml a la secció platforms podeu descriure molts amfitrions que podeu implementar.
---
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: hostEn conseqüència, aquests amfitrions poden ser-ho converge.yml utilitzar:
---
- name: Converge all
hosts: all
vars:
ansible_user: root
roles:
- role: some_role
- name: Converge db
hosts: db-instance
roles:
- role: some_db_role
- name: Converge app
hosts: app-instance
roles:
- role: some_app_roleVerificador Ansible
A molecule és possible utilitzar ansible per comprovar que la instància s'ha configurat correctament, a més, aquesta és la predeterminada des de la versió 3. No és tan flexible com testinfra/inspec, però podem comprovar que el contingut del fitxer coincideix amb les nostres expectatives:
---
- name: Verify
hosts: all
tasks:
- name: copy config
copy:
src: expected_standalone.conf
dest: /root/wildfly/bin/standalone.conf
mode: "0644"
owner: root
group: root
register: config_copy_result
- name: Certify that standalone.conf changed
assert:
that: not config_copy_result.changedO implementeu el servei, espereu que estigui disponible i feu una prova de fum:
---
- name: Verify
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: Post documents to solr
command: /blah/solr/bin/post -c master /exampledocs/books.csvPosa lògica complexa en mòduls i connectors
Ansible defensa un enfocament declaratiu, de manera que quan feu ramificacions de codi, transformació de dades, mòduls de shell, el codi es fa difícil de llegir. Per combatre-ho i mantenir-ho senzill d'entendre, no seria superflu combatre aquesta complexitat creant els vostres propis mòduls.
Resum de consells i trucs
- Eviteu les variables globals.
- Prefixar variables de rol.
- Utilitzeu la variable de control de bucle.
- Comproveu les variables d'entrada.
- Eviteu els diccionaris de hashes, utilitzeu una estructura plana.
- Crea llibres de joc i rols idempotents.
- Eviteu utilitzar mòduls de l'intèrpret d'ordres.
- Posa a prova els teus rols mitjançant molècules.
- Posa lògica complexa en mòduls i connectors.
Conclusió

No podeu anar a refactoritzar la infraestructura en un projecte, encara que tingueu IaC. Aquest és un procés llarg que requereix paciència, temps i coneixement.
enllaços
- Diapositives
- Vídeo
UPD1 2020.05.01/20/30 XNUMX:XNUMX — Per a la creació de perfils principals de llibres de jugades que podeu utilitzar callback_whitelist = profile_tasks per entendre què funciona exactament durant molt de temps. Després passem . També pots provar
UPD2 2020.05.03/16/34 XNUMX:XNUMX -
Font: www.habr.com
