En una nueva aerolínea. Una azafata ingresa a la cabina de pasajeros: "Estás en nuestra nueva aerolínea. En la parte delantera del avión, tenemos una sala de cine. En la parte trasera, una sala de máquinas tragamonedas. En el piso inferior, una piscina. En el cubierta superior - una sauna Ahora, caballeros, abróchense los cinturones de seguridad, y con todas estas cosas innecesarias, vamos a intentar despegar.
Hola, mi nombre es Andrii. He estado trabajando en la industria de TI durante la mayor parte de mi vida. Estoy muy interesado en la evolución de la ingeniería de gestión de configuración de infraestructura. Durante los últimos 8 años, he estado involucrado en DevOps .
Una de las nuevas tendencias populares es el concepto de GitOps , presentado en 2017 por Alexis Richardson, director ejecutivo de Weaveworks. Weaveworks es una gran empresa adulta que, en 2020, recaudó más de 36 millones de inversión para desarrollar sus GitOps.
Mi artículo anterior discutió una historia de éxito de reducción de costos sobre cómo cambiamos de Elastic Stack a Grafana . Ahora, voy a tratar de hablar sobre los desafíos no obvios que pueden esperarle al adoptar este concepto. En resumen, GitOps no es una "bala de plata". Es probable que termine reorganizándose con muchas soluciones complicadas. Yo mismo he recorrido este camino y quiero mostrarle los problemas más frustrantes que no puede ver cuando lee otros artículos sobre GitOps.
¡Vamos a sumergirnos!
El concepto más prometedor de construcción de infraestructura hoy en día es la infraestructura inmutable. Su idea clave es dividir la infraestructura en 2 partes fundamentalmente diferentes: sin estado y con estado.
La parte sin estado de la infraestructura es inmutable e idempotente. No acumula estado (no almacena datos) ni cambia su funcionamiento dependiendo del estado acumulado. Las instancias de la parte sin estado pueden contener algunos artefactos, secuencias de comandos y ensamblajes básicos. Por regla general, los creo a partir de imágenes base en la nube/entornos virtualizados. Son frágiles y efímeros: entrego nuevas versiones de aplicaciones recreando instancias a partir de nuevas imágenes base.
Los datos persistentes se almacenan en la parte Stateful. Puede realizarse por el esquema clásico con servidores dedicados o por algunos mecanismos en la nube (DBaaS, almacenamiento de objetos o bloques).
Para que este "zoológico" sea manejable y funcione correctamente, necesitamos la colaboración entre los equipos de ingeniería y DevOps, así como canales de entrega totalmente automatizados.
La programación extrema es una de las metodologías de desarrollo ágil. Se distingue por muchos bucles de retroalimentación, que le permiten mantener la sincronización con las necesidades del cliente.
Implementamos la automatización de pipelines de entrega utilizando sistemas CI/CD. El término CI (Integración Continua) fue propuesto por Grady Booch en 1994, y en 1997 Kent Beck y Ron Jeffries lo introdujeron en la disciplina de la programación extrema. En CI, necesitamos integrar nuestros cambios con la mayor frecuencia posible en la rama de trabajo principal de nuestro proyecto.
Esto requiere, en primer lugar, una descomposición más granular de las tareas: los cambios pequeños son más atómicos y más fáciles de rastrear, comprender e integrar. En segundo lugar, no podemos fusionar código recién escrito. Antes de fusionar ramas, debemos asegurarnos de que nada de lo que funcionó antes se haya roto. Para hacer esto, la aplicación debe al menos estar construida. También es una buena idea cubrir el código con pruebas.
Y esta es la tarea que realizan los sistemas CI, que han avanzado mucho en el desarrollo y, en algún punto intermedio de este camino, se convirtieron en sistemas CI/CD.
¿Qué es un CD? Martin Fowler distingue 2 definiciones de CD :
Entrega continua. Aquí es cuando, con la ayuda de las prácticas de integración continua y la cultura DevOps, mantiene la rama principal de su proyecto constantemente lista para implementarse en producción.
Despliegue Continuo. Es la entrega continua donde todo lo que va a la rama principal se vuelca en su clúster, en su producción.
Vayamos más lejos.
Desafortunadamente, la infraestructura inmutable tiene varios problemas. La mayor parte de ellos se hereda del concepto de Infraestructura como Código (IaC).
En primer lugar, es la deriva de configuración. Este término nació en Puppet Labs (autores del conocido Puppet SCM) y establece que no todos los cambios en los sistemas de destino se realizan con la ayuda de la gestión de configuración del sistema (SCM). Algunos se realizan manualmente, sin pasar por ellos.
En el proceso de tales cambios múltiples, aparece la deriva de configuración: la diferencia entre la configuración descrita en SCM y el estado real de las cosas.
Esto conduce a una espiral de miedo a la automatización.
Cuantos más cambios manuales se realicen, más probable es que la ejecución de un script de SCM interrumpa los cambios no registrados. Cuanto más aterrador sea ejecutarlo, más probable es que se realicen nuevas ediciones manuales.
Eventualmente, esta retroalimentación positiva viciosa conduce a la formación de servidores de copos de nieve, que se han vuelto tan inconsistentes que ya nadie entiende lo que hay dentro. Después de las ediciones manuales, el nodo se vuelve tan único como cada copo de nieve individual en una nevada.
Esta deriva deja a los servidores en niveles más altos dentro de una infraestructura inmutable: ahora podemos hablar de GCP Project/AWS VPC/Kubernetes-cluster-snowflakes. Esto sucede porque la implementación de cambios no está regulada en una infraestructura inmutable. Además, nadie sabe cómo hacerlo correctamente.
Y luego aparece Weaveworks y dice: "Chicos, tenemos lo que necesitan: GitOps". Para promover GitOps, trajeron a un peso pesado como Kelsey Hightower, quien creó la guía "Kubernetes de la manera difícil" . Durante su PR, transmite en gran medida el mensaje: "¡Sé un hombre, b ...! Deje de escribir y comience a enviar". Y dice una cierta cantidad de bingo de mierda de marketing.
En mi opinión, los beneficios más emocionantes fueron:
Y cualquiera que intente descubrir qué es GitOps se encuentra con esta diapositiva de libro de texto.
A continuación, encontramos los principios de GitOps, que se asemejan a los principios de IaC ligeramente aumentados:
Sin embargo, esta es una descripción esférica en el vacío, por lo que continuamos nuestra investigación. Encontramos el sitio web GitOps.tech y en él varias aclaraciones importantes.
Primero, aprendemos que GitOps es un código similar a una infraestructura en Git con herramientas de CD que aplica esto automáticamente a la infraestructura.
Debemos tener al menos 2 repositorios dentro de GitOps:
Además, en la ideología de GitOps, se prefiere un enfoque orientado a la extracción sobre un enfoque orientado a la inserción. Esto es algo contrario a la evolución de los sistemas SCM desde los pesados monstruos pull Puppet y Chef hasta los ligeros Ansible y Terraform basados en push.
Y si GitOps es principalmente una historia de herramientas, entonces tiene sentido tomar el concepto basado en Flux de Weaveworks y deconstruirlo. Los autores de la idea deben haber hecho una implementación de referencia.
Flux ahora está en la versión 2 y su arquitectura consta de controladores que funcionan dentro de un clúster:
A continuación, analicemos el trabajo con Flux y Helm.
Voy a describir más detalladamente el ejemplo de implementación de una aplicación utilizando el administrador de paquetes Helm en Flux 2.
¿Por qué? Según la encuesta CNCF 2021 , el administrador de paquetes HELM fue la aplicación de embalaje más popular, con una participación de más del 50 %.
Desafortunadamente, no pude encontrar más datos actualizados, pero no creo que haya cambiado mucho desde entonces.
Entonces, repasemos la lógica básica de cómo funciona Flux 2 con Helm. Tenemos 2 repositorios: aplicación e infraestructura.
Creamos un gráfico HELM y una imagen acoplable desde el repositorio de la aplicación y los agregamos al repositorio de gráficos Helm y al registro acoplable, respectivamente.
A continuación, tenemos un clúster de Kubernetes que ejecuta los controladores de flujo.
Para implementar nuestra aplicación, preparamos un YAML que describe el recurso personalizado (CR) HelmRelease y lo agregamos al repositorio de infraestructura.
Para ayudar a flux a obtenerlo, creamos un CR GitRepository en el clúster de Kubernetes. El controlador de origen lo ve, va a git y lo descarga.
Para implementar este YAML en un clúster, describimos un recurso de personalización.
El controlador Kustomize lo ve, va al controlador de origen, obtiene el YAML y lo implementa en el clúster.
El controlador Helm ve que ha aparecido un CR HelmRelease en el clúster y va al controlador de origen para obtener la descripción del gráfico HELM.
Para que el controlador de origen proporcione al controlador HELM el gráfico solicitado, debemos crear un HelmRepository en el clúster CR.
Helm-controller obtiene un gráfico de Source-controller, crea una versión y la implementa en el clúster. Luego, Kubernetes crea los pods necesarios, va al registro de la ventana acoplable y descarga las imágenes correspondientes.
En consecuencia, para implementar una nueva versión de nuestra aplicación, debemos crear una nueva imagen, un nuevo archivo HelmRelease y posiblemente un nuevo gráfico HELM. Luego debemos ponerlos en los repositorios apropiados y esperar a que los controladores de Flux repitan el trabajo en la cadena descrita anteriormente.
Y, para finalizar nuestro trabajo, colocamos un controlador de Notificación en algún lugar que nos notifique lo que podría haber salido mal.
Ahora analicemos los recursos personalizados con los que opera Flux.
El primero es el repositorio de Git. Aquí podemos especificar la dirección del repositorio de Git (línea 14) y la rama que busca (línea 10).
Por lo tanto, solo descargamos una sola rama, no todo el repositorio. ¡Pero! Como somos ingenieros responsables y tratamos de adherirnos al concepto Zero Trust, bloqueamos el acceso al repositorio, creamos un secreto con una clave en el clúster de Kubernetes y se lo damos a Flux para que pueda ir allí (línea 12).
Lo siguiente es la personalización. Aquí quiero llamar su atención sobre el hecho de que el controlador Kustomize de Flux y Kustomize de los autores de Kubernetes son 2 cosas diferentes. No sé por qué se eligió una denominación tan desorientadora, pero es importante no confundirlos.
La personalización es una forma de implementar YAML (cualquiera) desde un repositorio de Git a un clúster. Aquí tenemos que especificar la fuente de donde lo ponemos (línea 12 - el nombre del CR GitRepository descrito arriba), el directorio de donde tomamos los YAML (línea 8), y podemos especificar el espacio de nombres de destino donde depositarlos (línea 13).
El siguiente es el lanzamiento de Helm.
Aquí podemos especificar el nombre y la versión del gráfico (líneas 10,11). Aquí especifica los valores de las variables para que Helm pueda personalizar la versión de un entorno a otro (líneas 15 a 19). Esta es una característica extremadamente importante y necesaria, ya que sus entornos pueden diferir significativamente. También especifica la fuente para tomar el gráfico de Helm (líneas 12, 13, 14). En este caso, es el repositorio de Helm.
¡Pero! Dado que aún somos ingenieros responsables, también tenemos acceso cercano al repositorio de Helm y le damos a Flux un secreto para llegar allí (líneas 7, 8).
Entonces, hagamos una pequeña lista de verificación para capturar lo que acabamos de repasar. Para comenzar a hacer GitOps, tenemos que escribir repentinamente un montón de scripts (recordamos que la infraestructura inmutable se trata de canalizaciones de entrega totalmente automatizadas). Así que antes que nada, tenemos que crear:
Genial, ahora tienes una lista de verificación para GitOps. Siga adelante.
Veamos qué obtenemos con nuestro lanzamiento de Helm en general. Es bastante evidente que Git no puede ser la única fuente de verdad en este caso particular. Tenemos al menos 2 recursos, 2 artefactos fuera de git, de los que depende esta versión de Helm:
Y podemos complicar aún más las cosas y especificar el rango de versiones del gráfico de Helm.
En este caso, Flux monitoreará y establecerá nuevos gráficos de Helm que aparezcan dentro de este rango. Además, el controlador de origen que tenemos puede usar YAML como fuente, incluidos los paquetes S3.
A partir de ahí, podemos conservar los gráficos YAML y Helm.
Además, tenemos controladores de automatización de imágenes que pueden vigilar nuevas imágenes en el registro de Docker y editar el repositorio de infraestructura.
Pero no queremos HELM Chart repo-Ops o Docker Registry-Ops. Queremos ser tan GitOps como sea posible. Así que miramos la documentación y corregimos los procesos para implementar nuestro diagrama de Helm desde el repositorio GIT (elegimos el repositorio de la aplicación para almacenarlo).
Esto nos obliga a hacer otro CR GitRepository para el repositorio de aplicaciones, una cuenta para que Flux acceda a él y crear un secreto con claves.
Al mismo tiempo, no resolvemos el problema de una dependencia complicada de la imagen de Docker de ninguna manera.
Creo que es suficiente por hoy. En la 2 parte, les diré qué problemas tiene esta bondad. Lo discutiré:
¡Espero que este artículo te haya sido útil!