Unha guía visual para solucionar problemas de Kubernetes

Nota. transl.: Este artigo forma parte dos materiais do proxecto publicados no dominio público aprender8s, adestrando empresas e administradores individuais para traballar con Kubernetes. Nela, Daniele Polencic, xefe de proxecto, comparte instrucións visuais sobre os pasos a seguir en caso de problemas xerais coas aplicacións que se executan no clúster K8s.

Unha guía visual para solucionar problemas de Kubernetes

TL;DR: aquí tes un diagrama que che axudará a depurar a implementación en Kubernetes:

Unha guía visual para solucionar problemas de Kubernetes

Diagrama de fluxo para atopar e corrixir erros nun clúster. O orixinal (en inglés) está dispoñible en PDF и como imaxe.

Ao implementar unha aplicación en Kubernetes, normalmente hai tres compoñentes que debes definir:

  • desenvolvemento - esta é unha especie de receita para crear copias dunha aplicación, chamada pods;
  • servizo — equilibrador de carga interno que distribúe o tráfico entre os pods;
  • Ingreso — unha descrición de como chegará o tráfico do mundo exterior ao Servizo.

Aquí tes un resumo gráfico rápido:

1) En Kubernetes, as aplicacións reciben tráfico do mundo exterior a través de dúas capas de equilibradores de carga: interna e externa.

Unha guía visual para solucionar problemas de Kubernetes

2) O equilibrador interno chámase Servizo, o externo chámase Ingress.

Unha guía visual para solucionar problemas de Kubernetes

3) O despregamento crea pods e monitorízaos (non se crean manualmente).

Unha guía visual para solucionar problemas de Kubernetes

Digamos que quere implementar unha aplicación sinxela ao mesmo tempo Ola mundo. A configuración de YAML para el será 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: /

A definición é bastante longa e é fácil confundirse sobre como se relacionan os compoñentes entre si.

Por exemplo:

  • Cando deberías usar o porto 80 e cando deberías usar o 8080?
  • Debo crear un novo porto para cada servizo para que non entren en conflito?
  • Importan os nomes das etiquetas? Deberían ser iguais en todas partes?

Antes de centrarnos na depuración, lembremos como se relacionan os tres compoñentes entre si. Comecemos coa implementación e o servizo.

Relación entre implantación e servizo

Sorprenderás, pero as implantacións e os servizos non están conectados de ningún xeito. Pola contra, o servizo apunta directamente a Pods, evitando a implantación.

Polo tanto, interésanos saber como os Pods e os Servizos están relacionados entre si. Tres cousas para lembrar:

  1. Selector (selector) para o servizo debe coincidir polo menos cunha etiqueta Pod.
  2. targetPort debe corresponder containerPort recipiente dentro do Pod.
  3. port O servizo pode ser calquera cousa. Diferentes servizos poden usar o mesmo porto porque teñen enderezos IP diferentes.

O seguinte diagrama representa todo o anterior en forma gráfica:

1) Imaxina que o servizo dirixe o tráfico a un determinado pod:

Unha guía visual para solucionar problemas de Kubernetes

2) Ao crear un pod, debes especificalo containerPort para cada recipiente en vainas:

Unha guía visual para solucionar problemas de Kubernetes

3) Ao crear un servizo, debes especificalo port и targetPort. Pero cal se usa para conectarse ao contedor?

Unha guía visual para solucionar problemas de Kubernetes

4) Vía targetPort. Debe coincidir containerPort.

Unha guía visual para solucionar problemas de Kubernetes

5) Digamos que o porto 3000 está aberto no contedor, entón o valor targetPort debería ser o mesmo.

Unha guía visual para solucionar problemas de Kubernetes

No ficheiro YAML, etiquetas e ports / targetPort debe corresponder:

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  # <<<

Que pasa coa etiqueta track: canary na parte superior da sección de Implementación? Debería coincidir?

Esta etiqueta é específica da implementación e o servizo non a utiliza para enrutar o tráfico. Noutras palabras, pódese eliminar ou asignarlle un valor diferente.

E o selector matchLabels?

Sempre debe coincidir coas etiquetas do Pod, xa que Deployment o usa para rastrexar pods.

Supoñamos que fixeches as edicións correctas. Como verificalos?

Podes comprobar a etiqueta do pod co seguinte comando:

kubectl get pods --show-labels

Ou, se os pods pertencen a varias aplicacións:

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

