Capítulo 4. Trabajar con objetos de Kubernetes

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

No entiendo por qué la gente tiene miedo de las nuevas ideas. A mí me asustan las viejas.

John Cage

En el Capítulo 2, creaste e implementaste una aplicación en Kubernetes. En este capítulo, aprenderás sobre los objetos fundamentales de Kubernetes implicados en ese proceso: Pods, Implementaciones y Servicios. También descubrirás cómo utilizar la herramienta esencial Helm para gestionar aplicaciones en Kubernetes.

Después de seguir el ejemplo de "Ejecución de la aplicación de demostración", deberías tener una imagen de contenedor ejecutándose en el clúster de Kubernetes, pero ¿cómo funciona realmente? Bajo el capó, el comando kubectl run crea un recurso de Kubernetes llamado Implementación. ¿Qué es eso? ¿Y cómo ejecuta realmente una Implementación tu imagen de contenedor?

Implementaciones

Piensa en y recuerda cómo ejecutaste la aplicación de demostración con Docker. El comando docker container run iniciaba el contenedor y éste se ejecutaba hasta que lo matabas con docker stop.

Pero supongamos que el contenedor sale por alguna otra razón: quizá el programa se bloqueó, o hubo un error del sistema, o tu máquina se quedó sin espacio en disco, o un rayo cósmico golpeó tu CPU en el momento equivocado (poco probable, pero ocurre). Suponiendo que se trate de una aplicación de producción, eso significa que ahora tienes usuarios descontentos, hasta que alguien pueda acceder a un terminal y teclear docker container run para iniciar de nuevo el contenedor.

Es una disposición insatisfactoria. Lo que realmente quieres es una especie de programa supervisor que compruebe continuamente que el contenedor se está ejecutando y, si alguna vez se detiene, lo vuelva a poner en marcha inmediatamente. En los servidores tradicionales, puedes utilizar una herramienta como systemd, runit, o supervisord para hacerlo; Docker tiene algo parecido, y no te sorprenderá saber que Kubernetes también tiene una función de supervisor: la Implementación.

Supervisión y programación

Para cada programa que Kubernetes tiene que supervisar, crea un objeto Implementación correspondiente, que registra cierta información sobre el programa: el nombre de la imagen del contenedor, el número de réplicas que quieres ejecutar y cualquier otra cosa que necesite saber para iniciar el contenedor.

Junto con el Recurso de implementación trabaja un tipo de componente de Kubernetes llamado controlador. Los controladores son básicamente piezas de código que se ejecutan continuamente en un bucle, y vigilan los recursos de los que son responsables, asegurándose de que están presentes y funcionando. Si una Implementación determinada no está ejecutando suficientes réplicas, por la razón que sea, el controlador creará algunas nuevas. (Si por alguna razón hubiera demasiadas réplicas, el controlador cerraría las que sobraran. En cualquier caso, el controlador se asegura de que el estado real coincide con el estado deseado).

En realidad, una Implementación no gestiona las réplicas directamente: en su lugar, crea automáticamente un objeto asociado llamado ReplicaSet, que se encarga de ello. Hablaremos más sobre los ReplicaSets dentro de un momento en "ReplicaSets", pero como generalmente sólo interactúas con Implementaciones, familiaricémonos primero con ellas.

Reiniciar Contenedores

A primera vista, la forma en que se comportan las Implementaciones puede resultar un poco sorprendente. Si tu contenedor termina su trabajo y sale, la Implementación lo reiniciará. Si se bloquea, o si lo matas con una señal, o lo terminas con kubectl, la Implementación lo reiniciará. (Así es como debes pensar conceptualmente; la realidad es un poco más complicada, como veremos).

La mayoría de las aplicaciones de Kubernetes están diseñadas para funcionar durante mucho tiempo y ser fiables, por lo que este comportamiento tiene sentido: los contenedores pueden salir por todo tipo de razones y, en la mayoría de los casos, lo único que haría un operador humano es reiniciarlos, así que eso es lo que hace Kubernetes por defecto.

