
Este es el segundo post de una colección de artículos acerca de GitOps. En este post analizaremos una herramienta para despliegue continuo en Kubernetes: FluxCD. El anterior artículo fue un análisis en profundidad sobre otra herramienta, ArgoCD.
Si no has leído los artículos previos a cerca de Kubernetes deployments y Helm, échales un ojo antes de leer este post, ya que te ayudarán a entender la idea general mucho mejor.
GitOps
GitOps se define como una estrategia para gestionar la infraestructura de Kuberentes y sus aplicaciones en la que la definición declarativa de lo que debe estar corriendo en el clúster se almacena en un repositorio de git. El repositorio de git se considera como la la única fuente de verdad en el modelo de GitOps. Con esta estrategia, cualquier cambio en la definición de las aplicaciones (código), se refleja en la infraestructura desplegada y en las aplicaciones. Además, permite detectar diferencias y desviaciones entre el código de la aplicación y las versiones desplegadas.
GitOps incrementa la frecuencia de entregas de software, ya que en el momento en el que el código se encuentre en la rama productiva, también estará presente en el clúster en cuestión de segundos, incrementando también la productividad. Este modelo incrementa también la fiabilidad y robustez, ya que como todas las aplicaciones y los despliegues se encuentran bajo el control de versiones de git, los rollbacks y procedimientos de recuperación son más sencillos. Además, GitOps permite mejorar la estabilidad y la consistencia de las aplicaciones, al automatizar y unificar el método de despliegue
FluxCD
FluxCD es una herramienta declarativa para la automatización de los despliegues en Kubernetes, que se controla con su propio CLI, fluxctl. FluxCD utiliza un operator instalado en el clúster para asegurar que los objetos que se encuentran desplegados, coinciden con la configuración definida en un repositorio de git. Los operators son una forma de extender las funcionalidades de Kubernetes. Monitorizan e interaccionan con la API de Kubernetes, y controlan los custom resources, que son los elementos que realmente permiten extender y customizar el comportamiento de Kubernetes. Resumiendo: los operators escuchan eventos y reaccionan ante ellos ejecutando acciones sobre los componentes desplegados en el clúster.
Para este ejemplo, utilizaremos FluxCD junto con su Helm v3 operator. Por ello, puede que el flujo se complique un poco más, pero merece la pena. El diagrama siguiente muestra las diferentes piezas que interaccionan para desplegar los charts de helm automáticamente.

