Kustomize to the rescue

Seguro que alguna que otra vez habéis encontrado en un recóndito lugar de Internet, esos manifiestos de Kubernetes qué tanto necesitabais para desplegar una nueva aplicación. El código se ajusta a vuestras necesidades en un 90-95%, pero necesitáis realizar algunas modificaciones, tanto generales como especificas por proyecto y/o entorno, para cumplir con los requisitos internos de la organización. ¿Qué se puede hacer en estos casos?

La solución mas evidente consiste en descargar los recursos, adaptarlos y desplegarlos, lo cual a corto plazo funciona a las mil maravillas, y si hubiera que realizar parametrizaciones siempre se podrían construir charts de Helm. Perfecto, ¿no?

En realidad no, ya que, si los fuentes originales son actualizados, ya sea para corregir errores o dar soporte a nuevas funcionalidades, habría que volver a realizar dicho proceso para todos los proyectos que los hubieran utilizado, por no hablar del grado de complejidad que podrían llegar a alcanzar los charts de Helm, dependiendo del número de modificaciones a realizar, claro está.

Cómo bien deja entrever el título, la solución pasa por Kustomize, y, cómo no podía ser de otra forma, en el presente artículo se pretende describir que es y cómo utilizarlo para dar solución al caso de uso presentado.

Caso de uso

Se dispone de un cluster vanilla de Kubernetes en el que se requiere desplegar un Nginx haciendo uso de manifiestos de Kubernetes (sin Helm), pudiendo aplicar modificaciones especificas por entorno sobre una base preestablecida.

Kustomize

Kustomize se define oficialmente como una solución para la gestión de la configuración que permite personalizar archivos YAML sin formato y sin plantillas para múltiples propósitos, dejando el YAML original intacto y utilizable como estaba.

Mas allá de que la traducción al castellano sea mas o menos acertada, la solución consiste en parchear dinamicamente los YAML originales, sin jamas llegar a modificarlos, con otros ficheros YAML que contienen los cambios a aplicar, ya sean para una organización, un proyecto o un entorno, o todos ellos en cascada. Es como generar nuevos recursos a partir de recursos, a base de aplicar dinámicamente pequeños merges sobre trozos específicos del manifiesto de Kubernetes.

En este caso, una imagen vale más que mil palabras:

   nginx/
   ├── base/
   │   ├── deployment.yaml
   │   └── service.yaml
   └── overlays/
      ├── pro/
      │   └── kustomization.yaml
      │   ├── replica_count.yaml
      └── stg/
          ├── kustomization.yaml
          └── replica_count.yaml

En la carpeta base se alojan los ficheros yaml que definen los recursos de Kubernetes, como un Deployment y un Service. Estos son los fuentes originales que posteriormente se parchean por entono y no difieren en nada de los manifiestos vanilla de Kubernetes.

A continuation se muestra el contenido del fichero deployment.yaml base encargado de desplegar el Nginx.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Más de lo mismo para el fichero service.yaml encargado de definir la política de acceso sobre el pod a desplegar.

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    run: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: nginx

Con la base preparada, es hora de trabajar sobre los cambios específicos por entorno. En este sencillo ejemplo se define un número de instancias distinto por entorno en el fichero replica_count.yaml.

En el caso de stg 2 instancias:

   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: nginx
   spec:
     replicas: 2

Mientras que para producción 3:

   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: nginx
   spec:
     replicas: 3

Como no podía ser de otra forma, en el fichero kustomization.yaml se definen los cambios a aplicar por entorno, que en este caso son los mismos. Basta con especificar la ubicación de los ficheros maestros, junto a los cambios a aplicar, bajo una estrategia de merge.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
patchesStrategicMerge:
- replica_count.yaml

Finalmente no queda mas que aplicar los cambios sobre el cluster de Kubertentes correspondiente

# STG
kustomize build ~/overlays/stg | kubectl apply -f -
# PRO
kustomize build ~/overlays/pro | kubectl apply -f -

Este ejemplo es muy muy básico y el artículo no pretende cubrir todas las opciones que brinda Kustomize, para eso existe un más que recomendado repositorio de GitHub. Lo fundamental es comprender bien la idea sobre la que se sustenta.

Kustomize VS Helm

La pregunta que todo el mundo se hace, una vez que conoce Kustomize, es si ha llegado o no el momento de jubilar Helm. Lo cierto es que, aunque tienen características comunes, son dos tecnologias distintas.

Helm es una herramienta de templating que simplifica el despliegue de aplicaciones sobre Kubernetes, incluyendo su versionado y rollback, mediante un avanzado sistema de plantillado que permite, en otros, definir bucles, condicionales o helpers que habilitan la implementación del patrón DRY (Don’t Repeat Yourself). La gran mayoría de los proyectos open source para K8s son compatibles con él.

Ahora bien, requiere instalar una herramienta externa a Kubernetes para funcionar, añade una capa de abstracción adicional a los despliegues con su correspondiente curva de aprendizaje y en caso de necesitar realizar modificaciones sobre los charts oficiales, no permite mantener intactos los fuentes base. Ademas, a medida que los charts crecen, su mantenibilidad se complica exponencialmente.

Kustomize, en cambio, es una sencilla solución nativa de Kubernetes para la gestión de la configuración que permite personalizar archivos YAML sin formato y sin plantillas para múltiples propósitos, dejando el fichero original intacto y utilizable como estaba. Se encuentra integrado con Kubectl, no requiere de herramientas externas y funciona sobre un modelo basado en herencia, lo que garantiza una mejor mantenibilidad que Helm.

Por contra, no es una herramienta que gestione per sé los despliegues, por lo que tampoco se hace cargo del versionado o rollback, no sigue el patrón DRY, teniendo que especificar los cambios en cada capa en lugar de simplemente pasar una variable, y por supuesto, no esta tan extendido como Helm, por lo que la cantidad de documentación o ejemplos disponibles es mucho menor.

Por tanto, la respuesta a la pregunta es que no, ya que ambas tecnologías pueden convivir en armonía. Puede que Kustomize se ajuste mejor en aquellos casos de uso en los que se requiera modificar los manifiestos originales de una aplicación de terceros, sin por ello renunciar a futuras actualizaciones de los mismos.

Helm en cambio puede ser ideal como herramienta con la que los desarrolladores pueden desplegar sus aplicaciones de forma sencilla, mediante un chart corporativo por ejemplo, abstrayendolos de toda la complejidad que los manifiestos de Kubernetes conllevan.

Conclusiones

En conclusión, a lo largo del artículo se ha descrito qué es y qué aporta Kustomize, acompañado de un sencillo caso de uso, así como de una comparativa con Helm.

Como todo en esta vida, y especialmente en Konami, tiene tanto sus pros como sus contras, pero lo cierto es que cada vez esta mas extendido entre los grandes proyectos open source de Kubernetes, por lo que no esta de mas conocer como funciona, no vaya a ser que se acabe convirtiendo en el estándar.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s