Es posible cambiar esta política para un contenedor individual: por ejemplo, para que no se reinicie nunca, o para que sólo se reinicie en caso de fallo, no si salió normalmente (consulta "Políticas de reinicio"). Sin embargo, el comportamiento por defecto (reiniciar siempre) suele ser lo que quieres.

El trabajo de una Implementación es vigilar sus contenedores asociados y asegurarse de que siempre se esté ejecutando el número especificado de ellos. Si hay menos, iniciará más. Si hay demasiados, terminará algunos. Esto es mucho más potente y flexible que un programa tradicional de tipo supervisor.

Creación de Implementaciones

Sigue adelante y crea una Implementación utilizando nuestra imagen de contenedor de demostración en tu entorno local Kubernetes para que podamos sumergirnos en su funcionamiento:

kubectl create deployment demo --image=cloudnatived/demo:hello
deployment.apps/demo created

Puedes ver todas las Implementaciones activas en tu espacio de nombres actual (consulta "Utilización de espacios de nombres") ejecutando el siguiente comando:

kubectl get deployments
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
demo   1/1     1            1           37s

Para obtener información más detallada sobre esta Implementación concreta, ejecuta el siguiente comando:

kubectl describe deployments/demo
Name:                   demo
Namespace:              default
...
Labels:                 app=demo
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=demo
...

Como puedes ver, hay mucha información aquí, la mayoría de la cual no es importante por ahora. Pero veamos más detenidamente la sección Pod Template:

Pod Template:
  Labels:  app=demo
  Containers:
   demo:
    Image:        cloudnatived/demo:hello
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
...

Ya sabes que una Implementación contiene la información que Kubernetes necesita para ejecutar el contenedor, y aquí la tienes. Pero, ¿qué es una Plantilla Pod? En realidad, antes de responder a eso, ¿qué es un Pod?

Vainas

Un Pod es el objeto de Kubernetes que representa un grupo de uno o más contenedores(pod es también el nombre de un grupo de ballenas, lo que encaja con el sabor vagamente marinero de las metáforas de Kubernetes).

¿Por qué una Implementación no gestiona directamente un contenedor individual? La respuesta es que a veces es necesario programar juntos un conjunto de contenedores, que se ejecutan en el mismo nodo y se comunican localmente, tal vez compartiendo almacenamiento. Aquí es donde Kubernetes empieza a ir más allá de la simple ejecución de contenedores directamente en un host utilizando algo como Docker. Gestiona combinaciones enteras de contenedores, su configuración y almacenamiento, etc. a través de un clúster de nodos.

Por ejemplo, una aplicación de blog puede tener un contenedor que sincronice el contenido con un repositorio Git, y un contenedor de servidor web NGINX que sirva el contenido del blog a los usuarios. Como comparten datos, los dos contenedores deben programarse juntos en un Pod. En la práctica, sin embargo, muchos Pods sólo tienen un contenedor, como en este caso. (Para más información, consulta "¿Qué pertenece a un Pod?").

Así, una especificación Pod(spec para abreviar) tiene una lista de containers, y en nuestro ejemplo sólo hay un contenedor, demo:

demo:
 Image:        cloudnatived/demo:hello

La especificación Image es nuestra imagen de contenedor Docker de demostración de Docker Hub, que contiene toda la información que necesita una Implementación de Kubernetes para iniciar el Pod y mantenerlo en funcionamiento.

Y éste es un punto importante. El comando kubectl create deployment en realidad no creó el Pod directamente. En lugar de eso, creó una Implementación, y luego la Implementación creó un ReplicaSet, que creó el Pod. La Implementación es una declaración del estado deseado: "Un Pod debe estar ejecutándose con el contenedor demo en su interior".

ConjuntosRéplica

Las Implementaciones no gestionan Pods directamente. Ése es el trabajo del objeto ReplicaSet.

Un ReplicaSet es responsable de un grupo de Pods idénticos, o réplicas. Si hay muy pocos (o demasiados) Pods, en comparación con la especificación, el controlador del ReplicaSet iniciará (o detendrá) algunos Pods para rectificar la situación.