Primero, el operator de FluxCD monitoriza los cambios en el código que se encuentra en el repositorio de git, y en el momento en el que detecta un cambio, aplica los cambios en el clúster. Ahora es cuando la cosa se pone interesante: en vez de aplicar los cambios directamente sobre los charts desplegados, aplica los cambios en unos custom resources específicos conocidos como HelmReleases. Éstos, a su vez disparan el funcionamiento de otro operator, el operator de Helm, que es el que realmente sincroniza los cambios en el código de los charts en los charts desplegados. Además, FluxCD puede monitorizar los repositorios de imágenes docker utilizados por los charts y desencadenar updates y nuevos despliegues cuando detecta cambios.
Instalando FluxCD
Para poder reproducir los ejemplos que vamos analizar, necesitarás un clúster de Kubernetes. Ya que no tiene que ser un clúster grande ni necesita alta disponibilidad, puedes utilizar Minikube o Docker desktop. Yo utilicé Docker desktop para preparar este artículo.
El primer paso es instalar el CLI de FluxCD (fluxctl): aquí puedes encontrar las releases actualizadas de sus binarios para diferentes SOs. Una vez obtengas la versión adecuada, coloca el binario en tu $PATH. Una vez instalado, es necesario instalar otro componente, el CLI de Helm v3, siguiendo un procedimiento similar. Los binarios de Helm v3 pueden encontrarse en aquí. Con ambos CLIs instalados, ya podemos comenzar a desplegar los recursos necesarios para FluxCD utilizando Helm. Para poder hacerlo, primero es necesario añadir el repositorio de charts de FluxCD y crear un namespace dedicado.
helm repo add fluxcd https://charts.fluxcd.io
kubectl create namespace fluxcd
Instala FluxCD indicando el repositorio que contiene el chart de Helm cuyo despliegue quieras automatizar. En este caso, puedes hacer fork de este repositorio público que ha sido específicamente desarrollado para el artículo. Contiene un chart de Helm sencillo que despliega un servidor web multipod así como un ingress controller de nginx. Además, el repositorio contiene la configuración que utilizará FluxCD para desplegar el chart de helm en diferentes entornos con diferentes valores y parámetros. El siguiente comando instalará FluxCD.
helm upgrade -i flux fluxcd/flux --wait --namespace fluxcd --set git.url=git@github.com:yourusername/helmflux
El repositorio se organiza como se muestra a continuación. Aparte de los charts de Helm en sí, contiene los namespaces de Kubernetes en los que FluxCD desplegará los charts, y recursos específicos para el operator de Helm en el directorio releases Para este ejemplo, se consideran tres entornos diferentes: development, staging y production, siendo implementados como namespaces de Kubernetes. Además, se emplean tres ramas en el repositorio, alineadas con los entornos: development, staging y master.
mifonpe/helmflux
|
helmbasics/
|
nginx-ingress/
|
releases/
| dev.yaml
| pro.yaml
| stg.yaml
| ingress.yaml
|
namespaces/
dev.yaml
pro.yaml
stg.yaml
ingress.yaml
El siguiente paso es dar acceso a FluxCD al repositorio de git utilizando una clave pública SSH. FluxCD genera una clave de forma automática, que puede recuperarse usando fluxctl.
fluxctl identity --k8s-fwd-ns fluxcd
Si utilizas GitLab o GitHub, tendrás que pegar la clave pública en los ajustes de control de acceso del repositorio. En el caso de GitHub ve a Settings>Deploy Keys y pega la clave pública proporcionada por el comando anterior de fluxctl. Activa los permisos de escritura sobre el repositorio.

A continuación es necesario instalar un custom resource de Kubernetes, conocido como HelmRelease. Este objeto representa una release de Helm para un chart específico, y contiene parámetros relevantes, como el namespace en el que desplegar el chart, el nombre de la release que utilizará Helm así como el repositorio de git, junto con la rama y ruta en el que se puede encontrar el chart. En el código del objeto HelmRelease puede observarse como se especifica la annotation fluxcd.io/automated. Cuando esta annotation toma el valor true, cualquier cambio en el repositorio, para la rama y ruta especificada disparará la sincronización automática de FluxCD. El código que se muestra a continuación muestra la HelmRelease que se desplegará en el namespace development. Este objeto permite sobreescribir los valores por defecto especificados en el fichero values.yaml del chart.
apiVersion: helm.fluxcd.io/v1
kind: HelmRelease
metadata:
name: helmbasic-develop
namespace: develop
annotations:
fluxcd.io/automated: "true"
spec:
releaseName: helmbasic-develop
chart:
git: git@github.com:yourname/helmflux
path: helmbasics
ref: develop
values:
environment: development
replicaCount: 1
ingress:
host: mywebserver.dev.kubesandclouds.com
El objeto HelmRelease para las ramas de los entornos producción y staging utiliza valores diferentes, para emular diferentes configuraciones y características del chart dependiendo del entorno. Tómate tu tiempo para revisar los objetos HelmRelease y los valores que se especifican en los mismos.
Para poder utilizar las HelmReleases, es necesario 'instalarlas' primero. El comando siguiente se encarga de ello, ya que instala el Custom Resource Definition (CRD) de Kubernetes para las HelmReleases. Los CRD especifican como utilizar e interactuar con los Custom Resources de Kubernetes.
kubectl apply -f https://raw.githubusercontent.com/fluxcd/helm-operator/master/deploy/crds.yaml
Tras esto, el operator de Helm para FluxCD debe instalarse en el clúster, para que los charts de Helm puedan desplegarse de forma automática. Fíjate que se especifica la versión 3 de Helm como argumento para la instalación. Este operator soporta también Helm v2.
helm upgrade -i helm-operator fluxcd/helm-operator --wait \
--namespace fluxcd \
--set git.ssh.secretName=flux-git-deploy \
--set helm.versions=v3
'Desplegando' todo
Tras haber creado los diferentes componentes, si esperas unos minutos e inspeccionas el clúster, podrás ver que los recursos definidos en el repositorio han sido desplegados.


