Guia de solução de problemas visuais para Kubernetes

Nota perev. : Este artigo faz parte dos materiais disponíveis gratuitamente no projeto learnk8s , que ensina como trabalhar com empresas Kubernetes e administradores individuais. Nele, Daniele Polencic, gerente de projetos, compartilha uma instrução clara sobre as etapas a serem seguidas em caso de problemas gerais para aplicativos em execução no cluster K8s.



TL; DR: aqui está um diagrama que ajudará você a depurar a implantação no Kubernetes:



Fluxograma para localizar e corrigir erros em um cluster. No original (em inglês), está disponível em PDF e como imagem .

Ao implantar um aplicativo no Kubernetes, você geralmente precisa definir três componentes:

  • Implantação é uma receita para criar cópias de um aplicativo chamado pods;
  • Serviço - um balanceador de carga interno que distribui o tráfego entre os pods;
  • Ingresso - uma descrição de como o tráfego fluirá do mundo externo para o Serviço.

Aqui está um breve resumo gráfico:

1) No Kubernetes, os aplicativos recebem tráfego do mundo externo através de duas camadas de balanceadores de carga: interno e externo.



2) O balanceador interno é chamado Serviço, o externo - Ingresso.



3) A implantação cria pods e os monitora (eles não são criados manualmente).



Suponha que você queira implantar um aplicativo simples no Hello World . A configuração do YAML terá a seguinte aparência:

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 definição é bastante longa e é fácil ficar confuso sobre como os componentes estão relacionados.

Por exemplo:

  • Quando você deve usar a porta 80 e quando - 8080?
  • Devo criar uma nova porta para cada serviço para que eles não entrem em conflito?
  • Os nomes dos rótulos são importantes? Eles deveriam ser os mesmos em todos os lugares?

Antes de focar na depuração, lembremos como os três componentes estão relacionados entre si. Vamos começar com implantação e serviço.

Implantação de Conexão'a e Serviço'a


Você ficará surpreso, mas as implantações e o serviço não estão conectados de forma alguma. Em vez disso, o Serviço aponta diretamente para os Pods ignorando a Implantação.

Portanto, estamos interessados ​​em saber como os Pods e os serviços estão relacionados entre si. Três coisas para lembrar:

  1. Um selector serviço deve corresponder a pelo menos um rótulo de Pod.
  2. targetPort deve corresponder ao containerPort contêiner dentro do Pod.
  3. port Service pode ser qualquer coisa. Serviços diferentes podem usar a mesma porta porque possuem endereços IP diferentes.

O diagrama a seguir representa todos os itens acima em forma gráfica:

1) Imagine que o serviço direcione o tráfego para um determinado pod:



2) Ao criar um pod, você deve especificar containerPort para cada container nos pods:



3) Ao criar o serviço, você deve especificar port e targetPort . Mas qual deles está se conectando ao contêiner?



4) Via targetPort . Deve corresponder a containerPort .



5) Digamos que a porta 3000 esteja aberta no contêiner e, em seguida, o valor targetPort deve ser o mesmo.



No arquivo YAML, os rótulos e as ports / targetPort devem 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 # <<< 

E a track: canary na parte superior da seção Implantação? Deve corresponder?

Este rótulo refere-se à implantação e não é usado pelo serviço para rotear o tráfego. Em outras palavras, ele pode ser excluído ou atribuído a um valor diferente.

E o seletor matchLabels ?

Sempre deve corresponder aos rótulos do Pod , pois é usado pelo Deployment para rastrear os pods.

Suponha que você tenha feito as edições corretas. Como verificá-los?

Você pode verificar o rótulo do pod com o seguinte comando:

 kubectl get pods --show-labels 

Ou, se os pods pertencerem a vários aplicativos:

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

Onde any-name=my-app é o rótulo any-name: my-app .

Há alguma dificuldade?

Você pode se conectar ao pod! Para fazer isso, use o comando port-forward no kubectl. Ele permite que você se conecte ao serviço e verifique a conexão.

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

Aqui:

  • service/<service name> - nome do serviço; no nosso caso, é o my-service ;
  • 3000 - a porta que você deseja abrir no computador;
  • 80 - porta especificada no campo de port do serviço.

