Kubernetes (2): Helm
Hoy en día es raro gestionar recursos en kubernetes de forma manual, ya que
existe una forma de compartir grupos de recursos: Helm. Ellos lo definen como
un “gestor de paquetes”, es decir, como pip
para python o npm
para node.
Aunque aún no hemos visto cómo utilizar kubernetes, sólo los conceptos básicos sobre kubernetes. Pero para poder gestionar es necesario tener algo que gestionar, así que comenzaremos la casa por el tejado mostrando cómo se instala algo hoy en día.
En concreto mostraré lo básico para crear un paquete helm.
Instalar helm
Lo primero será descargarnos helm. Mis mecanismos favoritos son snap
o bien
descargar el binario directamente sobre ~/.local/bin
. El caso es que debe
estar en la ruta.
La versión 3 es la más actual, que es algo incompatible con la 2, así que me centraré en esta versión 3.
Así que sugiero instalarlo con:
|
|
En la documentación hay más opciones para descargarnos helm.
Creación de un paquete helm
Crear un paquete es bastante sencillo. Supongamos que vamos a crear el paquete
mi-application
:
|
|
Y ya está creado:
|
|
Contenido del directorio
Veamos lo básico del directorio:
- archivo
Chart.yaml
, que contiene el nombre y versión del paquete. - archivo
values.yaml
, con los valores por defecto. Luego lo entenderemos. - directorio
templates
, con las plantillas para generar recursos
y ya. Luego veremos algunos archivos más, pero quedémonos con esos tres importantes.
Mencionaré también que el directorio charts
es sólo para descargarse
dependencias, por lo que se gestiona de forma automática, habría que eliminarlo
de nuestro repositorio metiéndolo en el .gitignore
y podemos ignorar que está
ahí.
Archivo Chart.yaml
El contenido de este archivo tras borrar los comentarios es bastante pobre:
|
|
Con decir que apiVersion
debe ser v2
para que se reconozca como un paquete
de tipo helm 3, y que el type
puede ser application
o library
pero que el
primero puede actuar como el segundo así que en la práctica no se utiliza, creo
que lo demás es auto-explicativo o podéis entenderlo con el comentario.
Otros campos interesantes:
dependencies
, para definir dependencias de un proyecto.annotations
, clave-valor con metadatosdeprecated
, boolean indicando si el paquete está obsoleto. Suele usarse sólo para indicar los que lo están.
Si queréis verlos todos o más detalle sobre alguno, consultad el apartado The Chart.yaml File de la guía oficial.
Archivo values.yaml
Este archivo es más largo, pero veamos sólo una parte del mismo:
|
|
Como se ve, es un archivo YAML. Contiene claves y valores, y cuando tenemos una
lista vacía, es necesario inicializarla como []
.
Estos valores se utilizarán en las templates
, pero eso lo veremos luego.
Quedémonos con que podemos utilizar cualquier clave y valor, de momento.
Directorio de templates
Aquí es necesario explicar cómo funciona Helm.
Helm es un programa go, y utiliza las templates de go. Éstas se encuentran
en el directorio templates
para no despistar y sustituyen los valores de
distintas fuentes:
Release
, que describe la release misma. Contiene los siguientes campos:Release.Name
Release.Namespace
Release.IsUpgrade
Release.IsInstall
Release.Revision
Release.Service
Values
, con todo el contenido del archivovalues.yaml
Chart
, con el contenido del archivoChart.yaml
Files
, que es una api para acceder a otros archivos. Muy útil para crear ConfigMaps o Secrets.Capabilities
, con información sobre qué soporta el cluster Kubernetes actualTemplate
, con información sobre la plantilla actual, como el nombre.
Podéis verlo más en detalle en la sección Built-in Objects de la documentación oficial.
Estas fuentes se utilizan en las plantillas de la siguiente forma:
|
|
Que se sustituirá por el nombre de la release actual.
Ejemplo
Veamos un uso real investigando un archivo pequeñito, como
templates/service.yaml
:
|
|
Aunque pequeñito, es bastante matón.
Veamos primero algo sencillo, como es la clave spec.type
, con el valor {{ .Values.service.port }}
. Éste se encuentra en el archivo values.yaml
y vale
ClusterIP
, os invito a comprobarlo. Así que cuando ejecutemos helm,
reemplazará dicho valor, generando algo como:
|
|
La clave metadata.name
tiene el valor {{ include "mi-application.fullname" . }}
. Ésta es la manera de invocar una “función” en el lenguaje de plantillas de
go. Su implementación se encuentra en el archivo templates/_helpers.tpl
y
tiene esta pinta:
|
|
No es muy obvio, pero tampoco complejo de seguir. Baste decir que tenemos todas las funciones proporcionadas por el sistema estándar de templates de go y las de sprig.
Finalmente, algo muy importante es que puede haber más de un archivo
values.yaml
, y helm los mezclará todos para obtener el valor final.
Usando helm
Basta ya de teoría y vamos a la práctica. Todos los comandos los ejecutaremos
desde el directorio my-application
. Vamos a instalar nuestra aplicación en
my-application . un cluster Kubernetes. Para ello crearemos un cluster con
Kind:
|
|
Y en unos 5 minutos tendremos nuestro cluster en pie. Ahora usaremos helm para descargar las dependencias aunque no tengamos, ya que si no lo hacemos y hay dependencias fallará, por lo que no es una mala costumbre:
|
|
y ahora lo instalamos:
|
|
Siempre utilizo upgrade -i
ya que install
fallará si ya existía.
Eso mostrará esta salida, más o menos:
|
|
El final, NOTES
, es el contenido renderizado del archivo templates/NOTES.txt
de nuestro paquete.
Y podemos preguntar a Helm por el estado de nuestro paquete:
$ helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
my-application default 1 2021-12-30 08:12:57.930000745 +0100 CET deployed mi-application-0.1.0 1.16.0
o ver el estado de los pods con kubectl:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-application-mi-application-7dc8c8c7df-khx7j 0/1 Pending 0 3m52s
Depurando un paquete Helm
Si nos ponemos a crear nuestro paquete Helm tarde o temprano la liaremos parda. Así que es muy útil ver qué es lo que va a generar el paquete:
|
|
Nos mostrará todos los recursos que se van a generar en distintos documentos
YAML separados por triple guión ---
. Ejemplo:
|
|
Como vemos, los valores de .Release
se expanden a valores por defecto y no a
los definitivos.
Personalizando un paquete helm
Lo más divertido de un paquete Helm es que es personalizable. Basta con crear
un archivo values.yaml
adicional y pasárselo a upgrade
, install
o
template
para sobreescribir valores.
Por ejemplo, podemos escribir el pequeño archivo values.foo.yaml
:
|
|
Veamos dónde estaba escuchando nuestro servicio:
$ kubectl get svc my-application-mi-application
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-application-mi-application ClusterIP 10.107.195.23 <none> 80/TCP 23m
Y ahora lo instalamos con ese archivo:
|
|
Y volvemos a comprobar:
$ kubectl get svc my-application-mi-application
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-application-mi-application ClusterIP 10.107.195.23 <none> 9000/TCP 23m
Con lo que el puerto del servicio ha cambiado.
Recursos Helm
Es interesante conocer el mayor repositorio de paquetes helm, el artifacthub, donde podemos encontrar casi de todo, aunque puede que no siempre nos convenza lo que veamos.
También se pueden instalar plugins para Helm.
Cuando instalamos un paquete de la nube, primero tendremos que instalar el repositorio Helm. Por ejemplo, para instalar Grafana:
|
|
Y a continuación se puede instalar el programa:
|
|
Saber más
Recomiendo jugar un poco con helm: borrar paquetes, sobreescribir valores, …
Si ya se tienen algunos conocimientos de Kubernetes, a lo mejor el lector se siente con fuerzas para intentar instalar algo útil pero sencillo, como un Grafana como se comentó antes o un Prometheus.
En el próximo artículo veremos cómo instalar ambos, Grafana y Prometheus,
para que trabajen juntos, lo que dará pie a hablar de más usos para kubectl
,
namespaces
, …