Introdução
Os laboratórios anteriores introduziram logs, eventos, kubectl exec, port-forwarding e probes. Uma aplicação em CrashLoop combina várias dessas habilidades. O Pod inicia, o container encerra, o Kubernetes o reinicia, e você precisa ler as evidências antes de alterar qualquer coisa.
Neste laboratório, você implantará uma aplicação que encerra porque uma variável de ambiente necessária está faltando. Você observará o comportamento de reinicialização, lerá os logs atuais e anteriores, inspecionará eventos, identificará a configuração ausente no Deployment, corrigirá o Deployment e verificará se a aplicação se torna acessível.
Preparar um Namespace para Depuração de CrashLoop
Nesta etapa, você preparará um namespace limpo para o exercício de depuração de CrashLoop.
Comece em /home/labex/project. Você criará e atualizará o manifesto da aplicação neste diretório.
mkdir -p /home/labex/project
cd /home/labex/project
Verifique se o servidor da API do Kubernetes está acessível. Se a VM acabou de iniciar e o nó ainda não está pronto, aguarde alguns segundos e execute o comando novamente.
kubectl get nodes --request-timeout=5s
A saída esperada inclui:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
Aguarde até que o Pod de rede do cluster esteja pronto (Ready). A aplicação corrigida será testada posteriormente através de um Service.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
Saída esperada:
pod/calico-node-... condition met
Crie um namespace chamado ckad-prep-crashloop e defina-o como o namespace atual:
kubectl create namespace ckad-prep-crashloop
kubectl config set-context --current --namespace=ckad-prep-crashloop
Confirme o namespace atual:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
Saída esperada:
ckad-prep-crashloop
Implantar e Observar um CrashLoop
Nesta etapa, você implantará uma aplicação que encerra repetidamente.
O script do container requer a variável de ambiente APP_MESSAGE. Se a variável estiver ausente, o script imprime um erro claro e encerra com status 1. O Kubernetes reiniciará o container, o que cria o comportamento de CrashLoop que você precisa depurar.
Crie o arquivo crash-demo.yaml:
cat > crash-demo.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: crash-demo
spec:
replicas: 1
selector:
matchLabels:
app: crash-demo
template:
metadata:
labels:
app: crash-demo
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- |
if [ -z "${APP_MESSAGE:-}" ]; then
echo "startup failed: APP_MESSAGE is required"
exit 1
fi
mkdir -p /www
echo "$APP_MESSAGE" > /www/index.html
httpd -f -p 8080 -h /www
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: crash-demo
spec:
selector:
app: crash-demo
ports:
- port: 80
targetPort: 8080
EOF
Aplique o manifesto:
kubectl apply -f crash-demo.yaml
Saída esperada:
deployment.apps/crash-demo created
service/crash-demo created
Dê ao Kubernetes um breve momento para reiniciar o container com falha e, em seguida, inspecione o Pod:
sleep 12
kubectl get pods -l app=crash-demo
A saída esperada inclui um Pod que não está saudável. O status exato pode ser Error ou CrashLoopBackOff dependendo do tempo:
NAME READY STATUS RESTARTS AGE
crash-demo-... 0/1 CrashLoopBackOff ... ...
Armazene o nome do Pod e inspecione o estado do seu container. O JSONPath permite ler os campos específicos que importam sem percorrer todo o objeto. O primeiro valor é a contagem de reinicializações. O segundo valor é o motivo da espera, que pode estar vazio se você capturar o Pod enquanto o último container com falha estiver em estado Error em vez de aguardar em CrashLoopBackOff.
CRASH_POD="$(kubectl get pods -l app=crash-demo -o jsonpath='{.items[0].metadata.name}')"
echo "$CRASH_POD"
kubectl get pod "$CRASH_POD" -o jsonpath='{.status.containerStatuses[0].restartCount}{" "}{.status.containerStatuses[0].state.waiting.reason}{"\n"}'
A saída esperada inclui uma contagem de reinicializações maior que 0. Dependendo do tempo, o motivo pode estar em branco ou mostrar um valor como CrashLoopBackOff:
2
ou:
... CrashLoopBackOff
Ler Logs e Eventos para Encontrar a Causa
Nesta etapa, você usará logs, logs anteriores e eventos para identificar por que o container encerra.
Quando um container está reiniciando rapidamente, o kubectl logs pode mostrar a tentativa atual do container, enquanto o kubectl logs --previous lê a tentativa anterior do container encerrado. Para depuração de CrashLoop, o --previous é frequentemente o comando que expõe o erro de inicialização útil.
Leia os logs atuais:
kubectl logs "$CRASH_POD" --container web
A saída esperada inclui:
startup failed: APP_MESSAGE is required
Leia os logs do container anterior. Se o Kubernetes tiver mantido o log do último container encerrado, isso mostrará o mesmo erro de inicialização de uma tentativa anterior. Em alguns casos de CrashLoop rápido, o runtime pode, em vez disso, informar que não consegue recuperar o log anterior. Isso ainda ensina um ponto importante de depuração: use --previous quando estiver disponível, mas sempre compare-o com os logs atuais e os eventos do Pod.
kubectl logs "$CRASH_POD" --container web --previous
A saída esperada frequentemente inclui:
startup failed: APP_MESSAGE is required
Também é aceitável ver uma mensagem semelhante a:
unable to retrieve container logs for ...
Inspecione os eventos do Pod. Os eventos mostram o Kubernetes reiniciando o container com falha.
kubectl describe pod "$CRASH_POD" | sed -n '/Events:/,$p'
A saída esperada inclui eventos como BackOff ou Started:
Warning BackOff ... Back-off restarting failed container
Agora, inspecione a configuração de ambiente do Deployment. A lista env está ausente, o que explica a mensagem de log.
kubectl get deployment crash-demo -o jsonpath='{.spec.template.spec.containers[0].env}'; echo
A saída esperada está vazia:
Corrigir o Deployment e Verificar a Recuperação
Nesta etapa, você corrigirá a variável de ambiente ausente e verificará se a aplicação se recupera.
A mensagem de erro nomeou a configuração ausente: APP_MESSAGE. Em vez de alterar o comando do container, defina a variável de ambiente necessária no Deployment. O Kubernetes criará um novo ReplicaSet porque o template do Pod mudou.
Defina a variável de ambiente:
kubectl set env deployment/crash-demo APP_MESSAGE=crashloop-fixed
Saída esperada:
deployment.apps/crash-demo env updated
Aguarde o rollout:
kubectl rollout status deployment/crash-demo --timeout=120s
Saída esperada:
deployment "crash-demo" successfully rolled out
Inspecione o novo Pod. Ele deve estar em estado Running e Ready:
kubectl get pods -l app=crash-demo
A saída esperada inclui:
NAME READY STATUS RESTARTS AGE
crash-demo-... 1/1 Running 0 ...
Crie um Pod cliente e teste o Service:
kubectl run crash-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/crash-client --timeout=120s
kubectl exec crash-client -- wget -qO- http://crash-demo
Saída esperada:
crashloop-fixed
Finalmente, confirme que o Deployment agora inclui a variável de ambiente:
kubectl get deployment crash-demo -o jsonpath='{.spec.template.spec.containers[0].env[0].name}{"="}{.spec.template.spec.containers[0].env[0].value}{"\n"}'
Saída esperada:
APP_MESSAGE=crashloop-fixed
Resumo
Você depurou uma aplicação em CrashLoop usando as mesmas fontes de evidência introduzidas anteriormente no Estágio 5. Você observou o status do Pod com falha, leu os logs atuais e anteriores do container, inspecionou eventos, identificou uma variável de ambiente ausente no Deployment, corrigiu o template do Pod com kubectl set env e verificou a aplicação recuperada através do seu Service.