Onde any-name=my-app é unha etiqueta any-name: my-app.

Quedan dificultades?

Podes conectarte ao pod! Para iso cómpre usar o comando port-forward en kubectl. Permítelle conectarse ao servizo e comprobar a conexión.

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

Aquí:

  • service/<service name> - nome do servizo; no noso caso é my-service;
  • 3000 é o porto que hai que abrir no ordenador;
  • 80 - porto especificado no campo port servizo

Se se estableceu a conexión, a configuración é correcta.

Se a conexión falla, hai un problema coas etiquetas ou os portos non coinciden.

Relación entre o servizo e a entrada

O seguinte paso para proporcionar acceso á aplicación está relacionado coa configuración de Ingress. Ingress necesita saber como atopar un servizo, despois atopar pods e dirixir o tráfico a eles. Ingress atopa o servizo necesario por nome e porto aberto.

Na descrición de Ingress e Service, dous parámetros deben coincidir:

  1. servicePort en Ingress debe coincidir co parámetro port en Servizo;
  2. serviceName en Ingress debe coincidir co campo name en Servizo.

O seguinte diagrama resume as conexións dos portos:

1) Como xa sabes, Service escoita un certo port:

Unha guía visual para solucionar problemas de Kubernetes

2) Ingress ten un parámetro chamado servicePort:

Unha guía visual para solucionar problemas de Kubernetes

3) Este parámetro (servicePort) deben coincidir sempre port na definición do servizo:

Unha guía visual para solucionar problemas de Kubernetes

4) Se se especifica o porto 80 en Servizo, entón é necesario que servicePort tamén era igual a 80:

Unha guía visual para solucionar problemas de Kubernetes

Na práctica, cómpre prestar atención ás seguintes liñas:

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: /

Como comprobar se Ingress está funcionando?

Podes usar o método con kubectl port-forward, pero en lugar do servizo, cómpre conectarse ao controlador Ingress.

Primeiro debes descubrir o nome do pod co 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

Busca o pod Ingress (pode estar nun espazo de nomes diferente) e executa o comando describepara saber os números de porto:

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

Finalmente, conéctate ao pod:

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

Agora cada vez que envíes unha solicitude ao porto 3000 do teu ordenador, reenviarase ao porto 80 do pod co controlador Ingress. Ao ir a http://localhost:3000, deberías ver a páxina xerada pola aplicación.

Resumo dos portos

Lembremos unha vez máis que portos e etiquetas deben coincidir:

  1. O selector da definición do servizo debe coincidir coa etiqueta do pod;
  2. targetPort na definición O servizo debe coincidir containerPort recipiente dentro da vaina;
  3. port na definición Servizo pode ser calquera cousa. Distintos servizos poden usar o mesmo porto porque teñen diferentes enderezos IP;
  4. servicePort A entrada debe coincidir port na definición de Servizo;
  5. O nome do servizo debe coincidir co campo serviceName en Ingress.

Desafortunadamente, non é suficiente saber como estruturar correctamente unha configuración YAML.

Que pasa cando as cousas van mal?

É posible que o pod non se inicie ou que se bloquee.

3 pasos para diagnosticar problemas de aplicación en Kubernetes

Antes de comezar a depurar a súa implementación, debes ter unha boa comprensión de como funciona Kubernetes.

Dado que cada aplicación descargada en K8s ten tres compoñentes, deberían ser depurados nunha determinada orde, comezando dende a parte inferior.

  1. Primeiro debes asegurarte de que as vainas funcionan, despois...
  2. Comproba se o servizo proporciona tráfico aos pods e despois...
  3. Comproba se Ingress está configurado correctamente.

Representación visual:

1) Deberías comezar a buscar problemas desde abaixo. Primeiro comproba que as vainas teñen estados Ready и Running:

Unha guía visual para solucionar problemas de Kubernetes

2) Se as vainas están listas (Ready), deberías averiguar se o servizo distribúe o tráfico entre pods:

Unha guía visual para solucionar problemas de Kubernetes

3) Finalmente, cómpre analizar a conexión entre o servizo e o Ingress:

Unha guía visual para solucionar problemas de Kubernetes

1. Diagnóstico de vainas

Na maioría dos casos, o problema está relacionado coa pod. Asegúrese de que as vainas estean listadas como Ready и Running. Podes comprobar isto usando o 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

