Nota do tradutor.: Este artigo faz parte dos conteúdos publicados de forma aberta do projeto , que ensina a trabalhar com Kubernetes para empresas e administradores individuais. Nele, Daniele Polencic, líder do projeto, compartilha uma instrução visual sobre quais passos devem ser tomados em caso de problemas gerais com aplicações executadas em um cluster K8s.

TL;DR: aqui está um esquema que ajudará você a depurar o deployment no Kubernetes:
Fluxograma para encontrar e corrigir erros em um cluster. No original (em inglês) está disponível em e .
Ao implantar uma aplicação no Kubernetes, geralmente é necessário definir três componentes:
- Deployment — é uma espécie de receita para criar cópias da aplicação, chamadas de pods;
- Service — um balanceador de carga interno que distribui o tráfego entre os pods;
- Ingress — uma descrição de como o tráfego irá chegar do mundo exterior ao Service.
Aqui está um breve resumo gráfico:
1) No Kubernetes, as aplicações recebem tráfego do mundo exterior através de duas camadas de balanceadores de carga: interno e externo.

2) O balanceador interno é chamado de Service, o externo – Ingress.

3) O Deployment cria pods e os monitora (não são criados manualmente).

Suponha que você queira implantar uma aplicação simples do tipo Hello World. A configuração YAML para ela será a seguinte:
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 se perder em como os componentes estão relacionados entre si.
Por exemplo:
- Quando você deve usar a porta 80 e quando a 8080?
- Devo criar uma nova porta para cada serviço, para que não haja conflito?
- Os nomes dos rótulos importam? Devem ser iguais em todos os lugares?
Antes de nos concentrarmos na depuração, vamos relembrar como os três componentes se relacionam. Começaremos com o Deployment e o Service.
A relação entre o Deployment e o Service
Você pode ficar surpreso, mas Deployments e Services não estão relacionados. Em vez disso, o Service aponta diretamente para os Pods, contornando o Deployment.
Assim, estamos interessados em como os Pods e os Services se relacionam. É importante lembrar três coisas:
- O seletor (
selector) do Service deve corresponder a pelo menos um rótulo do Pod. -
targetPortdeve coincidir comcontainerPortdo contêiner dentro do Pod. -
portdo Service pode ser qualquer um. Diferentes serviços podem usar a mesma porta, pois possuem endereços IP diferentes.
O esquema a seguir representa tudo o que foi mencionado acima de forma gráfica:
1) Vamos supor que o serviço direciona o tráfego para um pod:

2) Ao criar um pod, é necessário especificar containerPort para cada contêiner nos pods:

3) Ao criar um serviço, é necessário indicar port e targetPort. Mas através de qual deles a conexão com o contêiner ocorre?

4) Através de targetPort. Deve coincidir com containerPort.

5) Supondo que a porta 3000 esteja aberta no contêiner. Então, o valor targetPort deve ser o mesmo.

No arquivo YAML, os rótulos e ports / targetPort devem coincidir:
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 quanto ao rótulo track: canary na parte superior da seção Deployment? Ele deve coincidir?
Esse rótulo se refere ao deployment e não é usado pelo serviço para roteamento de tráfego. Em outras palavras, pode ser removido ou ter outro valor atribuído.
E quanto ao seletor matchLabels?
Deve sempre coincidir com os rótulos do Pod, pois é usado pelo Deployment para rastrear os pods.
Suponha que você fez as correções corretas. Como pode verificá-las?
Os rótulos dos pods podem ser verificados com o seguinte comando:
kubectl get pods --show-labelsOu, se os pods pertencerem a vários aplicativos:
kubectl get pods --selector any-name=my-app --show-labels Onde any-name=my-app — este é o rótulo any-name: my-app.
Ainda há dificuldades?
Você pode se conectar ao pod! Para 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/ 3000:80Aqui:
-
service/— nome do serviço; neste caso, émy-service; - 3000 — porta que precisa ser aberta no computador;
- 80 — porta especificada no campo
portdo serviço.
Se a conexão foi estabelecida, significa que as configurações estão corretas.
Se não foi possível estabelecer a conexão, a questão pode estar nos rótulos ou nas portas que não coincidem.
Relação entre Service e Ingress
O próximo passo para garantir o acesso ao aplicativo está relacionado à configuração do Ingress. O Ingress deve saber como encontrar o serviço, em seguida, localizar os pods e redirecionar o tráfego para eles. O Ingress encontra o serviço necessário pelo nome e pela porta aberta.
Na descrição do Ingress e do Service, devem coincidir dois parâmetros:
-
servicePortno Ingress deve coincidir com o parâmetroportno Service; -
serviceNameno Ingress deve coincidir com o camponomeno Service.
O seguinte diagrama resume a conexão das portas:
1) Como você já sabe, o Service escuta uma certa port:

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

