La Guía Definitiva de Pods y Servicios en Kubernetes

Kubernetes es una potente plataforma de orquestación de contenedores, pero para aprovechar todo su potencial, es importante comprender sus componentes principales, con los pods y servicios desempeñando roles fundamentales. En este artículo, profundizaremos en qué son y cómo trabajan juntos para exponer y gestionar el acceso a las aplicaciones que se ejecutan dentro de un clúster de Kubernetes.

¿Qué es un Pod?

Los pods son las unidades desplegables más pequeñas de computación que puedes crear y gestionar en Kubernetes.

Antes de crear un pod, revisemos los recursos de la API disponibles en tu clúster de Kubernetes; puedes usar el comando kubectl api-resources. Este comando lista los recursos de la API que son compatibles con el servidor de API de Kubernetes, incluyendo sus nombres cortos, grupos de API y si están en espacio de nombres o no. Esto es útil para comprender las capacidades de tu clúster, especialmente al trabajar con recursos personalizados o explorar nuevas características de Kubernetes. El comando kubectl explain complementa esto proporcionando información detallada sobre recursos individuales.

Creemos un archivo de configuración básico para un pod que ejecute un contenedor Nginx simple.

Crea un archivo llamado nginx-pod.yaml:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Aquí tienes una breve explicación de los términos utilizados:

  • apiVersion: v1: Especifica la versión de la API.
  • kind: Pod: Indica que esta configuración es para un pod.
  • metadata:name: El nombre del pod.
  • metadatos: etiquetas: Pares de clave-valor que se pueden utilizar para organizar y seleccionar el pod.
  • especificación:contenedores: Una lista de contenedores que se ejecutarán en el pod.
  • especificación:contenedores:nombre: El nombre del contenedor.
  • especificación:contenedores:imagen: La imagen del contenedor a utilizar (en este caso, la última imagen de Nginx).
  • especificación:contenedores:puertos: Los puertos a exponer desde el contenedor.

Usa kubectl para aplicar el archivo de configuración y crear el pod:

  • kubectl apply -f nginx-pod.yaml

Verifica el estado del pod para asegurarte de que se haya creado y esté en ejecución:

  • kubectl get pods

Deberías ver una salida similar a esta:

Shell

 

NAME         READY   STATUS    RESTARTS    AGE
nginx-pod    1/1     Running   0           10s

A continuación, elimina el pod:

  • kubectl delete pod nginx-pod

La salida debería ser similar a la siguiente:

Shell

 

kubectl get pod
No resources found in default namespace.

¿Qué es un Servicio?

Crear un servicio para un pod de Nginx en Kubernetes te permite exponer la aplicación de Nginx y hacerla accesible dentro o fuera del clúster. Aquí tienes una guía paso a paso para crear un Servicio para un pod de Nginx.

Para asegurarte de que tienes un pod de Nginx en ejecución, si aún no tienes uno, crea un archivo YAML llamado nginx-pod.yaml:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Aplica la configuración del Pod:

  • kubectl apply -f nginx-pod.yaml

Cree un archivo YAML llamado nginx-service.yaml para definir el Servicio:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
  type: ClusterIP

Aquí hay algunas cosas a tener en cuenta:

  • selector: Un selector de etiqueta para que coincida con el pod de Nginx.
  • app: nginx: Esto debería coincidir con la etiqueta en el pod de Nginx.
  • type: ClusterIP: El tipo de Servicio. ClusterIP hace que el Servicio solo sea accesible dentro del clúster. También puedes usar NodePort o LoadBalancer para exponer el Servicio externamente.

Aplica la configuración del Servicio usando kubectl:

  • kubectl apply -f nginx-service.yaml
  • kubectl get services
Shell

 

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   10.96.0.1        <none>        80/TCP    10s

Dado que el Servicio es de tipo ClusterIP, solo es accesible dentro del clúster. Para acceder desde fuera del clúster, puedes cambiar el tipo de Servicio a NodePort o LoadBalancer.

