Skip to content

Kubernetes

Cuando se trata de contenedores normalmente se comienza pensando en Docker, pero cuando se pasa a un nivel empresarial, conocido como la nube nativa (Cloud Native), se habla de orquestación y allí aparece Kubernetes, es decir, esta tecnología nos ofrece orquestación de contenedores de modo estandarizado cuando se trata de micro-servicios.

Elementos a considerar en Kubernetes

  1. Cluster: Es el grupo de instancias en Kubernetes. Lo primero que creas para trabajar con Kubernetes es un Cluster

  2. Master Node: Node principal con panel de control y procesos de administración del Cluster, entre ellos un servidor de API (API Server), un gestor de control (Controller Manager), un agendador (Scheduler) y una base de datos interna (etcd)

  3. Woker Nodes: Nodos donde se reliza el trabajo

  4. Control Plane: Orquestador de los nodos. Expone la API gestiona estado del Cluster

  5. Kubelet: Proceso que corre en los nodos (workers) en función de la comunicación y algunas tareas entre esos nodos

  6. API Server: Es parte del nodo maestro y sirve de punto de entrada (Entrypoint) como interfaz de programación de aplicaciones (API), en el nodo maestro, y puede usarse también con una interfaz de usuario (UI/Dashboard) o desde interfaz de linea de comandos (CLI)

  7. Controller Manager: Es parte del nodo maestro y monitorea lo que sucede en el Cluster, por ejemplo, para deemrinar si debe reiniciar un contenedor

  8. Scheduler: Es parte del nodo maestro y es responsable de las tareas programadas para lanzar contenedores (Pod) en diferentes nodos (decidiendo el Nodo correspondiente)

  9. etcd: Base de datos de clave valor para gestionar información de configuración y estado del Cluster

  10. Virtual Network: Permite la comunicación entre nodo maestro y los demás nodos

  11. Pod: Componente dentro de un Nodo que contiene la instancia de contenedor (o su abstracción) en el contexto de Kubernetes. Eventualmente, puede ser una instancia para la app y otra para algún tipo de gestor de la maya, o simplemente un contenedor. Cada unidad de contenedores (Pod) tiene una dirección IP en la red virtual de Kubernetes

  12. Service: Componente que básicamente se refiere a una IP fija dentro de la red virtual de Kubernetes, la cual se asigna a cada Pod para su comunicación

  13. Ingress: Componente que permite enrutamiento de tráfico y/o reenvio (forward) a un servicio dentro del Cluster. Es el punto de entrada (entrypoint)

  14. ConfigMap: Mecanismo en Kubernetes para almacenar y configurar parámetros externos

  15. Secret: Mecanismo en Kubernetes para almacenar información sensible externa como credenciales y/o llaves de certificados

  16. Volume: Componente que se refiere al almacenamiento físico cuando un Pod requiere persistencia de datos o uso de disco duro (ej. bases de datos o archivos de contenido). Los volúmenes son una refereca externa al Cluster

  17. Deployment: Componente o mecanismo de replicación con la prescripción y asbstracción de despliegue de Pods. En Kubernetes no se remite directamente al contenedor o Pod sino que se crean Deployments

  18. StatefulSet: Componente o mecanismo de replicación semejante al Deployment pero usado específicamente para Bases de Datos

  19. Namespace: Permite organizar un suconjunto de Pods y su red de forma separada dentro del Cluster

  20. kubectl: Se refiere a la interfaz de línea de comandos (CLI) para controlar y gestionar Kubernetes

Instalando Minikube para Kubernetes

Minikube proporciona un entorno local en el que es posible operar con Kubernetes. Para instalarlo en macOS ejecutamos el siguiente comando desde una terminal:

bash
brew install minikube

Existen alternativas como k3s que pueden ser mas eficientes si usas Linux, solo que Minikube es útil para comenzar con Kubernetes

Como prerrequisito para correr Minikube, es necesario tener Docker instalado, o una máquina virtual (incuslo WSL en el caso de Windows). Por ejemplo, para macOS puede usarse Colima e iniciar el entorno ejecutando: colima start

Para iniciar Minikube se ejecuta:

bash
minikube start

Para verificar el estado del servicio instalado podemos ejecutar:

bash
minikube status
kubectl get nodes

Al instalar minikube se incluye kubectl. minikube se usaría principalmente para inciar el cluster local.
La sentencia con kubectl en realidad lista nodos pero nos brinda también un estado inicial

Instalación de entorno local para Kubernetes

Si no estas usando Kubernetes en local, para gestión remota es necesario instalar la herramienta kubectl según el sistema operativo. Por ejemplo, para macOS ejecutamos el siguiente comando desde una terminal:

bash
brew install kubectl

Comandos claves de kubectl

