Una guía visual para solucionar problemas de Kubernetes

Nota. traducir: Este artículo es parte de los materiales del proyecto publicados en el dominio público. aprenderk8s, capacitando a empresas y administradores individuales para trabajar con Kubernetes. En él, Daniele Polencic, director del proyecto, comparte instrucciones visuales sobre los pasos a seguir en caso de problemas generales con las aplicaciones que se ejecutan en el clúster K8.

Una guía visual para solucionar problemas de Kubernetes

TL;DR: aquí hay un diagrama que le ayudará a depurar la implementación en Kubernetes:

Una guía visual para solucionar problemas de Kubernetes

Diagrama de flujo para buscar y corregir errores en un clúster. El original (en inglés) está disponible en (PDF) и como la imagen.

Al implementar una aplicación en Kubernetes, normalmente hay tres componentes que debes definir:

  • Despliegue - esta es una especie de receta para crear copias de la aplicación, llamadas pods;
  • Service — equilibrador de carga interno que distribuye el tráfico entre pods;
  • Ingreso — una descripción de cómo llegará el tráfico desde el mundo exterior al Servicio.

Aquí hay un resumen gráfico rápido:

1) En Kubernetes, las aplicaciones reciben tráfico del mundo exterior a través de dos capas de equilibradores de carga: interno y externo.

Una guía visual para solucionar problemas de Kubernetes

2) El equilibrador interno se llama Servicio, el externo se llama Ingreso.

Una guía visual para solucionar problemas de Kubernetes

3) La implementación crea pods y los monitorea (no se crean manualmente).

Una guía visual para solucionar problemas de Kubernetes

Supongamos que desea implementar una aplicación simple a la Hola Mundo. La configuración de YAML se verá así:

apiVersion: apps/v1
kind: Deployment # <<<
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
      labels:
        any-name: my-app
    spec:
      containers:
      - name: cont1
        image: learnk8s/app:1.0.0
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service # <<<
metadata:
  name: my-service
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    name: app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress # <<<
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
        serviceName: app
        servicePort: 80
      path: /

La definición es bastante larga y es fácil confundirse acerca de cómo se relacionan los componentes entre sí.

Por ejemplo:

  • ¿Cuándo debería utilizar el puerto 80 y cuándo debería utilizar el 8080?
  • ¿Debo crear un nuevo puerto para cada servicio para que no entren en conflicto?
  • ¿Importan los nombres de las etiquetas? ¿Deberían ser iguales en todas partes?

Antes de centrarnos en la depuración, recordemos cómo se relacionan los tres componentes entre sí. Comencemos con Implementación y Servicio.

Relación entre Despliegue y Servicio

Se sorprenderá, pero la implementación y el servicio no están relacionados de ninguna manera. En cambio, el Servicio apunta directamente a los Pods, sin pasar por la Implementación.

Por lo tanto, nos interesa cómo se relacionan los Pods y los Servicios entre sí. Tres cosas para recordar:

  1. Selector (selector) para el Servicio debe coincidir con al menos una etiqueta de Pod.
  2. targetPort debe coincidir con containerPort contenedor dentro del Pod.
  3. port El servicio puede ser cualquier cosa. Diferentes servicios pueden utilizar el mismo puerto porque tienen diferentes direcciones IP.

El siguiente diagrama representa todo lo anterior en forma gráfica:

1) Imagine que el servicio dirige el tráfico a un determinado módulo:

Una guía visual para solucionar problemas de Kubernetes

2) Al crear un pod, debes especificar containerPort por cada contenedor en vainas:

Una guía visual para solucionar problemas de Kubernetes

3) Al crear un servicio, debe especificar port и targetPort. ¿Pero cuál se utiliza para conectarse al contenedor?

Una guía visual para solucionar problemas de Kubernetes

4) Vía targetPort. debe coincidir containerPort.

Una guía visual para solucionar problemas de Kubernetes

5) Digamos que el puerto 3000 está abierto en el contenedor. Entonces el valor targetPort debería ser el mismo.

Una guía visual para solucionar problemas de Kubernetes