FluxCD utiliza un polling interval de 5 minutos, lo que significa que consulta el repositorio git cada 5 minutos para detectar cualquier posible cambio que haya que desplegar. No obstante, si no quieres esperar, o si la sincronización automática no se encuentra activada, puedes sincronizar el repositorio a mano utilizando el siguiente comando. Fluxctl necesita conocer el namespace en el que FluxCD se encuentra desplegado. Puede especificarse utilizando el flag –k8s-fwd-ns.Puede observarse el SHA del último commit aplicado en la sincronización.

Puedes inspeccionar los objetos HelmRelease desplegados por FluxCD utilizando el siguiente comando.
kubectl get hr -A

Recuerda que para este ejemplo, yo he utilizado Docker desktop, lo que implica que el clúster entero está corriendo dentro de una máquina, incluyendo el balanceador de carga que utiliza el ingress controller de nginx para enviar el tráfico HTTP/HTTPS a los servicios corriendo en el clúster. Por ello, para acceder a los recursos utilizando su nombre de DNS, puedes utilizar el siguiente comando. Tras ejecutarlo, tu máquina enviará todo el tráfico destinado a mywebserver.dev.kubesandclouds.com, mywebserver.staging.kubesandclouds.com y mywebserver.pro.kubesandclouds.com a ese balanceador de carga interno que está corriendo en la máquina.
sudo sh -c 'echo "127.0.0.1 mywebserver.dev.kubesandclouds.com mywebserver.pro.kubesandclouds.com mywebserver.staging.kubesandclouds.com" >> /etc/hosts'
Ahora puedes acceder a las aplicaciones desplegadas en los diferentes namespaces utilizando sus nombres de DNS. Cada pod del despliegue genera una entrada en la página principal del servidor web. Como cada entorno tiene un número diferente de replicas configurado en sus values, en cada entorno, la página principal tendrá un número diferente de entradas.



Haciendo algunos cambios
Añadamos algunos cambios en la rama develop del chart. Por ejemplo, podemos modificar el valor del secret con el que se configura el servidor.

Puedes añadir también un initContainer para emular el proceso de arranque y configuración previo del servidor.

Espera a que FluxCD sincronice los elementos modificados en el namespace development. Si no quieres esperar, puedes forzar la sincronización utilizando el CLI. Comprueba el nuevo servidor que se ha desplegado y podrás ver que ha generado tres entradas diferentes, aún utilizando una única réplica en el namespace development.

Cómo es posible? Es una consecuencia directa del empleo de volúmenes persistentes de Kubernetes para almacenar la página principal. Cada vez que el pod se reinicia, añade una nueva entrada en el fichero. En este caso, se han añadido cambios en dos commits diferentes, por lo que FluxCD sincronizó el repo dos veces, redesplegando el pod dos veces.

Imágenes y FluxCD
Como se comentó anteriormente, FluxCD es capaz de monitorizar repositorios de imágenes Docker y redesplegar las aplicaciones y recursos que usan dichas imágenes. FluxCD reconoce la annotation filter.fluxcd.io/chart-imagey monitoriza los repositorio de imágenes especificados en el chart detectando modificaciones en cualquier imagen que utilice un tag que coincida con el especificado en la annotation. En este caso, si se sube una nueva imagen al repositorio con un tag que empiece por v, FluxCD la detectará, y modificará el chart para que emplee la nueva imagen, tanto en el clúster como en el repositorio. Es por eso que le dimos permisos de escritura sobre el repo a la clave de SSH de FluxCD.
apiVersion: helm.fluxcd.io/v1
kind: HelmRelease
metadata:
name: helmbasic-develop
namespace: develop
annotations:
fluxcd.io/automated: "true"
filter.fluxcd.io/chart-image: glob:v*
spec:
releaseName: helmbasic-develop
chart:
git: git@github.com:yourname/helmflux
path: helmbasics
ref: develop
values:
environment: development
replicaCount: 1
ingress:
host: mywebserver.dev.kubesandclouds.com
Para reproducir este ejemplo, necesitarás un repositorio de imágenes Docker. Mi recomendación es utilizar Dockerhub, ya que solo tendrás que registrarte para poder crear tu propio repositorio y subir imágenes. Asegúrate de que el repositorio que creas es privado. Cuando se emplea un repositorio privado, es necesario especificar usuario y contraseña, para garantizar que solo los usuarios autorizados suben y descargan imágenes.
Cuando hayas creado el repositorio, puedes hacer push de la primera versión de la imagen. En este caso, será una copia de la imagen de Bitnami original sin modificaciones.
docker pull bitnami/apache:2.4.41-debian-10-r29
docker tag bitnami/apache:2.4.41-debian-10-r29 your-dockerhu-buser/your-reponame:v0.0.1
docker login docker.io
docker push your-dockerhub-user/your-reponame:v0.0.1
Una vez subida, la imagen estará disponible en el repositorio de Dockerhub. Ahora ya puedes modificar el chart para que utilice esta nueva imagen en lugar de la imagen original de Bitnami.