Para exponer el Servicio externamente usando NodePort, modifica el archivo nginx-service.yaml:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
      nodePort: 30007  # Specify a node port in the range 30000-32767 (optional)
  type: NodePort

Aplica la configuración actualizada del Servicio:

  • kubectl apply -f nginx-service.yaml

Ahora puedes acceder a la aplicación Nginx utilizando la dirección IP del nodo y el puerto del nodo (por ejemplo, http://<node-ip>:30007).

Pods de varios contenedores

Usar un solo contenedor por pod proporciona la máxima granularidad y desacoplamiento. Sin embargo, hay escenarios donde desplegar múltiples contenedores, a veces denominados contenedores compuestos, dentro de un solo pod es beneficioso. Estos contenedores secundarios pueden desempeñar diversos roles: manejar el registro o mejorar el contenedor primario (concepto de sidecar), actuar como proxy para sistemas externos (concepto de embajador) o modificar datos para que se ajusten a un formato externo (concepto de adaptador). Estos contenedores secundarios complementan al contenedor primario realizando tareas que este no maneja.

A continuación se muestra un ejemplo de una configuración de Pod de Kubernetes que incluye un contenedor primario ejecutando un servidor Nginx y un contenedor secundario actuando como un sidecar para manejar el registro. El contenedor sidecar utiliza un contenedor de registro simple como BusyBox para demostrar cómo puede seguir los registros de acceso de Nginx.

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-logging-sidecar
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  - name: log-sidecar
    image: busybox:latest
    command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  volumes:
  - name: shared-logs
    emptyDir: {}

A continuación, hará lo siguiente:

  • Guarde la configuración YAML en un archivo, por ejemplo, nginx-with-logging-sidecar.yaml
  • Aplique la configuración usando kubectl:kubectl apply -f nginx-with-logging-sidecar.yaml
  • Verifique que el Pod esté en ejecución: kubectl get pods
  • Revise los registros del contenedor sidecar para ver los registros de acceso de Nginx: kubectl logs -f <nombre-del-pod> -c log-sidecar.

Siguiendo estos pasos, eliminarás el Pod existente y aplicarás la nueva configuración, configurando un Pod con un contenedor Nginx y un contenedor sidecar para el registro. Esto asegurará que la nueva configuración esté activa y en funcionamiento en tu clúster de Kubernetes.

Los pods con múltiples contenedores en Kubernetes ofrecen varias ventajas, permitiendo despliegues y gestión de aplicaciones más flexibles y eficientes.

Patrones de Pods con Múltiples Contenedores

Patrón de Sidecar

Los contenedores sidecar pueden mejorar la aplicación principal al proporcionar funciones auxiliares como registro, gestión de configuración o proxy. Este patrón ayuda a extender la funcionalidad sin modificar el contenedor principal. Un contenedor sidecar puede encargarse del registro recopilando y reenviando registros desde el contenedor de la aplicación principal.

Patrón de Embajador

Los contenedores embajadores actúan como un proxy, gestionando la comunicación entre la aplicación principal y los servicios externos. Esto puede simplificar la integración y la configuración. Un contenedor embajador puede encargarse de la terminación de SSL o funciones de puerta de enlace API.

El patrón de embajador implica el uso de un contenedor sidecar para gestionar la comunicación entre la aplicación principal y los servicios externos. Este patrón puede encargarse de tareas como proxy, equilibrio de carga o gestión de conexiones seguras, abstrayendo así la complejidad del contenedor de la aplicación principal.

  • Contenedor de Aplicación Principal: Un servidor web simple que realiza solicitudes HTTP
  • Contenedor Embajador: Proxy Envoy configurado para gestionar las solicitudes a la API externa
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-ambassador
spec:
  containers:
  - name: web-app
    image: python:3.8-slim
    command: ["python", "-m", "http.server", "8000"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  - name: envoy-proxy
    image: envoyproxy/envoy:v1.18.3
    args: ["-c", "/etc/envoy/envoy.yaml"]
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  volumes:
  - name: config-volume
    configMap:
      name: envoy-config

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-config
data:
  envoy.yaml: |
    static_resources:
      listeners:
      - name: listener_0
        address:
          socket_address:
            address: 0.0.0.0
            port_value: 8080
        filter_chains:
        - filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              route_config:
                name: local_route
                virtual_hosts:
                - name: local_service
                  domains: ["*"]
                  routes:
                  - match:
                      prefix: "/"
                    route:
                      cluster: external_service
              http_filters:
              - name: envoy.filters.http.router
      clusters:
      - name: external_service
        connect_timeout: 0.25s
        type: LOGICAL_DNS
        lb_policy: ROUND_ROBIN
        load_assignment:
          cluster_name: external_service
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: api.example.com
                    port_value: 80

Este ejemplo demuestra el patrón de Embajador en Kubernetes, donde un proxy Envoy actúa como intermediario para gestionar la comunicación externa para el contenedor de la aplicación principal. Este patrón ayuda a abstraer las complejidades de la comunicación y mejora la modularidad y mantenibilidad.

Patrón Adaptador

Los contenedores de adaptador pueden modificar o transformar datos entre la aplicación principal y sistemas externos, asegurando la compatibilidad e integración. Por ejemplo, un contenedor de adaptador puede reformatear datos de registro para cumplir con los requisitos de un servicio de registro externo.

El patrón Adaptador en Kubernetes implica usar un contenedor auxiliar para transformar datos entre el contenedor de la aplicación principal y sistemas externos. Esto puede ser útil cuando la aplicación principal requiere datos en un formato específico que difiere del formato proporcionado o requerido por los sistemas externos.

Supongamos que tienes un contenedor de aplicación principal que genera registros en un formato personalizado. Necesitas enviar estos registros a un servicio de registro externo que requiere registros en un formato estándar específico. Un contenedor de adaptador puede ser utilizado para transformar los datos de registro al formato requerido antes de enviarlos al servicio externo.

  • Contenedor de Aplicación Principal: Una aplicación sencilla que escribe registros en un formato personalizado.
  • Contenedor de Adaptador: Un contenedor que lee los registros personalizados, los transforma al formato JSON y los envía a un servicio de registro externo.
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-adapter
spec:
  containers:
  - name: log-writer
    image: busybox
    command: ["sh", "-c", "while true; do echo \"$(date) - Custom log entry\" >> /var/log/custom/app.log; sleep 5; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
  - name: log-adapter
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/custom/app.log | while read line; do echo \"$(echo $line | sed 's/ - / - {\"timestamp\": \"/;s/$/\"}/')\" >> /var/log/json/app.json; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
    - name: json-logs
      mountPath: /var/log/json
  - name: log-sender
    image: busybox
    command: ["sh", "-c", "while true; do cat /var/log/json/app.json | grep -v '^$' | while read line; do echo \"Sending log to external service: $line\"; done; sleep 10; done"]
    volumeMounts:
    - name: json-logs
      mountPath: /var/log/json
  volumes:
  - name: shared-logs
    emptyDir: {}
  - name: json-logs
    emptyDir: {}

Este ejemplo demuestra el patrón Adaptador en Kubernetes, donde un contenedor adaptador transforma los datos del contenedor de la aplicación principal al formato requerido antes de enviarlo a un sistema externo. Este patrón ayuda a integrar aplicaciones con servicios externos al manejar transformaciones de formato de datos dentro del contenedor auxiliar.

Resumen

En resumen, pods:

  • Son las unidades desplegables más pequeñas en Kubernetes.
  • Representan una única instancia de un proceso en ejecución.
  • Pueden contener uno o más contenedores.

Servicios:

  • Proporcionan una dirección IP estable y un nombre DNS para acceder a los pods.
  • Permiten el equilibrio de carga entre un conjunto de pods.
  • Facilitan el descubrimiento de servicios dentro del clúster.

Source:
https://dzone.com/articles/the-ultimate-guide-to-kubernetes-pods-and-services