En el archivo YAML, etiquetas y ports / targetPort debe coincidir con:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
     labels:  # <<<
        any-name: my-app  # <<<
   spec:
      containers:
      - name: cont1
        image: learnk8s/app:1.0.0
        ports:
       - containerPort: 8080  # <<<
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
  - port: 80
   targetPort: 8080  # <<<
 selector:  # <<<
    any-name: my-app  # <<<

¿Qué pasa con la etiqueta? track: canary en la parte superior de la sección Implementación? ¿Debería coincidir?

Esta etiqueta es específica de la implementación y el servicio no la utiliza para enrutar el tráfico. En otras palabras, se puede eliminar o asignar un valor diferente.

¿Qué pasa con el selector? matchLabels?

Siempre debe coincidir con las etiquetas del Pod., ya que la implementación lo utiliza para realizar un seguimiento de los pods.

Supongamos que realizó las ediciones correctas. ¿Cómo comprobarlos?

Puede verificar la etiqueta del pod con el siguiente comando:

kubectl get pods --show-labels

O, si los pods pertenecen a varias aplicaciones:

kubectl get pods --selector any-name=my-app --show-labels

Donde any-name=my-app es una etiqueta any-name: my-app.

¿Quedan dificultades?

¡Puedes conectarte al pod! Para hacer esto necesitas usar el comando. port-forward en kubectl. Le permite conectarse al servicio y verificar la conexión.

kubectl port-forward service/<service name> 3000:80

Aquí:

  • service/<service name> - Nombre del Servicio; en nuestro caso es my-service;
  • 3000 es el puerto que debe abrirse en la computadora;
  • 80 - puerto especificado en el campo port servicio.

Si se estableció la conexión, entonces la configuración es correcta.

Si la conexión falla, hay un problema con las etiquetas o los puertos no coinciden.

Relación entre servicio e ingreso

El siguiente paso para proporcionar acceso a la aplicación implica configurar Ingress. Ingress necesita saber cómo encontrar un servicio, luego encontrar pods y dirigir el tráfico hacia ellos. Ingress encuentra el servicio requerido por nombre y puerto abierto.

En la descripción de Ingress y Service deben coincidir dos parámetros:

  1. servicePort en Ingress debe coincidir con el parámetro port en servicio;
  2. serviceName en Ingress debe coincidir con el campo name en servicio.

El siguiente diagrama resume las conexiones de los puertos:

1) Como ya sabes, el Servicio escucha a un determinado port:

Una guía visual para solucionar problemas de Kubernetes

2) El ingreso tiene un parámetro llamado servicePort:

Una guía visual para solucionar problemas de Kubernetes

3) Este parámetro (servicePort) siempre debe coincidir port en la definición del Servicio:

Una guía visual para solucionar problemas de Kubernetes

4) Si se especifica el puerto 80 en Servicio, entonces es necesario que servicePort también era igual a 80:

Una guía visual para solucionar problemas de Kubernetes

En la práctica, debes prestar atención a las siguientes líneas:

apiVersion: v1
kind: Service
metadata:
 name: my-service  # <<<
spec:
  ports:
 - port: 80  # <<<
   targetPort: 8080
  selector:
    any-name: my-app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
       serviceName: my-service  # <<<
       servicePort: 80  # <<<
     path: /

¿Cómo comprobar si Ingress se está ejecutando?

Puedes usar el método con kubectl port-forward, pero en lugar del servicio, necesita conectarse al controlador de Ingress.

Primero necesitas averiguar el nombre del pod con el controlador Ingress:

kubectl get pods --all-namespaces
NAMESPACE   NAME                              READY STATUS
kube-system coredns-5644d7b6d9-jn7cq          1/1   Running
kube-system etcd-minikube                     1/1   Running
kube-system kube-apiserver-minikube           1/1   Running
kube-system kube-controller-manager-minikube  1/1   Running
kube-system kube-proxy-zvf2h                  1/1   Running
kube-system kube-scheduler-minikube           1/1   Running
kube-system nginx-ingress-controller-6fc5bcc  1/1   Running

Busque el pod de Ingress (puede estar en un espacio de nombres diferente) y ejecute el comando describepara conocer los números de puerto:

kubectl describe pod nginx-ingress-controller-6fc5bcc 
--namespace kube-system 
 | grep Ports