Se você conseguiu estabelecer uma conexão, as configurações estão corretas.

Se a conexão não pôde ser estabelecida, há um problema com os rótulos ou as portas não coincidem.

Conexão de serviço e ingresso


A próxima etapa no fornecimento de acesso ao aplicativo está relacionada à configuração do Ingress. O Ingress deve saber como encontrar o serviço, encontrar os pods e direcionar o tráfego para eles. O Ingress localiza o serviço desejado por nome e porta aberta.

Na descrição do Ingress e Service, dois parâmetros devem corresponder:

  1. servicePort no Ingress deve corresponder ao parâmetro port no Service;
  2. serviceName no Ingress deve corresponder ao campo de name no Service.

O diagrama a seguir resume a conexão de portas:

1) Como você já sabe, o Serviço escuta em uma determinada port :



2) O Ingress possui um parâmetro chamado servicePort :



3) Este parâmetro ( servicePort ) deve sempre corresponder à port na definição de serviço:



4) Se a porta 80 for especificada em Serviço, servicePort também deverá ser 80:



Na prática, você precisa prestar atenção às seguintes linhas:

 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 verificar se o Ingress está funcionando?

Você pode usar o método com o kubectl port-forward , mas em vez do serviço, você precisa se conectar ao controlador do Ingress.

Primeiro, você precisa descobrir o nome do pod com o controlador do 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 

Localize o pod de entrada (ele pode se referir a um espaço para nome diferente) e execute o comando de describe para descobrir os números de porta:

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

Por fim, conecte-se ao pod:

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

Agora, toda vez que você enviar uma solicitação para a porta 3000 no computador, ela será redirecionada para a porta 80 do pod com o controlador do Ingress. Acessando http: // localhost: 3000 , você verá a página criada pelo aplicativo.

Resumo da porta


Vamos lembrar novamente quais portas e etiquetas devem corresponder:

  1. O seletor na definição de Serviço deve corresponder ao rótulo do pod;
  2. targetPort na definição de Serviço deve corresponder ao containerPort container dentro do pod;
  3. port na definição de serviço pode ser qualquer coisa. Serviços diferentes podem usar a mesma porta porque possuem endereços IP diferentes;
  4. servicePort Ingress deve corresponder à port na definição de Serviço;
  5. O nome do serviço deve corresponder ao campo serviceName no Ingress.

Infelizmente, não basta saber como estruturar corretamente sua configuração YAML.

O que acontece quando algo dá errado?

Talvez o pod não inicie ou trava.

3 etapas para solucionar falhas de aplicativos no Kubernetes


Antes de depurar uma implantação, você precisa entender bem como o Kubernetes funciona.

Como existem três componentes em cada aplicativo baixado para o K8s, eles devem ser depurados em uma determinada ordem, começando da parte inferior.

  1. Primeiro você precisa ter certeza de que os pods estão funcionando, então ...
  2. Verifique se o serviço entrega tráfego aos pods e, em seguida, ...
  3. Verifique se o Ingress está configurado corretamente.

Apresentação visual:

1) Inicie a busca de problemas deve estar na parte inferior. Primeiro verifique se os pods têm status Ready e Running :



2) Se os pods estiverem Ready , você deve descobrir se o serviço distribui o tráfego entre os pods:



3) Finalmente, você precisa analisar a conexão entre o serviço e o Ingress:



1. Diagnóstico de pods


Na maioria dos casos, o problema está no pod. Verifique se os pods estão Ready e em Running . Você pode verificar isso 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 acima, o último pod está listado como Em Running e Ready , mas para os outros dois, não.

Como entender o que deu errado?

Existem quatro comandos úteis para diagnosticar pods:

  1. kubectl logs < pod'> permite extrair logs de contêineres no pod;
  2. kubectl describe pod < pod'> permite visualizar uma lista de eventos associados ao pod;
  3. kubectl get pod < pod'> permite que você obtenha a configuração YAML do kubectl get pod < pod'> armazenado no Kubernetes;
  4. kubectl exec -ti < pod'> bash permite executar um shell de comando interativo em um dos contêineres do pod