Na saída do comando anterior, o último pod aparece como Running и Ready, porén, este non é o caso dos outros dous.

Como entender o que pasou mal?

Hai catro comandos útiles para diagnosticar pods:

  1. kubectl logs <имя pod'а> permítelle extraer rexistros dos recipientes dunha vaina;
  2. kubectl describe pod <имя pod'а> permítelle ver unha lista de eventos asociados ao pod;
  3. kubectl get pod <имя pod'а> permítelle obter a configuración YAML dun pod almacenado en Kubernetes;
  4. kubectl exec -ti <имя pod'а> bash permítelle lanzar un shell de comandos interactivo nun dos contenedores de vainas

Cal debes escoller?

O caso é que non existe un comando universal. Debe usarse unha combinación destes.

Problemas típicos de pod

Hai dous tipos principais de erros de pod: erros de inicio e erros de execución.

Erros de inicio:

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

Erros de execución:

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

Algúns erros son máis comúns que outros. Aquí tes algúns dos erros máis comúns e como solucionalos.

ImagePullBackOff

Este erro aparece cando Kubernetes non pode obter unha imaxe para un dos contedores de vainas. Aquí están as tres razóns máis comúns para iso:

  1. O nome da imaxe é incorrecto; por exemplo, cometeches un erro nela ou a imaxe non existe;
  2. Especificouse unha etiqueta inexistente para a imaxe;
  3. A imaxe gárdase nun rexistro privado e Kubernetes non ten permiso para acceder a ela.

As dúas primeiras razóns son fáciles de eliminar: só tes que corrixir o nome e a etiqueta da imaxe. No caso deste último, cómpre introducir as credenciais para o rexistro pechado en Segredo e engadir ligazóns a el en pods. Na documentación de Kubernetes hai un exemplo como se pode facer isto.

Desactivación do bucle de accidente

Kubenetes arroxa un erro CrashLoopBackOff, se o recipiente non pode comezar. Isto adoita ocorrer cando:

  1. Hai un erro na aplicación que impide que se inicie;
  2. Recipiente configurado incorrectamente;
  3. A proba de Liveness fallou demasiadas veces.

Debes tentar chegar aos rexistros desde o contedor para descubrir o motivo do seu fallo. Se é difícil acceder aos rexistros porque o contedor se reinicia demasiado rápido, pode usar o seguinte comando:

kubectl logs <pod-name> --previous

Mostra mensaxes de erro da encarnación anterior do contedor.

RunContainerError

Este erro ocorre cando o contedor non se inicia. Corresponde ao momento anterior ao lanzamento da aplicación. Normalmente é causado por configuracións incorrectas, por exemplo:

  • tentando montar un volume inexistente como ConfigMap ou Secrets;
  • un intento de montar un volume de só lectura como lectura-escritura.

O equipo é moi axeitado para analizar tales erros kubectl describe pod <pod-name>.

Os pods están en estado Pendente

Unha vez creada, a vaina permanece no estado Pending.

Por que isto ocorre?

Aquí están os posibles motivos (supoño que o programador funciona ben):

  1. O clúster non ten recursos suficientes, como potencia de procesamento e memoria, para executar o pod.
  2. O obxecto está instalado no espazo de nomes axeitado ResourceQuota e crear un pod fará que o espazo de nomes vaia máis alá da cota.
  3. O pod está vinculado a Pendente PersistentVolumeClaim.

Neste caso, recoméndase usar o comando kubectl describe e revisa a sección Events:

kubectl describe pod <pod name>

En caso de erros relacionados con ResourceQuotas, recoméndase ver os rexistros do clúster mediante o comando

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

As vainas non están listas

Se pod aparece como Running, pero non está nun estado Ready, significa comprobar a súa preparación (sonda de preparación) falla.

Cando isto ocorre, o pod non se conecta ao servizo e non circula ningún tráfico. O fallo da proba de preparación é causado por problemas na aplicación. Neste caso, para atopar o erro, cómpre analizar a sección Events na saída do comando kubectl describe.

2. Diagnóstico do servizo

Se as vainas están listadas como Running и Ready, pero aínda non hai resposta da aplicación, debes comprobar a configuración do servizo.

Os servizos encárganse de dirixir o tráfico aos pods dependendo das súas etiquetas. Polo tanto, o primeiro que debes facer é comprobar cantos pods funcionan co servizo. Para iso, pode comprobar os puntos finais do servizo:

