Helmfile: superpoderes para Helm ☸️🔧
Helm es sin duda una de las herramientas más utilizadas en el mundo de Kubernetes. Es especialmente útil ya que es a la vez, una herramienta de despliegue, un gestor de paquetes y una herramienta de templatizado que permite customizar el comportamiento de las aplicaciones en función de los valores utilizados. Además, proporciona características ideales para integrarlo en entornos de CI/CD modernos, convirtiéndola en una herramienta esencial para tu 'caja de herramientas' de DevOps.
Helm se basa en charts, que funcionan como paquetes de software independientes, conteniendo los manifiestos de los objetos de Kubernetes a desplegar. No obstante, para entornos más complejos, en los que deben desplegarse varios charts, no existe una manera sencilla de gestionar estos despliegues de forma centralizada. Basándome en mi experiencia, se pueden desarrollar plugins de Helm que permitan orquestar multiples charts y valores en varios entornos. No obstante, esta estrategia puede acabar siendo poco práctica, ya que es necesario mantener los plugins. Además, el empleo de dichos plugins impide utilizar algunas herramientas que proporcionan integraciones nativas con Helm, como herramientas de CD o GitOps. Pero no te preocupes, a continuación conocerás una herramienta que puede ayudarte a solucionar estos problemas: Helmfile.
Helmfile es un CLI desarrollado por Robert Boll que permite orquestar multiples releases de Helm de forma declarativa usando código (YAML+go templating). Proporciona una gran flexibilidad y modularidad para la gestión tanto de charts como de valores, así como una forma de desplegar los cambios en los clústers muy 'Terraformiana'. A parte de esto, también soporta kustomize en caso de que no quieras seguir la 'senda de Helm' 🌚.
Al igual que en artículos anteriores, se ha desarrollado un repo con ejemplos. Puedes encontrarlos aquí.
Instalando Helmfile ⬇️
Helmfile utiliza Helm para poder desplegar las releases de los charts, por lo que en primer lugar, es necesario instalar Helm en tu máquina local. El siguiente comando descargará el script de instalación de Helm 3 en tu máquina (no te recomiendo que utilices Helm 2 😂).
Si prefieres instalar el binario manualmente, puedes encontrarlo en la página de releases de Helm.
Lo siguiente es instalar Helmfile. Puedes hacerlo descargando el binario de la página de releases de Helmfile. Ejecuta los siguientes comandos añadiendo tu SO/plataforma a la URL.
Finalmente tendrás que instalar el plugin diff de Helm, ya que es necesario para que Helmfile pueda detectar las diferencias entre las releases presentes en los clústers y los cambios a desplegar.
Estructura 📂
Una vez que todos los binarios y plugins se encuentren instalados, es el momento de presentar la estructura utilizada por Helmfile para organizar las releases/charts como código. Para disponer de un Helmfile de ejemplo, clona el repositorio de ejemplo.
Es importante tener en cuenta que la estructura de Helmfile es altamente customizable, y que los ficheros pueden ser referenciados desde otros ficheros, lo que se conoce como 'layering', y ofrece infinitas posibilidades para organizar el código. La siguiente imagen muestra el contenido del repositorio de ejemplo, que es sencillamente una forma particular de organizar el código que encuentro bastante útil.
- En el directorio raíz puedes encontrar helmfile.yaml, que es el nombre por defecto para el fichero de configuración. Funciona como un 'punto de entrada' y referencia al resto de ficheros.
- El directorio bases contiene los repositorios de Helm que serán utilizados, así como los valores para los diferentes entornos.
- El directorio releases contiene releases.yaml, que especifica las releases de Helm a instalar, así como metadatos específicos de las releases.
- Bajo la ruta releases/values se encuentran los diferentes ficheros de valores a utilizar. Helmfile fusiona dichos valores con los presentes en los charts referenciados en releases.yaml.
helmfile.yaml define los ficheros base, los helmfiles anidados y los valores por defecto para Helm. Los ficheros base se fusionan entre ellos y junto con helmfile.yaml antes de procesar el resto de ficheros. El código que verás a continuación muestra el contenido de helmfile.yaml.
Bajo la directiva helmfiles es posible especificar el fichero o conjunto de ficheros en los que se definen las releases de Helm. Para mantener este ejemplo lo más sencillo posible, todas las releases se han agrupado en el mismo fichero (releases/releases.yaml). La directiva helmDefaults permite customizar el funcionamiento de Helm, con parámetros similares a los flags nativos del CLI de Helm.
repos.yaml es una colección de repositorios de Helm que utiliza Helmfile para descargar las releases que se le indican. Al ser parte de los ficheros base, se fusiona con helmfile.yaml (también puede especificarse este bloque directamente dentro de helmfile.yaml). Puedes ver sus contenidos a continuación.
El siguiente fragmento de código forma parte del fichero releases.yaml. Bajo la directiva releases se especifican las diferentes releases de Helm junto con algunos parámetros que permiten customizarlas. La ruta del fichero o ficheros de valores a utilizar, que se combinan con los valores por defecto del chart también se especifica aquí. Fíjate en que se pueden utilizar valores como el nombre del entorno para renderizar las rutas, y además Helmfile soporta el empleo de templating de go para definir releases condicionales.
En este caso particular, el autoscaler solo se desplegará en el entorno productivo, teniendo en cuenta los valores de entorno definidos en /bases/environments.yaml.
NOTA: Es importante mencionar aquí que Helmfile trata los ficheros de valores de forma diferente dependiendo de su extensión. Si necesitas renderizar expresiones dentro de los ficheros, añade al extensión .gotmpl , ya que si no, los ficheros se procesarán sin evaluar las expresiones. El siguiente código muestra el contenido de cluster-autoscaler-values.yaml.gotmpl, el único fichero de valores en este ejemplo que realmente utiliza expresiones. En este caso, se emplean para determinar el nombre del cluster en función del entorno.
Desplegando Charts ⚙️
Para probar Helmfile, desplegaremos releases en dos entornos diferentes: producción y desarrollo. El Helmfile de ejemplo contiene cuatro releases:
- Nginx Ingress Controller
- Kubernetes Dashboard
- Cluster Autoscaler
- Apache server
Como se ha comentado anteriormente, la release del autoscaler será sólo desplegada en prod utilizando la configuración avanzada de Helmfile. Además, las releases de Kubernetes dashboard y Apache utilizarán valores diferentes en función del entorno (host del ingress, número de réplicas, etc)
Los entornos consistirán en clústers de AWS EKS que desplegaremos utilizando eksctl. Si no has leído el artículo anterior sobre eksctl, y quieres conocer más detalles a cerca de esta herramienta, échale un ojo.
No obstante, también puedes probar este ejemplo en local con minikube o docker desktop (o incluso en tu clúster propio), pero ten en cuenta que no podrás emular dos clústers separados con este setup.
Para empezar, descarga el binario de eksctl y colócalo bajo tu PATH.
Antes de desplegar, necesitarás configurar tus credenciales de AWS, utilizando el AWS CLI. Para ello, necesitarás un par de access key y secret key de AWS. Si no dispones de uno, puedes generarlo en la consola de IAM de AWS. Consulta la documentación oficial como referencia si lo necesitas.
Ten en cuenta que el usuario al que se le asignen dichas claves de acceso debe tener permisos para crear la infraestructura. Para este ejemplo puedes utilizar la policy gestionada AdministratorAccess . Guarda bien el par de claves, y una vez que termines de probar estos ejemplos y este usuario no se vaya a utilizar de nuevo, elimínala, para evitar riesgos innecesarios.
Entorno de Desarrollo 🏗️
Una vez que eksctl esté listo para usar, ejecuta los siguientes comandos para crear el entorno de desarrollo en tu cuenta de AWS, y espera a eksctl termine su labor. Sé paciente, ya que puede tardar un rato ⏳.
Para cuando eksctl haya acabado, deberías tener un clúster con un sólo nodo. Eksctl se encarga de apuntar tu kubeconfig local y tu contexto de Kubernetes al clúster que acaba de crear, por lo que no es necesario configurar nada más.
Una vez que el clúster esté listo, empezaremos a desplegar los charts. En primer lugar, ejecuta el siguiente comando para añadir y actualizar los repos (es equivalente a helm repo add && helm repo update).
Helmfile puede utilizarse también para comprobar los templates que componen los charts. Para hacerlo, ejecuta el siguiente comando. Al añadir el flag –skip-deps Helmfile omite los pasos repo add y update , así como la construcción de las dependencias del chart (helm dependency build).
El siguiente comando despliega los charts adecuados en el entorno de desarrollo. El flag –suppress-secrets indica a Helmfile que no debe mostrar los secretos en la salida del terminal. Esto es especialmente útil para las herramientas de CI/CD, en las que los logs de los ejecutores suelen ser explícitos.
Como se comentó anteriormente, Helmfile tiene una forma de mostrar y aplicar los cambios 'a lo Terraform'. En este caso, todos los recursos se muestran en verdes ya que son nuevos recursos a añadir. Fíjate en como las definiciones de los secretos no se muestran en el terminal.
Ahora deberías poder ver tres releases desplegadas en el clúster. Puedes comprobarlo ejecutando el siguiente comando de Helm.
Como apache y Kubernetes dashboard se exponen a través de un ingress, ambas aplicaciones se pueden alcanzar con un navegador web.
NOTA: Seguramente te has fijado en que he podido alcanzar ambos ingress sin ninguna configuración extra de DNS. ¿Cómo es esto posible? No, no es magia negra 🧙♂️, es un sencillo truco que consiste en crear una entrada de DNS en el fichero /etc/hosts que contenga la IP del balanceador del ingress y el nombre del ingress. Si quieres probarlo, puedes obtener la IP del balanceador ejecutando el siguiente comando.
Una vez que hayas obtenido la IP, añade las entradas correspondientes a /etc/hosts .
Helmfile incluye el comando sync, que permite sincronizar los contenidos de los 'ficheros de estado' (repos, releases y dependencias). Es recomendable ejecutar este comando de forma periódica para asegurarse de que las releases están actualizadas. La principal diferencia entre helmfile apply y helmfile sync es que el primero solo despliega los cambios si se encuentran diferencias, mientras que el segundo sincroniza todos los recursos.
Ahora, modifica algunos de los valores para el entorno de desarrollo. Por ejemplo, modifica el número de réplicas del deployment de apache y luego ejecuta el siguiente comando. Como verás, muestra los campos de los objetos de Kubernetes que serán modificados en las releases de Helm presentes en el clúster. Este comando es bastante útil para entornos de CI/CD en los que se necesita aprobación manual para desplegar cambios en base a un plan de despliegue. En estos casos, el plan de despliegue se puede generar con helmfile diff y una vez aprobados, se aplican con helmfile apply.
El comando diff utiliza el plugin diff de Helm, y es por eso que tuvimos que instalarlo al comienzo.
Entorno de producción 🏭
Ahora, desplegaremos el clúster de producción y sus aplicaciones utilizando el mismo procedimiento que hemos empleado para el entorno de desarrollo.
Si todo funciona como debe, tendrás un clúster desplegado con una serie de aplicaciones que puedes ver en la siguiente imagen. En este caso, aparece una nueva release, cluster autoscaler, ya que los valores condicionales solo permitían que se desplegase en el entorno de producción.
El autoscaler es completamente funcional, y puedes probarlo escalando el número de réplicas del deployment de apache con el siguiente comando.
Si le das un par de minutos al cluster autoscaler, verás que aparecen nuevos nodos para poder servir el incremento de carga generado por las nuevas réplicas. En este ejemplo, el número máximo de nodos configurado para el clúster es 3.
Desmontando el chiringuito🎪
Una vez que hayas terminado de jugar con tus entornos y Helmfile, puedes destruir directamente los clústers utilizando eksctl 💥.
Si estás probando este ejemplo en tu propio clúster, puedes eliminar todas las releases con Helmfile. Para ello, ejecuta los siguientes comandos.
Sigue aprendiendo👩💻👨💻
Si te ha gustado Helmfile, tómate tu tiempo para investigar su repo en GitHub, ya que te ayudará a entender mejor todas las configuraciones avanzadas y opciones para customizar las releases y el propio comportamiento de Helm.
Recuerda que el ejemplo que se ha presentado en este artículo es solo una de las posibles formas de organizar Helmfiles, puedes hacer una prueba y organizarlo como mejor se adapte a tu escenario particular: colocando todas las releases y la configuración en un solo fichero, utilizando un fichero por release, etc. Si quieres indagar un poco más en cómo organizar tus Helmfiles, échale un ojo a la Guía de mejores prácticas de Helmfile.