Qual escolher?

O fato é que não há equipe universal. Uma combinação destes deve ser usada.

Problemas comuns no pod


Existem dois tipos principais de erros de pod: erros de inicialização e erros de tempo de execução.

Erros de inicialização:

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

Erros de tempo de execução:

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

Alguns erros são mais comuns que outros. Aqui estão alguns erros comuns e como corrigi-los.

ImagePullBackOff


Este erro aparece quando o Kubernetes não pode obter uma imagem para um dos contêineres de pod. Aqui estão os três motivos mais comuns para isso:

  1. O nome da imagem está especificado incorretamente - por exemplo, você cometeu um erro ou a imagem não existe;
  2. Uma tag inexistente para a imagem é especificada;
  3. A imagem é armazenada em um registro privado e o Kubernetes não tem autoridade para acessá-la.

As duas primeiras razões são fáceis de eliminar - basta corrigir o nome e a etiqueta da imagem. No caso deste último, você deve inserir as credenciais para o registro privado em Segredo e adicionar links a ele em pods. A documentação do Kubernetes tem um exemplo de como isso pode ser feito.

CrashLoopBackOff


O Kubenetes lançará um erro CrashLoopBackOff se o contêiner não puder iniciar. Isso geralmente acontece quando:

  1. Há um erro no aplicativo que impede que ele seja iniciado;
  2. O contêiner está configurado incorretamente ;
  3. O teste de vida falhou muitas vezes.

Você deve tentar acessar os logs do contêiner para descobrir o motivo de sua falha. Se o acesso aos logs for difícil, porque o contêiner é reiniciado muito rapidamente, você pode usar o seguinte comando:

 kubectl logs <pod-name> --previous 

Ele exibe mensagens de erro de uma reencarnação anterior do contêiner.

RunContainerError


Este erro ocorre quando o contêiner falha ao iniciar. Corresponde ao momento anterior ao lançamento do aplicativo. Geralmente, sua causa é a configuração incorreta, por exemplo:

  • Tentativa de montar um volume inexistente, como ConfigMap ou Secrets;
  • tente montar um volume somente leitura como leitura e gravação.

O kubectl describe pod <pod-name> é adequado para analisar esses erros.

Pods pendentes


Após a criação, o pod permanece no estado Pending .

Por que isso está acontecendo?

Aqui estão os possíveis motivos (suponho que o agendador esteja funcionando bem):

  1. O cluster não possui recursos suficientes, como poder de processamento e memória, para executar o pod.
  2. O objeto ResourceQuota é instalado no espaço para nome correspondente e a criação de um pod fará com que o espaço para nome ultrapasse a cota.
  3. O pod está vinculado a Pending PersistentVolumeClaim .

Nesse caso, é recomendável usar o comando kubectl describe e verificar a seção Events :

 kubectl describe pod <pod name> 

No caso de erros relacionados ao ResourceQuotas , é recomendável visualizar os logs do cluster usando o comando

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

Pods não prontos


Se o pod estiver listado como Em Running , mas não estiver no estado Ready , a sonda de prontidão não terá êxito.

Quando isso acontece, o pod não se conecta ao serviço e o tráfego não flui para ele. O teste de prontidão falhou devido a problemas de aplicativo. Nesse caso, para encontrar o erro, você precisa analisar a seção Events na saída do comando kubectl describe .

2. Diagnóstico de serviços


Se os pods estiverem listados como Em Running e Ready , mas ainda não houver resposta do aplicativo, verifique as configurações do serviço.

Os serviços estão envolvidos no roteamento de tráfego para os pods, dependendo de seus rótulos. Portanto, a primeira coisa a fazer é verificar quantos pods funcionam com o serviço. Para fazer isso, você pode verificar os pontos de extremidade no serviço:

 kubectl describe service <service-name> | grep Endpoints 

O ponto de extremidade é um par de valores no formato <IP-:> e pelo menos um desses pares deve estar presente na saída (ou seja, pelo menos um pod funciona com o serviço).

Se a seção Endpoins vazia, duas opções serão possíveis:

  1. não há pods com o rótulo correto (dica: verifique se o espaço para nome está selecionado corretamente);
  2. Há um erro nas etiquetas de serviço no seletor.