Las Implementaciones, a su vez, gestionan ReplicaSets, y controlan cómo se comportan las réplicas cuando las actualizas, por ejemplo, al desplegar una nueva versión de tu aplicación (consulta "Estrategias de Implementación"). Cuando actualizas la Implementación, se crea un nuevo ReplicaSet para gestionar los nuevos Pods, y cuando finaliza la actualización, se eliminan el antiguo ReplicaSet y sus Pods.

En la Figura 4-1, cada ReplicaSet (V1, V2, V3) representa una versión diferente de la aplicación, con sus correspondientes Pods.

Diagram of a Deployment managing ReplicaSets
Figura 4-1. Implementaciones, ReplicaSets y Pods

Normalmente, no interactuarás directamente con los ReplicaSets, ya que las Implementaciones hacen el trabajo por ti, pero es útil saber qué son.

Mantener el estado deseado

Los controladores de Kubernetes comprueban continuamente el estado deseado especificado por cada recurso con el estado real del clúster, y realizan los ajustes necesarios para mantenerlos sincronizados. Este proceso se denomina bucle de reconciliación, porque hace un bucle eterno, intentando reconciliar el estado real con el estado deseado.

Por ejemplo, cuando creas por primera vez la Implementación demo, no hay ningún Pod demo en ejecución. Por tanto, Kubernetes iniciará inmediatamente el Pod necesario. Si alguna vez se detiene, Kubernetes lo iniciará de nuevo, siempre que la Implementación siga existiendo.

Vamos a comprobarlo ahora mismo eliminando el Pod manualmente. Primero, comprueba que el Pod se está ejecutando:

kubectl get pods --selector app=demo
NAME                    READY   STATUS    RESTARTS   AGE
demo-794889fc8d-5ddsg   1/1     Running   0          33s

Ten en cuenta que el nombre del Pod será único para ti. También puedes ver el ReplicaSet que creó este Pod ejecutando:

kubectl get replicaset --selector app=demo
NAME              DESIRED   CURRENT   READY   AGE
demo-794889fc8d   1         1         1       64s

¿Ves cómo el ReplicaSet tiene un ID generado aleatoriamente que coincide con la parte inicial del nombre del Pod de demostración anterior? En este ejemplo, el ReplicaSet demo-794889fc8d creó un Pod llamado demo-794889fc8d-5ddsg.

Ahora, ejecuta el siguiente comando para eliminar el Pod:

kubectl delete pods --selector app=demo
pod "demo-794889fc8d-bdbcp" deleted

Enumera de nuevo los Pods:

kubectl get pods --selector app=demo
NAME                    READY     STATUS        RESTARTS   AGE
demo-794889fc8d-qbcxm   1/1       Running       0          5s
demo-794889fc8d-bdbcp   0/1       Terminating   0          1h

Puedes ver que el Pod original se está apagando (su estado es Terminating), pero ya ha sido sustituido por un nuevo Pod, que sólo tiene cinco segundos de vida. También puedes ver que el nuevo Pod tiene el mismo ReplicaSet, demo-794889fc8d, pero un nuevo nombre de Pod único demo-794889fc8d-qbcxm. Ése es el bucle de reconciliación en funcionamiento.

Le dijiste a Kubernetes, mediante la Implementación que creaste, que el Pod demo debía ejecutar siempre una réplica. Te toma la palabra, e incluso si eliminas el Pod por tu cuenta, Kubernetes asume que debes haber cometido un error y, amablemente, inicia un nuevo Pod para sustituirlo por ti.

Cuando hayas terminado de experimentar con la Implementación, ciérrala y límpiala utilizando el comando siguiente:

kubectl delete all --selector app=demo
pod "demo-794889fc8d-qbcxm" deleted
deployment.apps "demo" deleted
replicaset.apps "demo-794889fc8d" deleted

El programador de Kubernetes

Hemos dicho cosas como que la Implementación creará Pods y Kubernetes iniciará el Pod necesario, sin explicar realmente cómo ocurre.

El programador de Kubernetes es el componente responsable de esta parte del proceso. Cuando una Implementación (a través de su ReplicaSet asociado) decide que se necesita una nueva réplica, crea un recurso Pod en la base de datos de Kubernetes. Simultáneamente, este Pod se añade a una cola, que es como la bandeja de entrada del programador.

