Personaliza tus despliegues en Kubernetes con Kustomize

En estos días de fiesta, sin prisa pero sin pausa, me he montado una pequeña demo para contarte lo que es Kustomize, una herramienta que forma parte de kubectl desde la versión 1.14, que nos permite personalizar nuestros despliegues, pensando en diferentes entornos/aplicaciones, sin la necesidad de utilizar plantillas. Me han dicho que «se me da muy mal no hacer nada», así que en este artículo te cuento cómo usarlo 😃

Aplicación de ejemplo: un WordPress

Vamos a imaginar que tenemos el siguiente escenario, donde queremos desplegar un WordPress, el cual consta de un MySQL:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
        - image: mysql:5.6
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: wp_password
          ports:
            - containerPort: 3306
              name: mysql
          volumeMounts:
            - name: mysql-storage
              mountPath: /var/lib/mysql
      volumes:
        - name: mysql-storage
          emptyDir: {}

y su servicio:

apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None

y un WordPress:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  replicas: 2
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
        - image: wordpress:4.8-apache
          name: wordpress
          env:
            - name: WORDPRESS_DB_HOST
              value: wordpress-mysql
            - name: WORDPRESS_DB_PASSWORD
              value: wp_password
          ports:
            - containerPort: 80
              name: wordpress
          volumeMounts:
            - name: wordpress-storage
              mountPath: /var/www/html
      volumes:
        - name: wordpress-storage
          emptyDir: {}

y su servicio:

apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer

Ahora bien, lo que me gustaría hacer es que, sin tocar estos archivos pudiera personalizarlos, para adecuarlos al entorno donde los quiera desplegar, ya sea desarrollo, qa, producción, etcétera. De esta forma siempre tendría unos manifiestos base y otros que complementan o reemplazan de estos lo que consideremos, y justamente para eso es para lo que queremos Kustomize.

Estructura del repositorio

Para que quede lo más ordenado posible, la estructura que va a tener mi repositorio es la siguiente:

Estructura de mi repositorio kustomize-demo

Como ves, tenemos una carpeta base donde están los archivos que te acabo de mostrar, y dos carpetas, dev y prod, con las diferencias sobre la base para estos entornos.
En el directorio base, además de los despliegues y los servicios mostrados, hay un archivo adicional dentro de este llamado kustomization.yaml el cual únicamente contiene un listado de todos los recursos que debería de tener en cuenta esta herramienta:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:  
  - mysql-deployment.yaml
  - mysql-service.yaml  
  - wordpress-deployment.yaml
  - wordpress-service.yaml

La forma en la que organices tu proyecto es indiferente, ya que haces mención siempre a los archivos que están involucrados, pero a nivel visual es más sencillo tener algo de este estilo.

Personalización para dev

Ahora vamos a fijarnos en la carpeta dev donde vamos a tener, de nuevo, un archivo kustomization.yaml que en este caso tendrá lo siguiente:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: dev
commonLabels:
  env: dev
namePrefix: dev-
bases:
  - ../base
secretGenerator:
  - name: dbpassword
    literals:
      - "password=Passw0rd"
resources:
  - namespace.yaml
patchesStrategicMerge:
  - mysql-deployment-patch.yaml
  - wordpress-deployment-patch.yaml

Este se encarga de recoger todos los cambios para el entorno, que para este caso son los siguientes:

  • Gracias a la propiedad namespace estoy diciendo que, sin tocar ningún archivo base, todos los elementos que se vayan a generar estén dentro de dev. Como este es posible que no exista, en el apartado resources he añadido un YAML que lo genera.
  • También he utilizado commonLabels para añadir etiquetas comunes a todos los objetos del entorno.
  • namePrefix me permite utilizar un prefijo para todo lo que cree en este entorno (también existe nameSufix)
  • bases: se utiliza para indicar dónde están los manifiestos de partida, que son los que vamos a alterar. También se pueden utilizar URLs de repositorios git.
  • secretGenerator: me permite generar los secretos que necesito para este entorno. Aquí estoy utilizando literals pero puedes también indicar un archivo con texto plano o .env, como puedes ver en el kustomization de prod.
  • Por último, el apartado patchesStrategicMerge son el nombre de los archivos que contienen mis cambios respecto a los objetos base.

Para que este ejemplo no se haga eterno, los cambios en mysql-deployment-patch.yaml y wordpress-deployment-patch.yaml son los mismos, y es el cambio del valor de la contraseña de la base de datos por la que he generado aquí:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
spec:
  template:
    spec:      
      containers:
        - name: wordpress
          env: 
            - name: WORDPRESS_DB_HOST
              value: dev-wordpress-mysql          
            - name: WORDPRESS_DB_PASSWORD
              value: ""
              valueFrom: 
                secretKeyRef:
                  name: dbpassword
                  key: password

Como ves, la forma de definir los cambios es usando simplemente la misma estructura que ya conocemos, en este caso de un Deployment, pero sin que tengas que incluir aquellas propiedades que no quieres que cambien.

Para ver el resultado sin tener ejecutarlo sobre tu clúster puedes utilizar el siguiente comando:

kustomize build dev

Por ejemplo, en el despliegue del MySQL puedes ver todos estos cambios:

Cambios en wordpress-mysql

Si estás conforme con lo que has visto, para aplicarlos, en lugar de usar kubectl apply -f, utilizamos el siguiente comando:

kubectl apply -k dev 

Básicamente una k en lugar de una f 😊 Si ahora te fijas en el namespace dev verás que todo lo que has personalizado, incluido el propio namespace, está en su sitio:

Resultado del despliegue con Kustomize

El código del ejemplo lo tienes en mi GitHub.

¡Saludos!

logo lemoncode

 

 

Bootcamp DevOps

Si tienes ganas de meterte en el área de DevOps, formo parte del
equipo de docentes del Bootcamp DevOps Lemoncode, ¿Te animas a
aprender con nosotros?

Más Info