Ports:         80/TCP, 443/TCP, 18080/TCP

Finalmente, conéctese al pod:

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

Ahora, cada vez que envíe una solicitud al puerto 3000 de su computadora, se reenviará al puerto 80 del pod con el controlador de Ingress. Al ir a http://localhost:3000, debería ver la página generada por la aplicación.

Resumen de puertos

Recordemos una vez más qué puertos y etiquetas deben coincidir:

  1. El selector en la definición del Servicio debe coincidir con la etiqueta del pod;
  2. targetPort en la definición el Servicio debe coincidir containerPort contenedor dentro de una vaina;
  3. port en la definición, Servicio puede ser cualquier cosa. Diferentes servicios pueden utilizar el mismo puerto porque tienen diferentes direcciones IP;
  4. servicePort El ingreso debe coincidir port en la definición de Servicio;
  5. El nombre del servicio debe coincidir con el campo. serviceName en ingreso.

Desafortunadamente, no basta con saber cómo estructurar correctamente una configuración YAML.

¿Qué pasa cuando las cosas van mal?

Es posible que el módulo no se inicie o que se bloquee.

Tres pasos para diagnosticar problemas de aplicaciones en Kubernetes

Antes de comenzar a depurar su implementación, debe comprender bien cómo funciona Kubernetes.

Dado que cada aplicación descargada en K8 tiene tres componentes, deben depurarse en un orden determinado, comenzando desde abajo.

  1. Primero debes asegurarte de que las cápsulas estén funcionando, luego...
  2. Compruebe si el servicio suministra tráfico a los pods y luego...
  3. Compruebe si Ingress está configurado correctamente.

Representación visual:

1) Deberías empezar a buscar los problemas desde abajo. Primero verifique que los pods tengan estados Ready и Running:

Una guía visual para solucionar problemas de Kubernetes

2) Si las vainas están listas (Ready), deberías averiguar si el servicio distribuye el tráfico entre pods:

Una guía visual para solucionar problemas de Kubernetes

3) Finalmente, es necesario analizar la conexión entre el servicio y el Ingress:

Una guía visual para solucionar problemas de Kubernetes

1. Diagnóstico de vainas

En la mayoría de los casos el problema está relacionado con el pod. Asegúrese de que las vainas estén enumeradas como Ready и Running. Puedes verificar esto usando el comando:

kubectl get pods
NAME                    READY STATUS            RESTARTS  AGE
app1                    0/1   ImagePullBackOff  0         47h
app2                    0/1   Error             0         47h
app3-76f9fcd46b-xbv4k   1/1   Running           1         47h

En el resultado del comando anterior, el último pod aparece como Running и Ready, sin embargo, este no es el caso de los otros dos.

¿Cómo entender qué salió mal?

Hay cuatro comandos útiles para diagnosticar pods:

  1. kubectl logs <имя pod'а> le permite extraer registros de contenedores en un pod;
  2. kubectl describe pod <имя pod'а> le permite ver una lista de eventos asociados con el pod;
  3. kubectl get pod <имя pod'а> le permite obtener la configuración YAML de un pod almacenado en Kubernetes;
  4. kubectl exec -ti <имя pod'а> bash le permite iniciar un shell de comando interactivo en uno de los contenedores del pod

¿Cuál deberías elegir?

El hecho es que no existe un mandamiento universal. Se debe utilizar una combinación de estos.

Problemas típicos de las cápsulas

Hay dos tipos principales de errores de pod: errores de inicio y errores de tiempo de ejecución.

Errores de inicio:

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • RegistryUnavailable
  • InvalidImageName

Errores de tiempo de ejecución:

  • CrashLoopBackOff
  • RunContainerError
  • KillContainerError
  • VerifyNonRootError
  • RunInitContainerError
  • CreatePodSandboxError
  • ConfigPodSandboxError
  • KillPodSandboxError
  • SetupNetworkError
  • TeardownNetworkError

Algunos errores son más comunes que otros. Estos son algunos de los errores más comunes y cómo solucionarlos.

ImagenPullBackOff