No obstante, antes de modificar el código y hacer que FluxCD sincronice los cambios, es necesario asegurar que el clúster tiene acceso al repositorio de imágenes privado. ¿Y cómo hacemos eso? Es sencillo, basta con crear un secret de Kubernetes de tipo docker-registry que contenga las credenciales en el namespace develop y añadirlo a la service account por defecto en el namespace. El demonio Docker corriendo en los nodos del clúster de Kubernetes utilizará estas credenciales para loguearse en el registry de Docker y descargar las imágenes.
kubectl create secret docker-registry regcred --docker-server=https://index.docker.io/v1/ --docker-username=<your-name> --docker-password=<your-pword> -n develop
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}' -n develop
FluxCD también necesita conocer este secret, para poder monitorizar cambios en el repositorio. Con siguiente comando, el deployment de FluxCD se actualiza utilizando el nombre del secret.
helm upgrade -i flux fluxcd/flux --wait --namespace fluxcd --set git.url=git@github.com:yourusername/helmflux --set image.pullSecret=regcred
Ahora puedes modificar la imagen especificada en la HelmRelease del entorno development en la rama master.

De esta manera, la nueva versión de tu HelmRelease en el entorno develop debe parecerse a la siguiente definición.
apiVersion: helm.fluxcd.io/v1
kind: HelmRelease
metadata:
name: helmbasic-develop
namespace: develop
annotations:
fluxcd.io/automated: "true"
filter.fluxcd.io/chart-image: glob:v*
spec:
releaseName: helmbasic-develop
chart:
git: git@github.com:yourname/helmflux
path: helmbasics
ref: develop
values:
environment: development
replicaCount: 1
ingress:
host: mywebserver.dev.kubesandclouds.com
image:
repository: your-dockerhub-user/your-reponame
tag: v0.0.1
Al igual que en los ejemplos anteriores, espera unos minutos a que FluxCD detecte los cambios y redespliegue el pod en el entorno development. Como puedes ver, finalmente el deployment utiliza la nueva imagen.

TRUQUILLO: Al utilizar el flag jsonpath puedes obtener los parámetros que necesites en el formato y orden que quieras. Es un poco más complejo que el clásico kubectl get pods, pero es una opción muy potente y flexible.
kubectl get pods <your-apache-podname> -n develop -o jsonpath='{ range .spec.containers[*]}{.image}{"\n"}'
Finalmente, podemos crear una nueva versión de la imagen. Digamos que necesitas añadir el comando tree para poder inspeccionar mejor los directorios del contenedor. Para hacerlo, puedes utilizar el siguiente Dockerfile.
FROM your-dockerhub-user/your-reponame:v0.0.1
CMD yum update && yum install tree -y
Construye la nueva imagen y súbela al registry de Docker para que FluxCD se encargue del trabajo sucio.
docker build . -t your-dockerhub-user/your-reponame:v0.0.2
docker push your-dockerhub-user/your-reponame:v0.0.2

Espera unos minutos hasta que el operator de FluxCD detecte la nueva imagen y podrás ver como el despliegue se actualiza con la imagen v0.0.2.

Además, FluxCD modifica automáticamente el tag de la imagen en la HelmRelease del entorno development, generando un commit identificado como 'auto-release'.