Partiendo de que se ha creado un Cluster y se desea gestionar algún Pod, podemos citar la siguinte tabla de sentencias kubectl...

SentenciaDescripción
kubectl versionUtil para verificar versión de CLI o si está instalada
kubectl get allVisualiza el estado de todos los recursos
kubectl get podsVisualiza lista de Pods. Para ver Pods del sistema se usa: kubectl get pods -n kube-system
kubectl top podsMuestra el uso de recursos de los Pods
kubectl describe pod nameMuestra información descriptiva sobre el Pod específico: name
kubectl logs nameVisualiza trazabilidad de registros del Pod específico: name
kubectl delete pod nameReinicia un Pod específico: name
kubectl get deploymentsMuestra información de los despliegues
kubectl delete deployment nameElimina el despligue del Pod específico: name (usa este comando para eliminar el Pod definitivamente)
kubectl get servicesMuestra información de los servicios, puede abreviarse con svc
kubectl get eventsMuestra información de los eventos
kubectl get namespacesMuestra los Namespaces, puede abreviarse con ns
kubectl get configmapsMuestra la lista de parámetros o ConfigMaps. Puede abreviarse con cm y exportar con la opción: -o yaml
kubectl get secretsMuestra la lista de secretos
kubectl get nodesMuestra los Nodos respectivos
kubectl get ingressesMuestra si hay algún Ingress asociado
kubectl apply -f name.ymlActualiza el despliegue a partir de un archivo específico: name.yaml
kubectl config current-contextIdentifica y visualiza el Cluster actual

Ejemplos de algunas sentencias kubectl

Para ver los logs de un Pod debemos identificar el nombre de la instancia que se encuentre corriendo y luego mostramos el log. Por ejemplo:

bash
kubectl get pods -n namespace-apps
kubectl logs my-api-z123a -n namespace-apps --all-containers=true

En la primera sentencia se identifican las instancias de Pods (cuyos nombres varían cada vez que reinician) que pretenecen a un Namespace específico, en este caso: namespace-apps
En la segunda sentencia se muestran logs para el Pod identificado dentro del Namespace específico, en este caso my-api-z123a

Para reiniciar los servicios se puede usar un comando como el siguiente:

bash
kubectl rollout restart deployment my-api -n namespace-apps

Esta sentencia reinicia despliegues para Pods de my-api dentro del Namespace específico, en este caso namespace-apps

Para ingresar dentro de un Pod y usar sentencias podemos ejecutar un comando como el siguiente:

bash
kubectl exec -it my-api-z123a -- /bin/bash

En esta sentencia ingresamos a la línea de comandos para un Pod específico, en este caso my-api-z123a

Para ver y editar, por ejemplo, un archivo de manifiesto de parámetros (ConfigMap) usamos comandos como los siguientes:

bash
kubectl get configmap -n namespace-apps my-config -o yaml
kubectl edit configmap -n namespace-apps my-config

En la primera sentencia listamos parámetro y en la segunda los editamos.
-o yaml no permite visualizar en formato yaml un ConfigMap denominado my-config.
Para secretos usamos secrets en lugar de configmap, pero los valores usan Base64.

Para actualizar o aplicar un parámetro del manifiesto también podemos usar el archivo de manifiesto yaml respectivo, por ejemplo:

bash
kubectl apply -f my-config.yaml

Alternativas a kubectl

De manera simple, listaré algunas alternativas a kubectl para gestionar e interactuar facilmente con Kubernetes.

  • k9s: Utilidad de intetefaz de usuario desde la terminal, que invoca kubectl en el fondo, y facilita usar Kubernetes.
  • kube-prompt: Se asemeja a kubectl pero con ayudas desplegables sobre componentes disponibles.
  • web-kubectl: Permite usar comandos kubectl para acceder a un Cluster desde el navegador.
  • Lens (No Open Source): IDE gráfico para interactuar con Kubernetes con versión personal gratuita, así como de pago por usuario.
  • K8Studio (No Open Source): Gestor gráfico para Kubernetes con suscripción de pago anual por cerca de USD$ 190 (monto único/total por año).

Configurando un proyecto de ejemplo para Kubernetes

Para un ejercicio con Kubernetes debemos configurar archivos de manifiesto en formato YAML según la aplicación. Por ejemplo, podríamos tener una aplicación o servicio que consulte unos datos en MongoDB.

Creamos un archivo mongo-task.yaml para Deployment y Service, el cual tendrá un contenido como el siguiente...

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-deployment
  labels:
    app: mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
      - name: mongodb
        image: mongo:8.0
        ports:
        - containerPort: 27017
---
apiVersion: v1
kind: Service
metadata:
  name: mongo-service
spec:
  selector:
    app: mongo
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