Este error ocurre cuando Kubernetes no puede obtener una imagen para uno de los contenedores del pod. Estas son las tres razones más comunes para esto:

  1. El nombre de la imagen es incorrecto; por ejemplo, cometió un error o la imagen no existe;
  2. Se especificó una etiqueta inexistente para la imagen;
  3. La imagen se almacena en un registro privado y Kubernetes no tiene permiso para acceder a ella.

Las dos primeras razones son fáciles de eliminar: simplemente corrija el nombre de la imagen y la etiqueta. En el caso de este último, debe ingresar las credenciales para el registro cerrado en Secreto y agregarle enlaces en pods. En la documentación de Kubernetes hay un ejemplo Cómo se puede hacer esto.

Desactivación del bucle de bloqueo

Kubenetes arroja un error CrashLoopBackOff, si el contenedor no puede iniciarse. Esto suele suceder cuando:

  1. Hay un error en la aplicación que impide que se inicie;
  2. envase configurado incorrectamente;
  3. La prueba de Liveness ha fallado demasiadas veces.

Debe intentar acceder a los registros del contenedor para descubrir el motivo de su falla. Si resulta difícil acceder a los registros porque el contenedor se reinicia demasiado rápido, puede utilizar el siguiente comando:

kubectl logs <pod-name> --previous

Muestra mensajes de error de la encarnación anterior del contenedor.

EjecutarContenedorError

Este error ocurre cuando el contenedor no se inicia. Corresponde al momento previo al lanzamiento de la aplicación. Suele deberse a configuraciones incorrectas, por ejemplo:

  • intentar montar un volumen inexistente como ConfigMap o Secrets;
  • un intento de montar un volumen de solo lectura como lectura-escritura.

El equipo está bien preparado para analizar este tipo de errores. kubectl describe pod <pod-name>.

Los pods están en estado Pendiente

Una vez creado, el pod permanece en el estado Pending.

¿Por qué está pasando esto?

Estas son las posibles razones (supongo que el programador funciona bien):

  1. El clúster no tiene suficientes recursos, como potencia de procesamiento y memoria, para ejecutar el pod.
  2. El objeto se instala en el espacio de nombres apropiado. ResourceQuota y la creación de un pod hará que el espacio de nombres supere la cuota.
  3. El pod está vinculado a Pendiente PersistentVolumeClaim.

En este caso, se recomienda utilizar el comando kubectl describe y revisa la sección Events:

kubectl describe pod <pod name>

En caso de errores relacionados con ResourceQuotas, se recomienda ver los registros del clúster usando el comando

kubectl get events --sort-by=.metadata.creationTimestamp

Las cápsulas no están listas

Si pod aparece como Running, pero no está en estado Ready, significa comprobar su preparación (sonda de preparación) falla.

Cuando esto sucede, el pod no se conecta al servicio y no fluye tráfico hacia él. El error en la prueba de preparación se debe a problemas en la aplicación. En este caso, para encontrar el error es necesario analizar la sección. Events en la salida del comando kubectl describe.

2. Diagnóstico de servicio

Si las vainas aparecen como Running и Ready, pero aún no hay respuesta de la aplicación, debes verificar la configuración del servicio.

Los servicios son responsables de enrutar el tráfico a los pods según sus etiquetas. Por tanto, lo primero que debes hacer es comprobar cuántos pods funcionan con el servicio. Para hacer esto, puede verificar los puntos finales en el servicio:

kubectl describe service <service-name> | grep Endpoints

El punto final es un par de valores de la forma <IP-адрес:порт>y al menos uno de esos pares debe estar presente en la salida (es decir, al menos un pod funciona con el servicio).

si seccion Endpoins vacío, son posibles dos opciones:

  1. no hay pods con la etiqueta correcta (sugerencia: verifique si el espacio de nombres está seleccionado correctamente);
  2. Hay un error en las etiquetas de servicios en el selector.

Si ve una lista de puntos finales pero aún no puede acceder a la aplicación, entonces el probable culpable es un error en targetPort en la descripción del servicio.

¿Cómo comprobar la funcionalidad del servicio?

Independientemente del tipo de servicio, puede utilizar el comando kubectl port-forward para conectarse a él:

kubectl port-forward service/<service-name> 3000:80

Aquí:

  • <service-name> - Nombre del Servicio;
  • 3000 es el puerto que abres en la computadora;
  • 80 - puerto en el lado de servicio.