El trabajo del programador consiste en observar su cola de Pods no programados, coger de ella el siguiente Pod y encontrar un nodo en el que ejecutarlo. Utilizará algunos criterios diferentes, incluidas las solicitudes de recursos del Pod, para elegir un nodo adecuado, suponiendo que haya uno disponible (hablaremos más sobre este proceso en el Capítulo 5).

Una vez programado el Pod en un nodo, el kubelet que se ejecuta en ese nodo lo recoge y se encarga de iniciar realmente sus contenedores (ver "Componentes de nodo").

Cuando eliminaste un Pod en "Mantener estado deseado", fue el ReplicaSet el que lo detectó e inició uno de sustitución. Sabe que en su nodo debería estar funcionando un Pod demo y, si no lo encuentra, iniciará uno. (¿Qué ocurriría si apagaras el nodo por completo? Sus Pods quedarían sin programar y volverían a la cola del programador, para ser reasignados a otros nodos).

La ingeniera de Stripe Julia Evans ha escrito una explicación deliciosamente clara de cómo funciona la programación en Kubernetes.

Manifiestos de recursos en formato YAML

Ahora que ya sabes cómo ejecutar una aplicación en Kubernetes, ¿ya está? ¿Has terminado? No del todo. Utilizar el comando kubectl create para crear una Implementación es útil, pero limitado. Supón que quieres cambiar algo de la especificación de la Implementación: el nombre de la imagen o la versión, por ejemplo. Podrías eliminar la Implementación existente (utilizando kubectl delete) y crear una nueva con los campos adecuados. Pero veamos si podemos hacerlo mejor.

Como Kubernetes es inherentemente un sistema declarativo, que reconcilia continuamente el estado real con el deseado, todo lo que tienes que hacer es cambiar el estado deseado -la especificación de Implementación- y Kubernetes hará el resto. ¿Cómo lo haces?

Los recursos son datos

Todos los recursos de Kubernetes, como Implementaciones o Pods, están representados por registros en su base de datos interna. El bucle de reconciliación vigila la base de datos para detectar cualquier cambio en esos registros, y toma las medidas oportunas. De hecho, todo lo que hace el comando kubectl create es añadir un nuevo registro en la base de datos correspondiente a una Implementación, y Kubernetes hace el resto.

Pero no necesitas utilizar kubectl create para interactuar con Kubernetes. También puedes crear y editar directamente el manifiesto del recurso (la especificación del estado deseado del recurso). Puedes (y debes) mantener el archivo de manifiesto en un sistema de control de versiones, y en lugar de ejecutar comandos imperativos para hacer cambios sobre la marcha, puedes cambiar tus archivos de manifiesto y luego decirle a Kubernetes que lea los datos actualizados.

Manifiestos de Implementación

El formato habitual de los archivos de manifiesto de Kubernetes es YAML, aunque también puede entender el formato JSON. ¿Qué aspecto tiene el manifiesto YAML de una Implementación?