Limpiando el desastre 🧹
Una vez que hayas acabado con esta sesión de aprendizaje, puedes limpiar tu clúster utilizando los siguientes comandos. Si utilizas minikube o Docker desktop también puedes resetear el clúster.
kubectl delete hr helmbasic-develop -n develop
kubectl delete hr helmbasic-staging -n staging
kubectl delete hr helmbasic-production -n production
kubectl delete hr nginx-ingress -n ingress
kubectl delete -f https://raw.githubusercontent.com/fluxcd/helm-operator/master/deploy/crds.yaml
helm delete helmbasic-develop -n develop
helm delete helmbasic-staging -n staging
helm delete helmbasic-production -n production
helm delete nginx-ingress -n ingress
helm delete flux -n fluxcd
helm delete helm-operator -n fluxcd
kubectl delete namespaces develop staging ingress production
Conclusión
En este post, hemos analizado FluxCD como herramienta de despliegue continuo y habilitador del modelo de GitOps.
Esta herramienta permite automatizar los despliegues de Kubernetes, y permite asegurar que lo que hay corriendo en el clúster se corresponde con el contenido del repositorio de git donde se encuentran las definiciones. Además permite la posibilidad de sincronizar los despliegues cuando se construyen nuevas imágenes Docker, ideal para entornos automatizados de CI/CD.
En comparación con la primera herramienta que se analizó en la serie de posts de GitOps: ArgoCD, FluxCD ofrece una aproximación desde un punto de vista más developer y una manera descentralizada de gestionar los despliegues, siguiendo la filosofía GitOps. FluxCD se controla a través de su CLI y los custom resources. No obstante, FluxCD no ofrece un interfaz web ni un API server como ArgoCD. Además, ArgoCD proporciona una corrección de desviaciones más avanzada, así como 'self-healing' para los despliegues, pero todo ello incrementa su complejidad com herramienta.
Recuerda que FluxCD utiliza un único repositorio git para gestionar todas las releases del clúster, mientras que ArgoCD puede utilizar diferentes repositorios. Si necesitas un comportamiento similar con FluxCD, puedes considerar el empleo de submódulos de git.
FluxCD ofrece un montón de funcionalidades extra bastante interesantes, que permiten configurar la sincronización y las releases de imágenes en función de las necesidades que tengas. Si quieres conocer más a cerca de ello échale un ojo a la documentación.
Otros artículos
Karpenter vs Cluster Autoscaler ☸️ ⚒️
Getting the size of a Kubernetes cluster right is not an easy task, if the number of nodes provisioned is too high, resources might be…
Read MoreAutenticación a nivel de clúster para tus registries privados 🌐🔐
Using private container image registries is a common practice in the industry, as it ensures applications packaged within the images are just accessible for users…
Read MoreKaniko: construyendo imágenes sin Docker🐳🔫
Building container images is a pretty common stage within the modern CI flows, in which these images are the main artifact used to distribute and…
Read MoreKubernetes en 5 Minutos ⏱️☸️
English https://www.youtube.com/watch?v=N8LDO9pHY8I Spanish https://www.youtube.com/watch?v=TC6VkqQ835U Other Articles
Read MoreKsniff: capturando tráfico en Kubernetes 🕵️♂️📦
Troubleshooting containers in Kubernetes is a recurring topic that you may face regularly. Logging and monitoring tools come in really handy here as they help…
Read MoreHelmfile: superpoderes para Helm ☸️🔧
Helm is definitely one the most used tools in the Kubernetes world. It comes in pretty handy as it is a deployment tool, a package…
Read MoreTerraboard: Gestionando estados de Terrafom visualmente🌍🖥
Dealing with multiple terraform remote states can become a rather complex task. Besides, querying resources with terraform CLI isn’t very visual 😅. In this post…
Read Moreeksctl: el CLI para EKS ☸️ 🎮
Let’s be honest, managing Kubernetes clusters is not an easy task, even when it comes to managed Kubernetes services. Controlling the overall infrastructure, performing cluster…
Read MoreWerf: GitOps totalmente customizable 🛥️⚙️
This is the third post of a collection of GitOps tools articles. In this post, a continuous integration and continuous deployment tool for Kubernetes is…
Read More