3. Diagnóstico de ingreso

Si has leído hasta aquí, entonces:

  • las vainas se enumeran como Running и Ready;
  • el servicio distribuye con éxito el tráfico entre pods.

Sin embargo, todavía no puedes acceder a la aplicación.

Esto significa que lo más probable es que el controlador Ingress no esté configurado correctamente. Dado que el controlador de Ingress es un componente de terceros en el clúster, existen diferentes métodos de depuración según su tipo.

Pero antes de recurrir al uso de herramientas especiales para configurar Ingress, puedes hacer algo muy simple. Usos de ingreso serviceName и servicePort para conectarse al servicio. Debe verificar si están configurados correctamente. Puedes hacer esto usando el comando:

kubectl describe ingress <ingress-name>

Si columna Backend vacío, existe una alta probabilidad de que se produzca un error de configuración. Si los servidores están instalados, pero aún no se puede acceder a la aplicación, entonces el problema puede estar relacionado con:

  • Ingrese a la configuración de accesibilidad desde la Internet pública;
  • configuración de accesibilidad del clúster desde la Internet pública.

Puede identificar problemas con la infraestructura conectándose directamente al pod de Ingress. Para hacer esto, primero busque el pod del controlador de ingreso (puede estar en un espacio de nombres diferente):

kubectl get pods --all-namespaces
NAMESPACE   NAME                              READY STATUS
kube-system coredns-5644d7b6d9-jn7cq          1/1   Running
kube-system etcd-minikube                     1/1   Running
kube-system kube-apiserver-minikube           1/1   Running
kube-system kube-controller-manager-minikube  1/1   Running
kube-system kube-proxy-zvf2h                  1/1   Running
kube-system kube-scheduler-minikube           1/1   Running
kube-system nginx-ingress-controller-6fc5bcc  1/1   Running

usa el comando describepara configurar el puerto:

kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system 
 | grep Ports

Finalmente, conéctese al pod:

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

Ahora todas las solicitudes al puerto 3000 de la computadora se redirigirán al puerto 80 del pod.

¿Funciona ahora?

  • En caso afirmativo, entonces el problema está en la infraestructura. Es necesario saber exactamente cómo se dirige el tráfico al clúster.
  • Si no, entonces el problema está en el controlador de Ingress.

Si no puedes hacer que el controlador Ingress funcione, tendrás que depurarlo.

Hay muchas variedades de controladores Ingress. Los más populares son Nginx, HAProxy, Traefik, etc. (para obtener más información sobre las soluciones existentes, consulte nuestra reseña - aprox. trad.) Debe consultar la guía de solución de problemas en la documentación del controlador correspondiente. Porque el Ingreso Nginx es el controlador Ingress más popular, hemos incluido algunos consejos en el artículo para resolver problemas relacionados con él.

Depuración del controlador Ingress Nginx

El proyecto Ingress-nginx tiene un oficial complemento para kubectl. Equipo kubectl ingress-nginx se puede usar para:

  • análisis de logs, backends, certificados, etc.;
  • conexiones con Ingress;
  • estudiando la configuración actual.

Los siguientes tres comandos te ayudarán con esto:

  • kubectl ingress-nginx lint - cheques nginx.conf;
  • kubectl ingress-nginx backend — explora el backend (similar a kubectl describe ingress <ingress-name>);
  • kubectl ingress-nginx logs — revisa los registros.

Tenga en cuenta que en algunos casos es posible que necesite especificar el espacio de nombres correcto para el controlador de Ingress usando la bandera --namespace <name>.

Resumen

Solucionar problemas de Kubernetes puede ser un desafío si no sabes por dónde empezar. Siempre debes abordar el problema desde abajo hacia arriba: comenzar con los pods y luego pasar al servicio e Ingress. Las técnicas de depuración descritas en este artículo se pueden aplicar a otros objetos, como:

  • Trabajos inactivos y CronJobs;
  • StatefulSets y DaemonSets.

expreso mi gratitud Gergely Risko, Daniel Weibel и Charles Christyraj por valiosos comentarios y adiciones.

PD del traductor

Lea también en nuestro blog:

Fuente: habr.com

Añadir un comentario