kubectl describe service <service-name> | grep Endpoints

O punto final é un par de valores do formulario <IP-адрес:порт>, e polo menos un destes pares debe estar presente na saída (é dicir, polo menos un pod funciona co servizo).

Se sección Endpoins baleiro, son posibles dúas opcións:

  1. non hai pods coa etiqueta correcta (suxestión: comprobe se o espazo de nomes está seleccionado correctamente);
  2. Hai un erro nas etiquetas do servizo do selector.

Se ves unha lista de puntos finais pero aínda non podes acceder á aplicación, entón o probable culpable é un erro targetPort na descrición do servizo.

Como comprobar a funcionalidade do servizo?

Independentemente do tipo de servizo, podes usar o comando kubectl port-forward para conectar con el:

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

Aquí:

  • <service-name> - nome do servizo;
  • 3000 é o porto que abres no ordenador;
  • 80 - porto no lado de servizo.

3. Diagnóstico de entrada

Se liches ata aquí, entón:

  • as vainas están listadas como Running и Ready;
  • o servizo distribúe correctamente o tráfico entre os pods.

Non obstante, aínda non podes acceder á aplicación.

Isto significa que o controlador Ingress probablemente non estea configurado correctamente. Dado que o controlador Ingress é un compoñente de terceiros no clúster, hai diferentes métodos de depuración dependendo do seu tipo.

Pero antes de recorrer a usar ferramentas especiais para configurar Ingress, podes facer algo moi sinxelo. Usos de entrada serviceName и servicePort para conectarse ao servizo. Debe comprobar se están configurados correctamente. Podes facelo usando o comando:

kubectl describe ingress <ingress-name>

Se columna Backend baleiro, hai unha alta probabilidade de erro de configuración. Se os backends están no seu lugar, pero aínda non se pode acceder á aplicación, entón o problema pode estar relacionado con:

  • Entrar a configuración de accesibilidade desde a Internet pública;
  • configuración de accesibilidade do clúster desde Internet pública.

Podes identificar problemas coa infraestrutura conectándote directamente ao pod de Ingress. Para facelo, primeiro busque o pod do controlador de entrada (pode estar nun espazo de nomes 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

Use o comando describepara configurar o porto:

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

Finalmente, conéctate ao pod:

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

Agora todas as solicitudes ao porto 3000 do ordenador serán redirixidas ao porto 80 do pod.

Funciona agora?

  • Se si, entón o problema está na infraestrutura. É necesario descubrir exactamente como se dirixe o tráfico ao clúster.
  • Se non, entón o problema é co controlador de entrada.

Se non podes facer que o controlador Ingress funcione, terás que depuralo.

Hai moitas variedades de controladores de entrada. Os máis populares son Nginx, HAProxy, Traefik, etc. (para obter máis información sobre as solucións existentes, consulte a nosa revisión - aprox. transl.) Debería consultar a guía de solución de problemas na documentación do controlador correspondente. Porque o Entrada Nginx é o controlador Ingress máis popular, incluímos no artigo algúns consellos para resolver problemas relacionados con el.

Depurando o controlador Ingress Nginx

O proxecto Ingress-nginx ten un oficial plugin para kubectl. Equipo kubectl ingress-nginx pódese usar para:

  • análise de rexistros, backends, certificados, etc.;
  • conexións a Ingress;
  • estudando a configuración actual.

Os seguintes tres comandos axudarán con isto:

  • kubectl ingress-nginx lint - cheques nginx.conf;
  • kubectl ingress-nginx backend — explora o backend (semellante a kubectl describe ingress <ingress-name>);
  • kubectl ingress-nginx logs - comproba os rexistros.

Teña en conta que, nalgúns casos, pode ter que especificar o espazo de nomes correcto para o controlador Ingress usando a marca --namespace <name>.

Resumo

A resolución de problemas de Kubernetes pode ser un reto se non sabes por onde comezar. Sempre debes abordar o problema de forma ascendente: comeza con pods e despois pasa ao servizo e Ingress. As técnicas de depuración descritas neste artigo pódense aplicar a outros obxectos, como:

  • traballos inactivos e CronJobs;
  • StatefulSets e DaemonSets.

Expreso o meu agradecemento Gergely Risko, Daniel Weibel и Charles Christyraj para comentarios e engadidos valiosos.

PS do tradutor

Lea tamén no noso blog:

Fonte: www.habr.com

Engadir un comentario