3) Esse parâmetro (servicePort) deve sempre coincidir com port na definição do Service:

4) Se no Service foi definido a porta 80, então é necessário que servicePort também seja igual a 80:

Na prática, é necessário prestar atenção nas 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 kubectl port-forward, mas em vez do serviço, você deve 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 do Ingress (ele pode pertencer a outro namespace) e execute o comando describe, para descobrir os números das portas:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep Ports
Ports: 80/TCP, 443/TCP, 18080/TCPPor fim, conecte-se ao pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemAgora, sempre 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. Ao acessar , você deverá ver a página criada pelo aplicativo.
Resumo sobre as portas
Vamos lembrar novamente quais portas e rótulos devem coincidir:
- O seletor na definição do Service deve coincidir com o rótulo do pod;
-
targetPortna definição do Service deve coincidir comcontainerPorto contêiner dentro do pod; -
portna definição do Service pode ser qualquer um. Diferentes serviços podem usar a mesma porta, já que possuem endereços IP diferentes; -
servicePorto Ingress deve coincidir comportna definição do Service; - O nome do serviço deve coincidir com o campo
serviceNameno Ingress.
Infelizmente, não basta saber como estruturar corretamente a configuração YAML.
O que acontece quando algo dá errado?
Pode ser que o pod não esteja iniciando ou está falhando.
3 etapas para diagnosticar problemas em aplicativos no Kubernetes
Antes de começar a depurar o deployment, é necessário ter uma boa compreensão de como o Kubernetes funciona.
Como cada aplicativo implantado no K8s possui três componentes, a depuração deve ser feita em uma ordem específica, começando de baixo para cima.
- Primeiro, é preciso garantir que os pods estejam funcionando, depois...
- Verifique se o serviço está direcionando tráfego para os pods e depois...
- Verifique se o Ingress está configurado corretamente.
Representação visual:
1) Comece a busca por problemas de baixo para cima. Primeiro, verifique se os pods têm status Pronto e Em execução:

2) Se os pods estão prontos (Pronto), é necessário descobrir se o serviço está distribuindo tráfego entre os pods:

3) Finalmente, analise a conexão entre o serviço e o Ingress:

