A partir de la segunda confirmación, cualquier código se vuelve heredado, porque Las ideas iniciales comienzan a alejarse de la dura realidad. Esto no es ni bueno ni malo, es un hecho difícil de discutir y con el que hay que vivir. Parte de este proceso es la refactorización. Refactorización de infraestructura como código. Que comience la historia sobre cómo refactorizar Ansible en un año y no volverse loco.
El nacimiento del legado
Día #1: Paciente Cero
Érase una vez un proyecto condicional. Tenía un equipo de desarrollo de desarrollo e ingenieros de operaciones. Estaban resolviendo el mismo problema: cómo implementar servidores y ejecutar una aplicación. El problema fue que cada equipo resolvió este problema a su manera. En el proyecto, se decidió utilizar Ansible para sincronizar el conocimiento entre los equipos de desarrollo y operaciones.
Día #89: El nacimiento del legado
Sin darse cuenta, quisieron hacerlo lo mejor posible, pero resultó ser un legado. ¿Como sucedió esto?
Tenemos una tarea urgente aquí, hagamos un truco sucio y luego solucionémoslo.
No es necesario escribir documentación y todo está claro lo que está pasando aquí.
Soy un desarrollador de Full Stack Overflow y copié esto de stackoverflow. No sé cómo funciona, pero se ve bien y resuelve el problema.
Como resultado, puede obtener un tipo de código incomprensible para el cual no hay documentación, no está claro qué hace, si es necesario, pero el problema es que necesita desarrollarlo, modificarlo, agregarle muletas y soportes. , empeorando aún más la situación.
El modelo IaC inicialmente concebido e implementado ya no cumple con los requisitos de los usuarios/negocios/otros equipos, y el tiempo para realizar cambios en la infraestructura deja de ser aceptable. En este momento, llega el entendimiento de que es hora de actuar.
refactorización de IaC
Día #139: ¿Realmente necesitas refactorizar?
Antes de apresurarse a refactorizar, debe responder una serie de preguntas importantes:
¿Por qué necesitas todo esto?
¿Tienes tiempo?
¿Es suficiente el conocimiento?
Si no sabe cómo responder las preguntas, entonces la refactorización terminará incluso antes de comenzar, o puede que empeore. Porque tenido experiencia ( Lo que aprendí al probar 200 líneas de código de infraestructura), luego el proyecto recibió una solicitud de ayuda para arreglar los roles y cubrirlos con pruebas.
Día #149: Preparando la refactorización
Lo primero es prepararse. Decidir qué haremos. Para ello, nos comunicamos, encontramos áreas problemáticas y encontramos formas de resolverlas. Registramos los conceptos resultantes de alguna manera, por ejemplo un artículo en confluencia, para que cuando surja la pregunta “¿qué es mejor?” o "¿cuál es correcto?" No hemos perdido el rumbo. En nuestro caso, nos atenemos a la idea. divide y vencerás: dividimos la infraestructura en pequeños pedazos/ladrillos. Este enfoque le permite tomar una pieza aislada de infraestructura, comprender qué hace, cubrirla con pruebas y cambiarla sin temor a romper nada.
Resulta que las pruebas de infraestructura se convierten en la piedra angular y aquí vale la pena mencionar la pirámide de pruebas de infraestructura. Exactamente la misma idea que está en desarrollo, pero para la infraestructura: estamos pasando de pruebas rápidas y baratas que verifican cosas simples, como la sangría, a pruebas costosas y completas que implementan toda la infraestructura.
Intentos de prueba ansibles
Antes de pasar a describir cómo cubrimos las pruebas de Ansible en el proyecto, describiré los intentos y enfoques que tuve la oportunidad de utilizar anteriormente para comprender el contexto de las decisiones tomadas.
Día No. -997: Provisión de SDS
La primera vez que probé Ansible fue en un proyecto para desarrollar SDS (almacenamiento definido por software). Hay un artículo separado sobre este tema. Cómo romper bicicletas sobre muletas al probar tu distribución, pero en resumen, terminamos con una pirámide de pruebas invertida y en las pruebas dedicamos entre 60 y 90 minutos a un rol, lo cual es mucho tiempo. La base fueron las pruebas e2e, es decir. Implementamos una instalación completa y luego la probamos. Lo que fue aún más irritante fue la invención de su propia bicicleta. Pero debo admitir que esta solución funcionó y permitió una versión estable.
Día # -701: Cocina Ansible y de prueba
El desarrollo de la idea de prueba de Ansible fue el uso de herramientas listas para usar, a saber, test kitchen / kitchen-ci e inspec. La elección estuvo determinada por el conocimiento de Ruby (para más detalles, consulte el artículo sobre Habré: ¿Sueñan los programadores de YML con probar Ansible?) trabajó más rápido, unos 40 minutos para 10 roles. Creamos un paquete de máquinas virtuales y realizamos pruebas en su interior.
En general, la solución funcionó, pero hubo algunos sedimentos debido a la heterogeneidad. Cuando el número de personas evaluadas se incrementó a 13 roles básicos y 2 meta roles que combinan roles más pequeños, de repente las pruebas comenzaron a ejecutarse durante 70 minutos, que es casi 2 veces más. Era difícil hablar de prácticas de XP (programación extrema) porque... Nadie quiere esperar 70 minutos. Esta fue la razón para cambiar el enfoque.
Día # -601: Ansible y molécula.
Conceptualmente, esto es similar a testkitchen, solo que movimos las pruebas de roles a Docker y cambiamos la pila. Como resultado, el tiempo se redujo a 20-25 minutos estables para 7 roles.
Al aumentar el número de roles probados a 17 y vincular 45 roles, ejecutamos esto en 28 minutos en 2 esclavos jenkins.
Día #167: Agregar pruebas de Ansible al proyecto
Lo más probable es que no sea posible realizar la tarea de refactorización rápidamente. La tarea debe ser medible para que puedas partirla en trozos pequeños y comer el elefante pieza a pieza con una cucharadita. Debe comprenderse si se está avanzando en la dirección correcta y cuánto tiempo queda por recorrer.
En general, no importa cómo se haga, puedes escribir en una hoja de papel, puedes poner pegatinas en el armario, puedes crear tareas en Jira o puedes abrir Google Docs y anotar el estado actual. allá. Las piernas crecen porque el proceso no es inmediato, será largo y tedioso. Es poco probable que alguien quiera que usted se quede sin ideas, se canse y se sienta abrumado durante la refactorización.
La refactorización es simple:
Eat.
Sueño.
Código.
Prueba IaC.
Repetición:
y repetimos esto hasta llegar al objetivo previsto.
Puede que no sea posible comenzar a probar todo de inmediato, por lo que nuestra primera tarea fue comenzar con linting y verificar la sintaxis.
Día #181: Maestro de la construcción ecológica
Linting es un pequeño primer paso hacia Green Build Master. Esto no romperá casi nada, pero le permitirá depurar procesos y realizar compilaciones ecológicas en jenkins. La idea es desarrollar hábitos entre el equipo:
Las pruebas rojas son malas.
Vine a arreglar algo y al mismo tiempo hacer que el código sea un poco mejor que antes.
Día #193: De linting a pruebas unitarias
Una vez creado el proceso de obtención del código en el maestro, puede comenzar el proceso de mejora paso a paso: reemplazando el linting con roles de lanzamiento, incluso puede hacerlo sin idempotencia. Es necesario comprender cómo aplicar los roles y cómo funcionan.
Día #211: De las pruebas unitarias a las de integración
Cuando la mayoría de los roles están cubiertos con pruebas unitarias y todo está desordenado, puede pasar a agregar pruebas de integración. Aquellos. Probar no un solo bloque de la infraestructura, sino una combinación de ellos, por ejemplo, una configuración de instancia completa.
Usando jenkins, generamos muchas etapas que vinculaban roles/libros de jugadas en paralelo, luego pruebas unitarias en contenedores y finalmente pruebas de integración.
Jenkins + Docker + Ansible = Pruebas
Consulte el repositorio y genere etapas de compilación.
Ejecute las etapas del libro de jugadas de pelusa en paralelo.
Ejecute etapas de rol de pelusa en paralelo.
Ejecute las etapas del rol de verificación de sintaxis en paralelo.
Ejecute etapas de función de prueba en paralelo.
Papel de pelusa.
Verifique la dependencia de otros roles.
Verifique la sintaxis.
Crear instancia de ventana acoplable
Ejecute molécula/default/playbook.yml.
Comprueba la idempotencia.
Ejecutar pruebas de integración
Acabado
Día #271: Factor de autobús
Al principio, la refactorización la llevó a cabo un pequeño grupo de dos o tres personas. Revisaron el código en el maestro. Con el tiempo, el equipo desarrolló conocimientos sobre cómo escribir código y la revisión del código contribuyó a la difusión de conocimientos sobre la infraestructura y cómo funciona. Lo más destacado aquí fue que los revisores fueron seleccionados uno por uno, según un cronograma, es decir, con cierto grado de probabilidad subirás a una nueva pieza de infraestructura.
Y debería ser cómodo aquí. Conviene hacer un repaso, ver en el marco de qué tarea se realizó y el historial de discusiones. Hemos integrado jenkins + bitbucket + jira.
Pero como tal, una revisión no es una panacea; de alguna manera, llegamos al código maestro, lo que nos hizo fracasar en las pruebas:
Con el tiempo, hubo más pruebas y las compilaciones se ejecutaron más lentamente, hasta una hora en el peor de los casos. En una de las retros había una frase como “qué bueno que haya pruebas, pero son lentas”. Como resultado, abandonamos las pruebas de integración en máquinas virtuales y las adaptamos a Docker para hacerlo más rápido. También reemplazamos testinfra con ansible verifier para reducir la cantidad de herramientas utilizadas.
En rigor, hubo un conjunto de medidas:
Cambie a la ventana acoplable.
Elimine las pruebas de roles, que están duplicadas debido a dependencias.
Aumentar el número de esclavos.
Orden de ejecución de la prueba.
Capacidad de pelusa TODO localmente con un comando.
Como resultado, Pipeline en jenkins también se unificó.
Generar etapas de construcción.
Pelusa todo en paralelo.
Ejecute etapas de función de prueba en paralelo.
Finalizar.
Lecciones aprendidas
Evite las variables globales
Ansible utiliza variables globales, existe una solución parcial en el formulario vars_roles_privados, pero esto no es una panacea.
Dejame darte un ejemplo. Déjanos tener role_a и role_b
Lo curioso es que el resultado de los playbooks dependerá de cosas que no siempre son obvias, como el orden en que se enumeran los roles. Desafortunadamente, esta es la naturaleza de Ansible y lo mejor que se puede hacer es usar algún tipo de acuerdo, por ejemplo, dentro de un rol, usar solo la variable descrita en este rol.
BUENA: En roles para variables, use variables con el prefijo del nombre del rol; esto, al observar el inventario, hará que sea más fácil comprender lo que está sucediendo.
BAD: Usar variable estándar en bucles item, si esta tarea/libro de estrategias se incluye en alguna parte, esto puede provocar un comportamiento inesperado
Acordamos utilizar prefijos de variables; no sería superfluo comprobar que estén definidos como esperamos y, por ejemplo, no hayan sido anulados por un valor vacío.
BUENA: Verifique las 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_item3
Evite diccionarios hashes, use estructura plana
Si un rol espera un hash/diccionario en uno de sus parámetros, entonces si queremos cambiar uno de los parámetros secundarios, necesitaremos anular todo el hash/diccionario, lo que aumentará la complejidad de la configuración.
Los roles y los manuales deben ser idempotentes, porque reduce la deriva de configuración y el miedo a romper algo. Pero si usas molécula, entonces este es el comportamiento predeterminado.
Evite el uso de módulos de shell de comandos
El uso de un módulo de shell da como resultado un paradigma de descripción imperativo, en lugar del declarativo, que es el núcleo de Ansible.
Pon a prueba tus roles a través de la molécula
La molécula es algo muy flexible, veamos algunos escenarios.
Molécula Múltiples instancias
В molecule.yml en la sección platforms puede describir muchos hosts que puede implementar.
En molecula es posible usar ansible para verificar que la instancia se haya configurado correctamente, además, este ha sido el valor predeterminado desde la versión 3. No es tan flexible como testinfra/inspec, pero podemos comprobar que el contenido del archivo coincide con nuestras expectativas:
O implemente el servicio, espere a que esté disponible y realice una prueba de humo:
---
- 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.csv
Ponga lógica compleja en módulos y complementos
Ansible aboga por un enfoque declarativo, por lo que cuando realiza bifurcaciones de código, transformación de datos y módulos de shell, el código se vuelve difícil de leer. Para combatir esto y que sea fácil de entender, no sería superfluo combatir esta complejidad creando sus propios módulos.
Resumir consejos y trucos
Evite las variables globales.
Variables de rol de prefijo.
Utilice la variable de control de bucle.
Verifique las variables de entrada.
Evite los diccionarios hashes, utilice una estructura plana.
Cree manuales y roles idempotentes.
Evite el uso de módulos de shell de comandos.
Pruebe sus roles a través de moléculas.
Coloque lógica compleja en módulos y complementos.
Conclusión
No puedes simplemente refactorizar la infraestructura de un proyecto, incluso si tienes IaC. Este es un proceso largo que requiere paciencia, tiempo y conocimiento.
UPD1 2020.05.01 20:30 — Para la creación de perfiles principales de libros de jugadas, puede utilizar callback_whitelist = profile_tasks para comprender qué funciona exactamente durante mucho tiempo. Luego pasamos por Clásicos de la aceleración ansible. También puedes probar mitógeno UPD2 2020.05.03 16:34 - Versión Inglés