Se você vir uma lista de pontos de extremidade, mas ainda não conseguir acessar o aplicativo, o provável culpado é o erro no targetPort na descrição do serviço.

Como verificar a capacidade de manutenção do serviço?

Independentemente do tipo de serviço, você pode usar o kubectl port-forward para se conectar a ele:

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

Aqui:

  • <service-name> - o nome do serviço;
  • 3000 - a porta que você abre no computador;
  • 80 - porta no lado do serviço.

3. Diagnóstico do ingresso


Se você ler este lugar, então:

  • os pods estão listados como Running and Ready ;
  • o serviço distribui com sucesso o tráfego entre os pods.

No entanto, você ainda não pode "alcançar" o aplicativo.

Isso significa que, muito provavelmente, o controlador do Ingress está configurado incorretamente. Como o controlador do Ingress é um componente de terceiros no cluster, existem vários métodos de depuração, dependendo do seu tipo.

Mas antes de recorrer a ferramentas especiais para configurar o Ingress, você pode fazer algo muito simples. O Ingress usa serviceName e servicePort para se conectar ao serviço. Você deve verificar se eles estão configurados corretamente. Você pode fazer isso usando o comando:

 kubectl describe ingress <ingress-name> 

Se a coluna Backend - Backend estiver vazia, há uma grande chance de um erro de configuração. Se os back-end estiverem instalados, mas ainda não houver acesso ao aplicativo, o problema poderá estar relacionado a:

  • Configurações de acessibilidade do ingresso da Internet pública;
  • configurações de acessibilidade de cluster da Internet pública.

Você pode identificar problemas de infraestrutura conectando-se diretamente ao pod do Ingress. Para fazer isso, primeiro encontre o pod do controlador do Ingress (ele pode estar em um espaço para nome 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 de describe para definir a porta:

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

Por fim, conecte-se ao pod:

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

Agora, todos os pedidos da porta 3000 no computador serão redirecionados para o pod da porta 80.

Isso funciona agora?

  • Nesse caso, o problema está na infraestrutura. É necessário descobrir exatamente como o tráfego é roteado para o cluster.
  • Caso contrário, o problema está no controlador do Ingress.

Se você não conseguir que o controlador do Ingress funcione, será necessário depurá-lo.

Existem muitas variedades de controladores do Ingress. Os mais populares são Nginx, HAProxy, Traefik etc. (para obter mais informações sobre soluções existentes, consulte nossa revisão - aprox. Transl.) Você deve usar o guia de solução de problemas na documentação do controlador correspondente. Como o Ingress Nginx é o controlador de ingresso mais popular, incluímos algumas dicas sobre como resolver problemas relacionados neste artigo.

Depurando um controlador Nginx do Ingress



O projeto Ingress-nginx possui um plugin oficial para o kubectl . O kubectl ingress-nginx pode ser usado para:

  • análise de logs, backends, certificados, etc;
  • conexão com o Ingress;
  • estudando a configuração atual.

As três equipes a seguir o ajudarão com isso:

  • kubectl ingress-nginx lint - verifica o nginx.conf ;
  • kubectl ingress-nginx backend - examina o back-end (semelhante ao kubectl describe ingress <ingress-name> );
  • kubectl ingress-nginx logs - verifica os logs.

Observe que, em alguns casos, pode ser necessário especificar o espaço para nome correto para o controlador Ingress usando o --namespace <name> .

Sumário


Diagnosticar o Kubernetes pode ser uma tarefa assustadora, se você não sabe por onde começar. O problema sempre deve ser abordado de acordo com o princípio de baixo para cima: comece com pods e depois vá para o serviço e o Ingress. Os métodos de depuração descritos no artigo podem ser aplicados a outros objetos, como:

  • Jobs ociosos e CronJobs;
  • StatefulSets e DaemonSets.

Agradeço a Gergely Risko , Daniel Weibel e Charles Christyraj pelos valiosos comentários e adições.

PS do tradutor


Leia também em nosso blog:

Source: https://habr.com/ru/post/pt484954/


All Articles