1. Diagnóstico dos pods
Na maioria dos casos, o problema está relacionado ao pod. Certifique-se de que os pods estejam marcados como Pronto e Em execução. Isso pode ser verificado com o comando:
kubectl get pods
NAME READY STATUS RESTARTS AGE
app1 0/1 ImagePullBackOff 0 47h
app2 0/1 Erro 0 47h
app3-76f9fcd46b-xbv4k 1/1 Em execução 1 47h Na saída do comando acima, o último pod é listado como Em execução e Pronto, mas para os outros dois isso não é o caso.
Como entender o que deu errado?
Existem quatro comandos úteis para diagnosticar pods:
-
kubectl logspermite extrair logs dos contêineres no pod; -
kubectl describe podpermite visualizar a lista de eventos relacionados ao pod; -
kubectl get podpermite obter a configuração YAML do pod armazenada no Kubernetes; -
kubectl exec -ti bashpermite iniciar um shell de comandos interativo em um dos contêineres do pod
Qual delas escolher?
Na verdade, não há um comando universal. Deve-se usar uma combinação deles.
Problemas típicos dos pods
Existem dois tipos principais de erros nos pods: erros durante a inicialização (startup) e erros durante a execução (runtime).
Erros de inicialização:
-
ImagePullBackoff -
ImageInspectError -
ErrImagePull -
ErrImageNeverPull -
RegistryUnavailable -
InvalidImageName
Erros de runtime:
-
CrashLoopBackOff -
RunContainerError -
KillContainerError -
VerifyNonRootError -
RunInitContainerError -
CreatePodSandboxError -
ConfigPodSandboxError -
KillPodSandboxError -
SetupNetworkError -
TeardownNetworkError
Alguns erros ocorrem com mais frequência do que outros. Aqui estão alguns dos erros mais comuns e como resolvê-los.
ImagePullBackOff
Este erro ocorre quando o Kubernetes não consegue obter a imagem de um dos contêineres do pod. Aqui estão três razões mais comuns para isso:
- Nome da imagem especificado incorretamente - por exemplo, você cometeu um erro ou a imagem não existe;
- Um tag inexistente para a imagem foi especificado;
- A imagem está armazenada em um registro privado e o Kubernetes não tem permissões para acessá-la.
As duas primeiras causas são fáceis de corrigir - basta corrigir o nome da imagem e o tag. Para a última, é necessário adicionar as credenciais para o registro privado no Secret e adicionar referências a ele nos pods. Na documentação do Kubernetes de como isso pode ser feito.
CrashLoopBackOff
O Kubernetes retorna um erro CrashLoopBackOff, se o contêiner não consegue iniciar. Isso geralmente acontece quando:
- Há um erro no aplicativo que impede sua inicialização;
- O contêiner ;
- O teste de Liveness falhou muitas vezes.
É necessário tentar acessar os logs do contêiner para descobrir a razão da falha. Se o acesso aos logs for difícil devido ao contêiner reiniciar rapidamente, você pode usar o seguinte comando:
kubectl logs --previousIsso exibirá mensagens de erro da reencarnação anterior do contêiner.
RunContainerError
Este erro ocorre quando o contêiner não consegue iniciar. Isso corresponde ao momento antes de o aplicativo ser iniciado. Sua causa geralmente é uma configuração incorreta, como:
- tentar montar um volume inexistente, como ConfigMap ou Secrets;
- tentar montar um volume do tipo somente leitura como leitura-escrita.
Para analisar esses erros, o comando ideal é kubectl describe pod.
Os pods estão no estado Pending
Após a criação, o pod permanece no estado Pending.
Por que isso acontece?
Aqui estão as possíveis causas (parto do pressuposto de que o agendador está funcionando normalmente):
- O cluster não tem recursos suficientes, como poder de computação e memória, para iniciar o pod.
- O objeto está definido no namespace correspondente
ResourceQuotae a criação do pod fará com que o namespace exceda a cota. - Pod está em Pending
PersistentVolumeClaim.
Nesse caso, recomenda-se usar o comando kubectl describe e verificar a seção Eventos:
kubectl describe pod Em caso de erros relacionados a ResourceQuotas, recomenda-se visualizar os logs do cluster com o comando
kubectl get events --sort-by=.metadata.creationTimestampPods não estão prontos
Se o pod está marcado como Em execução, mas não está em estado Pronto, isso significa que a verificação de prontidão (readiness probe) falha.
Quando isso acontece, o pod não se conecta ao serviço e o tráfego não chega até ele. A falha do teste de prontidão é causada por problemas no aplicativo. Neste caso, para encontrar erro, é necessário analisar a seção Eventos na saída do comando kubectl describe.
2. Diagnóstico de serviços
Se os pods estão marcados como Em execução e Pronto, mas ainda não há resposta do aplicativo, é preciso verificar as configurações do serviço.
Os serviços são responsáveis por roteamento de tráfego para os pods com base em seus rótulos. Portanto, a primeira coisa a fazer é verificar quantos pods estão trabalhando com o serviço. Para isso, você pode verificar os endpoints no serviço:
kubectl describe service | grep Endpoints Endpoint é um par de valores do tipo <IP-адрес:порт>, e deve haver pelo menos um desses pares na saída (ou seja, pelo menos um pod está trabalhando com o serviço).
Se a seção Endpoins está vazia, podem haver duas razões:
- não existe nenhum pod com o rótulo correto (dica: verifique se o namespace está correto);
- há um erro nos rótulos do serviço no seletor.
Se você vê a lista de endpoints, mas ainda não consegue acessar o aplicativo, o provável culpado é um erro na targetPort descrição do serviço.
Como verificar a funcionalidade do serviço?
Independentemente do tipo de serviço, você pode usar o comando kubectl port-forward para se conectar a ele:
kubectl port-forward service/ 3000:80Aqui:
-
<service-name>— é o nome do serviço; - 3000 — a porta que você está abrindo no computador;
- 80 — a porta do lado do serviço.
3. Diagnóstico de Ingress
Se você leu até aqui, então:
- os pods estão marcados como
Em execuçãoePronto; - o serviço está distribuindo o tráfego corretamente entre os pods.
No entanto, você ainda não consegue "acessar" o aplicativo.
Isso significa que, provavelmente, o controlador Ingress está configurado incorretamente. Como o controlador Ingress é um componente de terceiros no cluster, existem diferentes métodos de depuração dependendo do seu tipo.
Mas antes de recorrer a ferramentas especiais para configurar o Ingress, você pode fazer algo bem simples. O Ingress utiliza serviceName e servicePort para conectar-se ao serviço. É necessário verificar se eles estão configurados corretamente. Isso pode ser feito com o seguinte comando:
kubectl describe ingress Se a coluna Backend estiver vazia, a probabilidade de um erro de configuração é alta. Se os backends estiverem no lugar, mas ainda não houver acesso ao aplicativo, o problema pode estar relacionado a:
- configurações de acessibilidade do Ingress da internet pública;
- configurações de acessibilidade do cluster da internet pública.
Identificar problemas com a infraestrutura pode ser feito conectando-se diretamente ao pod do Ingress. Para isso, primeiro encontre o pod do controlador Ingress (ele pode estar em outro namespace):
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 describe, para definir a porta:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep PortsPor fim, conecte-se ao pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemAgora todas as solicitações na porta 3000 do computador serão redirecionadas para a porta 80 do pod.
Ele está funcionando agora?
- Se sim, o problema está na infraestrutura. É necessário descobrir como exatamente o tráfego está sendo roteado no cluster.
- Se não, o problema está com o controlador Ingress.
Se não conseguir fazer o controlador Ingress funcionar, será necessário depurá-lo.
Existem muitas variedades de controladores Ingress. Os mais populares são Nginx, HAProxy, Traefik, entre outros. (para mais detalhes sobre as soluções existentes, veja nosso — nota do tradutor.) Deve-se consultar o guia de solução de problemas na documentação do respectivo controlador. Como o é o controlador Ingress mais popular, incluímos no artigo algumas dicas para resolver problemas relacionados a ele.
Depurando o controlador Ingress Nginx
O projeto Ingress-nginx tem um . O comando kubectl ingress-nginx pode ser usado para:
- analisar logs, backends, certificados, etc.;
- conectar-se ao Ingress;
- estudar a configuração atual.
As seguintes três comandos ajudarão você com isso:
-
kubectl ingress-nginx lint— verificanginx.conf; -
kubectl ingress-nginx backend— explora o backend (semelhante akubectl describe ingress); -
kubectl ingress-nginx logs— verifica os logs.
Observe que, em alguns casos, pode ser necessário especificar o namespace correto para o controlador Ingress usando a flag --namespace.
Resumo
A diagnose no Kubernetes pode ser uma tarefa desafiadora se você não souber por onde começar. A abordagem deve sempre ser de baixo para cima: comece pelos pods e depois avance para o serviço e o Ingress. Os métodos de depuração descritos no artigo podem ser aplicados a outros objetos, como:
- Jobs e CronJobs que não funcionam;
- StatefulSets e DaemonSets.
Agradeço a , e pelas valiosas observações e sugestões.
P.S. do tradutor
Confira também em nosso blog:
- «»;
- «»;
- «»;
- «».
Fonte: habr.com