Echa un vistazo a nuestro ejemplo para la aplicación de demostración(hello-k8s/k8s/deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  labels:
    app: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
        - name: demo
          image: cloudnatived/demo:hello
          ports:
          - containerPort: 8888

A primera vista, esto parece complicado, pero en su mayor parte es repetitivo. Las únicas partes interesantes son la misma información que ya has visto de varias formas: el nombre de la imagen del contenedor y el puerto. Cuando antes diste esta información a kubectl create, creó el equivalente de este manifiesto YAML entre bastidores y lo envió a Kubernetes.

Utilizar kubectl apply

Para utilizar toda la potencia de Kubernetes como sistema declarativo de infraestructura como código, envía tú mismo manifiestos YAML al clúster, utilizando el comando kubectl apply.

Pruébalo con nuestro manifiesto de Implementación de ejemplo, hello-k8s/k8s/deployment.yaml en el repositorio de demostración.1

Ejecuta los siguientes comandos en tu copia clonada del repositorio de demostración:

cd hello-k8s
kubectl apply -f k8s/deployment.yaml
deployment.apps "demo" created

Tras unos segundos, debería estar funcionando un demo Pod:

kubectl get pods --selector app=demo
NAME                   READY   STATUS    RESTARTS   AGE
demo-c77cc8d6f-nc6fm   1/1     Running   0          13s

Pero aún no hemos terminado, porque para conectarnos al Pod demo con un navegador web, vamos a crear un Servicio, que es un recurso de Kubernetes que te permite conectarte a tus Pods desplegados (hablaremos de esto más adelante).

En primer lugar, veamos qué es un Servicio y por qué lo necesitamos.

Recursos de servicio

Supongamos que quieres establecer una conexión de red con un Pod (como nuestra aplicación de ejemplo). ¿Cómo puedes hacerlo? Podrías averiguar la dirección IP del Pod y conectarte directamente a esa dirección y al número de puerto de la aplicación. Pero la dirección IP puede cambiar cuando se reinicia el Pod, así que tendrás que seguir buscándola para asegurarte de que está actualizada.

Peor aún, puede haber múltiples réplicas del Pod, cada una con direcciones diferentes. Cualquier otra aplicación que necesite contactar con el Pod tendría que mantener una lista de esas direcciones, lo que no parece una gran idea.

Afortunadamente, hay una forma mejor: un recurso de Servicio te proporciona una dirección IP o un nombre DNS únicos e invariables que se enrutarán automáticamente a cualquier Pod que coincida. Más adelante, en "Ingress", hablaremos del recurso Ingress, que permite un enrutamiento más avanzado y el uso de certificados TLS.

Pero por ahora, veamos más de cerca cómo funciona un Servicio Kubernetes.

Puedes pensar que un Servicio es como un proxy web o un equilibrador de carga, que reenvía peticiones a un conjunto de Pods backend(Figura 4-2). Sin embargo, no está restringido a los puertos web: un Servicio puede reenviar tráfico desde cualquier puerto a cualquier otro puerto, como se detalla en la parte ports de la especificación.

Diagram showing a Service forwarding traffic to Pods
Figura 4-2. Un Servicio proporciona un punto final persistente para un grupo de Pods

Aquí tienes el manifiesto YAML del Servicio de nuestra aplicación de demostración:

apiVersion: v1
kind: Service
metadata:
  name: demo
  labels:
    app: demo
spec:
  ports:
  - port: 8888
    protocol: TCP
    targetPort: 8888
  selector:
    app: demo
  type: ClusterIP

Puedes ver que se parece un poco al Recurso de implementación que mostramos antes. Sin embargo, el kind es Service, en lugar de Deployment, y el spec sólo incluye una lista de ports, además de un selector y un type.

Si te acercas un poco, puedes ver que el Servicio está reenviando su puerto 8888 al puerto 8888 del Pod:

...
ports:
- port: 8888
  protocol: TCP
  targetPort: 8888

selector es la parte que indica al Servicio cómo dirigir las solicitudes a determinados Pods. Las peticiones se reenviarán a cualquier Pod que coincida con el conjunto de etiquetas especificado; en este caso, sólo app: demo (ver "Etiquetas"). En nuestro ejemplo, sólo hay un Pod que coincide, pero si hubiera varios Pods, el Servicio enviaría cada solicitud a uno seleccionado al azar.2

En este sentido, un Servicio Kubernetes se parece un poco a un equilibrador de carga tradicional y, de hecho, tanto los Servicios como los Ingress pueden crear automáticamente equilibradores de carga en la nube (ver "Ingress").

Por ahora, lo principal que debes recordar es que una Implementación gestiona un conjunto de Pods para tu aplicación, y un Servicio te proporciona un único punto de entrada para las peticiones a esos Pods.

Sigue adelante y aplica el manifiesto ahora, para crear el Servicio:

kubectl apply -f k8s/service.yaml
service "demo" created

kubectl port-forward service/demo 9999:8888
Forwarding from 127.0.0.1:9999 -> 8888
Forwarding from [::1]:9999 -> 8888

Como antes, kubectl port-forward conectará el pod demo a un puerto de tu máquina local para que puedas conectarte a http://localhost:9999/ con tu navegador web.

Cuando estés seguro de que todo funciona correctamente, ejecuta el siguiente comando para limpiar antes de pasar a la siguiente sección:

kubectl delete -f k8s/
deployment.apps "demo" deleted
service "demo" deleted
Consejo

Puedes utilizar kubectl delete con un selector de etiquetas, como hicimos antes, para eliminar todos los recursos que coincidan con el selector (ver "Etiquetas"). Alternativamente, puedes utilizar kubectl delete -f, como aquí, con un directorio de manifiestos. Se borrarán todos los recursos descritos por los archivos de manifiestos.

Consulta del clúster con kubectl

La herramienta kubectl es la navaja suiza de Kubernetes: aplica la configuración, crea, modifica y destruye recursos, y también puede consultar el clúster para obtener información sobre los recursos que existen, así como sobre su estado.

Ya hemos visto cómo utilizar kubectl get para consultar Pods e Implementaciones. También puedes utilizarlo para ver qué nodos existen en tu clúster.

Si estás ejecutando minikube, debería tener este aspecto:

kubectl get nodes
NAME       STATUS   ROLES                  AGE   VERSION
minikube   Ready    control-plane,master   17d   v1.21.2

Si quieres ver recursos de todos los tipos, utiliza kubectl get all. (De hecho, esto no muestra literalmente todos los recursos, sólo los tipos más comunes, pero no vamos a discutirlo por ahora).

Para ver información completa sobre un Pod individual (o cualquier otro recurso), utiliza kubectl describe:

kubectl describe pod/demo-dev-6c96484c48-69vss
Name:         demo-794889fc8d-7frgb
Namespace:    default
Priority:     0
Node:         minikube/192.168.49.2
Start Time:   Mon, 02 Aug 2021 13:21:25 -0700
...
Containers:
  demo:
    Container ID:   docker://646aaf7c4baf6d...
    Image:          cloudnatived/demo:hello
...
Conditions:
  Type           Status
  Initialized    True
  Ready          True
  PodScheduled   True
...
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  1d    default-scheduler  Successfully assigned demo-dev...
  Normal  Pulling    1d    kubelet            pulling image "cloudnatived/demo...
...

En la salida del ejemplo, puedes ver que kubectl te da información básica sobre el propio contenedor, incluyendo su identificador de imagen y su estado, junto con una lista ordenada de los eventos que le han ocurrido. (Aprenderemos mucho más sobre la potencia de kubectl en el Capítulo 7.)

Llevar los recursos al siguiente nivel

Ahora ya sabes todo lo que necesitas saber para implementar aplicaciones en clusters Kubernetes utilizando manifiestos declarativos YAML. Pero hay muchas repeticiones en estos archivos: por ejemplo, has repetido varias veces el nombre demo, el selector de etiqueta app: demo y el puerto 8888.

¿No deberías poder especificar esos valores una sola vez y luego hacer referencia a ellos dondequiera que aparezcan a través de los manifiestos de Kubernetes?

Por ejemplo, sería estupendo poder definir variables llamadas algo así como container.name y container.port, y luego utilizarlas donde se necesiten en los archivos YAML. Entonces, si tuvieras que cambiar el nombre de la aplicación o el número de puerto en el que escucha, sólo tendrías que cambiarlos en un lugar, y todos los manifiestos se actualizarían automáticamente.

Afortunadamente, existe una herramienta para ello, y en la sección final de este capítulo te mostraremos un poco de lo que puede hacer.

Helm: Un gestor de paquetes Kubernetes

Un gestor de paquetes popular de para Kubernetes se llama Helm, y funciona tal y como hemos descrito en la sección anterior. Puedes utilizar la herramienta de línea de comandos helm para instalar y configurar aplicaciones (propias o ajenas), y puedes crear paquetes llamados gráficos de Helm, que especifican completamente los recursos necesarios para ejecutar la aplicación, sus dependencias y sus ajustes configurables.

Helm forma parte de la familia de proyectos de la Cloud Native Computing Foundation (véase "Cloud Native"), lo que refleja su estabilidad y amplia adopción.

Nota

Es importante darse cuenta de que un gráfico de Helm, a diferencia de los paquetes binarios de software utilizados por herramientas como APT o Yum, no incluye en realidad la propia imagen del contenedor. En su lugar, simplemente contiene metadatos sobre dónde se puede encontrar la imagen, al igual que hace una Implementación de Kubernetes.

Cuando instales el gráfico, el propio Kubernetes localizará y descargará la imagen binaria del contenedor desde el lugar que hayas especificado. De hecho, un gráfico de Helm no es más que una cómoda envoltura de los manifiestos YAML de Kubernetes.

Instalación de Helm

Sigue las instrucciones de instalación de Helm para tu sistema operativo.

Para comprobar que Helm está instalado y funcionando, ejecuta

helm version
version.BuildInfo{Version:"v3...GoVersion:"go1.16.5"}

Una vez que este comando tenga éxito, estarás listo para empezar a utilizar Helm.

Instalar un gráfico de Helm

¿Qué aspecto tendría el gráfico Helm de nuestra aplicación de demostración? En el directorio hello-helm3, verás un subdirectorio k8s, que en el ejemplo anterior (hello-k8s) sólo contenía los archivos de manifiesto de Kubernetes para implementar la aplicación. Ahora contiene un gráfico de Helm, en el directorio demo:

ls k8s/demo
Chart.yaml  production-values.yaml  staging-values.yaml  templates  values.yaml

Veremos para qué sirven todos estos archivos en "¿Qué hay dentro de un gráfico Helm?", pero por ahora, vamos a utilizar Helm para instalar la aplicación de demostración. En primer lugar, limpia los recursos de cualquier implementación anterior:

kubectl delete all --selector app=demo

A continuación, ejecuta el siguiente comando:

helm upgrade --install demo ./k8s/demo
NAME: demo
LAST DEPLOYED: Mon Aug  2 13:37:21 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

Si utilizas los comandos kubectl get deployment y kubectl get service que aprendiste antes, verás que Helm ha creado un Recurso de implementación (que inicia un Pod) y un Servicio, igual que en los ejemplos anteriores. El comando helm upgrade --install también crea un Secreto de Kubernetes con un Tipo de helm.sh/release.v1 para realizar un seguimiento de la liberación.

Gráficos, repositorios y publicaciones

Estos son los tres términos más importantes de Helm que debes conocer:

  • Un gráfico es un paquete Helm que contiene todas las definiciones de recursos necesarias para ejecutar una aplicación en Kubernetes.

  • Un repositorio es un lugar donde se pueden recopilar y compartir gráficos.

  • Una versión es una instancia concreta de un gráfico que se ejecuta en un clúster de Kubernetes.

Existen algunos paralelismos con los recursos Helm para contenedores Docker:

  • Un repositorio de Helm es un servidor donde se almacenan gráficos y se descargan desde los clientes, de forma similar a como un registro de contenedores almacena y sirve imágenes de contenedores, como Docker Hub.

  • Una publicación de Helm es cuando un gráfico se instala en un clúster, de forma muy parecida a cuando una imagen Docker publicada se lanza como un contenedor en ejecución.

Los gráficos de Helm pueden descargarse e instalarse desde servidores de repositorios, o instalarse directamente apuntando a una ruta local de un directorio que contenga los archivos YAML de Helm en el sistema de archivos.

Una carta puede instalarse muchas veces en el mismo clúster. Por ejemplo, podrías estar ejecutando varias copias del gráfico Redis para varias aplicaciones, cada una de ellas sirviendo como backend para diferentes sitios web. Cada instancia independiente del gráfico Helm es una versión distinta.

También es posible que quieras instalar de forma centralizada algo en tu clúster que utilicen todas tus aplicaciones, como Prometheus para el monitoreo centralizado, o el controlador NGINX Ingress para gestionar las peticiones web entrantes.

Listado de comunicados de Helm

Para comprobar qué versiones tienes en ejecución en cualquier momento, ejecuta helm list:

helm list
NAME  NAMESPACE REVISION  UPDATED STATUS    CHART
demo  default   1         ...     deployed  demo-1.0.1

Para ver el estado exacto de una versión concreta, ejecuta helm status seguido del nombre de la versión. Verás la misma información que cuando implementaste la versión por primera vez.

Más adelante en el libro, te mostraremos cómo construir tus propios gráficos de Helm para tus aplicaciones (consulta "¿Qué hay dentro de un gráfico de Helm?"). Por ahora, basta con que sepas que Helm es una forma práctica de instalar aplicaciones a partir de gráficos públicos.

Muchas aplicaciones populares están alojadas en varios repositorios Helm y mantenidas por los proveedores de paquetes. Puedes añadir repositorios Helm e instalar sus gráficos, y también puedes alojar y publicar tus propios gráficos de Helm para tus propias aplicaciones.

Consejo

Puedes ver muchos ejemplos de populares gráficos de Helm alojados en Artifact Hub, otro proyecto del CNCF.

Resumen

Éste es principalmente un libro sobre el uso de Kubernetes, no un libro que profundice en los detalles del funcionamiento de Kubernetes. Nuestro objetivo es mostrarte lo que Kubernetes puede hacer, y llevarte rápidamente al punto en que puedas ejecutar cargas de trabajo reales en producción. Sin embargo, es útil conocer al menos algunas de las principales piezas de la maquinaria con las que trabajarás, como los Pods y las Implementaciones. En este capítulo, hemos presentado brevemente algunas de las más importantes. También recomendamos Managing Kubernetes, Production Kubernetes y el repositorioKubernetes the Hard Way para quienes deseen familiarizarse con lo que ocurre bajo el capó.

Por fascinante que sea la tecnología para los frikis como nosotros, también nos interesa hacer cosas. Por lo tanto, no hemos cubierto exhaustivamente todos los tipos de recursos que proporciona Kubernetes, porque hay muchos, y muchos de ellos es casi seguro que no los necesitarás (al menos, no todavía).

Los puntos clave que creemos que necesitas saber ahora mismo son:

  • El Pod es la unidad fundamental de trabajo en Kubernetes, que especifica un único contenedor o grupo de contenedores comunicados que se programan juntos.

  • Una Implementación es un recurso de alto nivel de Kubernetes que gestiona de forma declarativa los Pods, desplegándolos, programándolos, actualizándolos y reiniciándolos cuando es necesario.

  • Un Servicio es el equivalente en Kubernetes de un equilibrador de carga o proxy, que dirige el tráfico a sus Pods correspondientes a través de una dirección IP o un nombre DNS únicos, conocidos y duraderos.

  • El programador de Kubernetes busca un Pod que aún no se esté ejecutando en ningún nodo, encuentra un nodo adecuado para él e indica al kubelet de ese nodo que ejecute el Pod.

  • Recursos como las Implementaciones se representan mediante registros en la base de datos interna de Kubernetes. Externamente, estos recursos pueden representarse mediante archivos de texto (conocidos como manifiestos) en formato YAML. El manifiesto es una declaración del estado deseado del recurso.

  • kubectl es la herramienta principal para interactuar con Kubernetes, permitiéndote aplicar manifiestos, consultar recursos, realizar cambios, eliminar recursos y realizar muchas otras tareas.

  • Helm es un gestor de paquetes Kubernetes. Simplifica la configuración e implementación de aplicaciones Kubernetes, permitiéndote utilizar un único conjunto de manifiestos y plantillas empaquetadas para generar archivos YAML Kubernetes parametrizados, en lugar de tener que mantener tú mismo los archivos YAML sin procesar.

1 k8s, pronunciado kates, es una abreviatura común de Kubernetes, que sigue el patrón friki de abreviar palabras como un numeral: su primera y última letra, más el número de letras intermedias(k-8-s). Véase también i18n (internacionalización), a11y (accesibilidad) y o11y (observabilidad).

2 Este es el algoritmo de equilibrio de carga por defecto; las versiones de Kubernetes 1.10+ admiten también otros algoritmos, como el de menor conexión. Para más información, consulta la documentación de Kubernetes.

Get DevOps Nativo en la Nube con Kubernetes, 2ª Edición now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.