En este archivo el valor del atributo kind (al inicio) es Deployment y se le agrega una metadata. Luego encontramos spec y dentro de este un template para la configuración de containers (Pod).
Posteriormente encontramos un separador de tres guiones (---) y una configuración con kind de tipo Service, en cuyo spec se configuran ports (puertos), asumiendo que es un servicio interno (de tipo ClusterIP por defecto)

Creamos un archivo mongo-config.yaml de tipo ConfigMap, el cual tendrá un contenido como el siguiente...

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mongo-config
data:
  mongo-url: mongo-service

En este archivo el valor del atributo kind es ConfigMap y se le agrega una metadata.
Nótese que bajo el atributo data se definen pares de clave y valor, básicamente parámetros de configuración.

Creamos un archivo mongo-secret.yaml de tipo Secret, el cual tendrá un contenido como el siguiente...

yaml
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
type: Opaque
data:
  mongo-user: dXNlcg==
  mongo-password: cGFzc3dvcmQ=

En este archivo el valor del atributo kind es Secret y se le agrega una metadata. Además, el valor de type es Opaque, usado comunmente con secretos.
Nótese que bajo el atributo data se definen pares de clave y valor sensibles, básicamente credenciales (en base64).

Modificamos el archivo mongo-task.yaml para incluir dentro de template.spec.containers.name el atributo env que hará referencia a los valores definidos en mongo-config.yaml y mongo-secret.yaml. Por ejemplo, agregamos lo siguiente:

yaml
  template:
    ...
    spec:
      containers:
      - name: mongodb
        ...
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-user
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password

Nótese que bajo el atributo env se reportan variables de entorno cuyos valores se resuelven a partir de los secretos definidos

Creamos un archivo webapp-task.yaml para Deployment y Service, el cual tendrá un contenido como el siguiente...

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-deployment
  labels:
    app: webapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: nanajanashia/k8s-demo-app:v1.0
        ports:
        - containerPort: 3000
        env:
        - name: USER_NAME
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-user
        - name: USER_PWD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password 
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: mongo-config
              key: mongo-url
---
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: NodePort
  selector:
    app: webapp
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000
      nodePort: 30100

Semejante al primer archivo, en este encontramos la definición de Deployment y Service para la aplicación web, indicando la imágen (image) del contenedor (containers), según se haya creado previamente, y las variables de entorno, así como también los ports (puertos) del servicio (con spec de tipo NodePort)

Aplicando nuestro proyecto de Kubenertes

Para lanzar el proyecto de ejemplo y crear los componentes en el Cluster, ejecutamos los comandos siguientes:

bash
kubectl apply -f mongo-config.yaml
kubectl apply -f mongo-secret.yaml
kubectl apply -f mongo-task.yaml
kubectl apply -f webapp-task.yaml
kubectl get all

Nótese que se usa el comando kubectl apply -f y primero aplicamos las definiciones o manifiestos para datos de configuraión y secretos.
El último comando nos lista componentes del Cluster

Podemos verificar también el servicio ejecutando:

bash
kubectl get svc
minikube ip

El primer comando lista los Services (Puertos de Servicios), mientras el último es usado para identificar la IP asignada a Minikube.

Ahora podemos abrir un navegador y acceder a la dirección de nuestra aplicación, según corresponda, o bien, se puede ejecutar el siguiente comando:

bash
minikube service webapp-service

Helm - el gestor de paquetes de Kubernetes

En palabras simples con Helm podemos instalar aplicaciones disponibles para Kubernetes. Para instalarlo en macOS podemos ejecutar:

bash
brew install helm

Para Linux (o WSL - Windows Subsystem for Linux) ejecutamos los siguientes comandos:

bash
curl -O https://get.helm.sh/helm-v3.17.1-linux-arm64.tar.gz
tar xvf helm-v3.17.1-linux-arm64.tar.gz
sudo mv linux-arm64/helm /usr/local/bin
helm version

Verifica la arquitectura de tu sistema y si es el caso reemplaza arm64 por amd64

Después de usar helm version, para identifiar la versión instalada, se pueden borrar los archivos de descarga, por ejemplo:

bash
rm helm-*.tar.gz
rm -rf linux-amd64

Los comandos para lograr la prueba del primer ejercicio de instalación con Helm podrían ser los siguientes:

bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install nginx bitnami/nginx

kubectl get pods
kubectl get svc nginx

kubectl get svc nginx -o jsonpath='{.spec.ports[0].nodePort}'

Helm Chart - Instalación

Con Helm Chart es posible gestionar aplicaciones disponibles para la nube nativa, en esencia se trata del gestor de paquetes para Kubernetes. Para instalar Helm Chart en Linux se puede usar el siguiente comando:

bash
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

Podemos probar usando alguna aplicación disponible, por ejemplo, para n8n podríamos ejecutar un comando como el siguiente:

bash
helm install n8n oci://8gears.container-registry.com/library/n8n --version 1.0.0