Nota do tradutor.: O engenheiro principal da Zalando, Henning Jacobs, notou várias vezes que usuários do Kubernetes têm dificuldades em entender o propósito dos liveness (e readiness) probes e sua aplicação correta. Por isso, ele organizou seus pensamentos nesta nota concisa, que eventualmente fará parte da documentação do K8s.

As verificações de estado, conhecidas no Kubernetes como liveness probes (ou seja, literalmente, 'testes de viabilidade' — nota do tradutor), podem ser bastante perigosas. Recomendo, sempre que possível, evitá-las; exceções são apenas os casos em que elas são realmente necessárias e você compreende completamente a especificidade e as consequências de seu uso. Nesta publicação, falaremos sobre liveness e readiness probes, e em quais situações está e quando não devemos aplicá-las.
Meu colega Sandor recentemente compartilhou no Twitter os erros mais comuns que ele observa, incluindo aqueles relacionados ao uso de readiness/liveness probes:
Uma configuração inadequada livenessProbe pode agravar situações de alta carga (desligamento em cadeia + possível longo tempo de inicialização do contêiner/aplicação) e levar a outras consequências negativas, como a falha de dependências (veja também sobre limitação de requisições na combinação K3s+ACME). Pior ainda, quando liveness probe é combinado com a verificação de saúde de uma dependência (health check), que é um banco de dados externo: uma única falha no banco de dados pode reiniciar todos os seus contêineres.!
A mensagem geral ‘Não use liveness probes’ neste caso ajuda pouco, então vamos considerar para que servem as verificações de readiness e liveness.
Nota: a maior parte do teste abaixo foi inicialmente incluída na documentação interna para desenvolvedores da Zalando.
Verificações de Readiness e Liveness
O Kubernetes fornece dois mecanismos importantes, chamados de . Eles realizam periodicamente alguma ação — por exemplo, enviando uma solicitação HTTP, abrindo uma conexão TCP ou executando um comando dentro do contêiner — para confirmar que a aplicação está funcionando corretamente.
O Kubernetes utiliza readiness probes, para entender quando o contêiner está pronto para receber tráfego. O pod é considerado pronto quando todos os seus contêineres estão prontos. Uma das aplicações desse mecanismo é controlar quais pods são usados como backends para serviços do Kubernetes (especialmente ingress).
Verificações de liveness ajudam o Kubernetes a entender quando é hora de reiniciar um contêiner. Por exemplo, essa verificação pode interceptar um deadlock, quando a aplicação "fica presa". Reiniciar o contêiner nesse estado ajuda a mover a aplicação do ponto morto, apesar dos erros, mas também pode levar a falhas em cascata (veja abaixo).
Se você tentar implantar uma atualização de aplicação que falhe nas verificações de liveness/readiness, sua implantação será interrompida, pois o Kubernetes aguardará o status Pronto de todos os pods.
Exemplo
Aqui está um exemplo de readiness probe, verificando o caminho /health via HTTP com configurações padrão (interval: 10 segundos, timeout: 1 segundo, threshold de sucesso: 1, threshold de falha: 3):
# часть общего описания deployment'а/стека
podTemplate:
spec:
containers:
- name: my-container
# ...
readinessProbe:
httpGet:
path: /health
port: 8080Recomendações
- Para microsserviços com endpoint HTTP (REST, etc.) sempre defina um readiness probe, que verifica se a aplicação (pod) está pronta para receber tráfego.
- Certifique-se de que o readiness probe cobre a prontidão da porta real do servidor web:
- usando portas para necessidades administrativas, chamadas de "admin" ou "management" (por exemplo, 9090), para
readinessProbe, certifique-se de que o endpoint retorna OK somente se a porta HTTP principal (como 8080) estiver pronta para receber tráfego*;* Tenho conhecimento de pelo menos um caso na Zalando, onde isso não aconteceu, ou seja,
readinessProbeverificou a porta "management", mas o servidor não começou a funcionar devido a problemas de carregamento de cache. - atribuir readiness probe a uma porta separada pode resultar em que a sobrecarga na porta principal não seja refletida na verificação de saúde (ou seja, o pool de threads no servidor está cheio, mas a verificação de saúde ainda mostra que está tudo OK).
- usando portas para necessidades administrativas, chamadas de "admin" ou "management" (por exemplo, 9090), para
- Verifique se a readiness probe inclui inicialização/migração do banco de dados;
- a maneira mais simples de conseguir isso é acessar o servidor HTTP somente após a conclusão da inicialização (por exemplo, migração do banco de dados com etc.); ou seja, em vez de mudar o status da verificação de saúde, simplesmente não inicie o servidor web até que a migração do banco de dados seja concluída*.
* Também é possível executar migrações de banco de dados a partir de contêineres init fora do pod. Eu ainda sou um fã de aplicações autônomas (self-contained), ou seja, aquelas em que o contêiner da aplicação sabe, sem coordenação externa, como deixar o banco de dados no estado desejado.
- a maneira mais simples de conseguir isso é acessar o servidor HTTP somente após a conclusão da inicialização (por exemplo, migração do banco de dados com etc.); ou seja, em vez de mudar o status da verificação de saúde, simplesmente não inicie o servidor web até que a migração do banco de dados seja concluída*.
- Use
httpGetpara verificações de readiness através de endpoints típicos de verificações de saúde (por exemplo,/health). - Entenda os parâmetros das verificações definidas por padrão (
intervalo: 10s,timeout: 1s,successThreshold: 1,failureThreshold: 3):- os parâmetros padrão significam que o pod se tornará não pronto em cerca de 30 segundos (3 verificações de disponibilidade falhadas).
- Use uma porta separada para "admin" ou "management", se a pilha tecnológica (como Java/Spring) permitir, para separar o gerenciamento de "saúde" e métricas do tráfego normal:
- mas não se esqueça do item 2.
- Se necessário, o readiness probe pode ser usado para aquecer/carregar o cache e retornar o código de estado 503 enquanto o contêiner não estiver "aquecido":
- também recomendo examinar a nova verificação
startupProbe, (escrevemos sobre isso em russo — nota do tradutor.).
- também recomendo examinar a nova verificação
Avisos
- Não confie em dependências externas (como bancos de dados) ao realizar testes de readiness/liveness — isso pode levar a falhas em cascata:
- por exemplo, vamos considerar um serviço stateful REST com 10 pods dependentes de um único banco de dados Postgres: quando a verificação depende de uma conexão ativa com o banco de dados, todos os 10 pods podem falhar se houver atraso na rede/na parte do banco de dados — normalmente, tudo isso termina pior do que poderia;
- note que o Spring Data verifica a conexão com o banco de dados por padrão*;
* Este é o comportamento padrão do Spring Data Redis (pelo menos era assim da última vez que verifiquei), o que levou a uma falha "catastrófica": quando o Redis ficou indisponível por um curto período, todos os pods "falharam".
- "externo" neste contexto também pode significar outros pods da mesma aplicação, ou seja, idealmente a verificação não deve depender do estado de outros pods do mesmo cluster para evitar falhas em cascata:
- os resultados podem variar para aplicações com estado distribuído (por exemplo, caching em memória nos pods).
- Não use liveness probe para pods (exceto nos casos em que realmente são necessários e você esteja totalmente ciente das especificidades e consequências de seu uso):
- liveness probe pode ajudar na recuperação de contêineres "congelados", mas, uma vez que você tem controle total sobre sua aplicação, não deveria haver ocorrências como processos "congelados" e deadlocks: a melhor alternativa é causar uma falha intencional na aplicação e retorná-la ao seu estado estável anterior;
- Uma falha na liveness probe levará ao reinício do contêiner, potencialmente agravando as consequências de erros relacionados à inicialização: o reinício do contêiner resultará em um tempo de inatividade (pelo menos, durante o tempo de inicialização do aplicativo, digamos, mais de 30 segundos), causando novos erros, aumentando a carga sobre outros contêineres e elevando a probabilidade de falhas, etc.;
- liveness probes combinadas com dependências externas são a pior combinação possível, ameaçando falhas em cascata: um pequeno atraso no lado do banco de dados fará com que todos os seus contêineres sejam reiniciados!
- As configurações de liveness e readiness probes devem ser diferentes:
- é possível usar uma liveness probe com a mesma verificação de saúde, mas com um limite de disparo mais alto (
failureThreshold), por exemplo, atribuindo um status não pronto após 3 tentativas e considerando que a liveness probe falhou após 10 tentativas;
- é possível usar uma liveness probe com a mesma verificação de saúde, mas com um limite de disparo mais alto (
- Não use exec checks, pois estão associados a problemas conhecidos que levam à criação de processos zumbis:
- detalhes: ver .
Resumo
- Use readiness probes para determinar quando o pod está pronto para receber tráfego.
- Utilize liveness probes apenas quando forem realmente necessárias.
- O uso inadequado de readiness/liveness probes pode resultar em menor disponibilidade e falhas em cascata.
Materiais adicionais sobre o tema
- ;
- ;
- (também fala sobre livenessProbe).
Atualização nº 1 de 2019-09-29
: nota adicionada.
sobre PDB: um dos problemas das liveness probes é a falta de coordenação entre os pods. No Kubernetes, existem para limitar o número de falhas paralelas que uma aplicação pode enfrentar, no entanto, as verificações não consideram o PDB. Idealmente, podemos instruir o K8s: "Reinicie um pod se sua verificação falhar, mas não reinicie todos eles para não piorar ainda mais a situação."
: "Use liveness probing quando você souber com certeza que o melhor a fazer é ‘matar’ o aplicativo" (novamente, não exagere).
Atualização nº 2 de 2019-09-29
: criei um pedido correspondente () para adicionar à documentação sobre liveness probes.
P.S. do tradutor
Confira também em nosso blog:
- «»;
- «»;
- «».
Fonte: habr.com
