Marcio Cunha

Aplicação travando? Como configurar liveness e readiness probes

Aprenda a configurar liveness e readiness probes em containers para evitar reinicializações desnecessárias e quedas de tráfego na sua aplicação.

Marcio Cunha•5 min
Também disponível em:EnglishEspañol
Resumo
  • Verificações de saúde evitam que o orquestrador envie tráfego para instâncias instáveis
  • Ajustar intervalos e limites de falhas previne reinicializações em cascata
  • Liveness cuida de travamentos internos enquanto readiness gerencia o fluxo de tráfego
  • Monitorar SLOs ajuda a calibrar o tempo de resposta aceitável para as sondas
  • Ferramentas como Prometheus complementam a observabilidade além das sondas nativas

Por que sua aplicação reinicia do nada?

Quando rodamos aplicações em sistemas de containers como o Kubernetes, o orquestrador precisa saber se o software está realmente vivo ou se apenas ocupando espaço na memória. Na prática, isso significa que um processo pode estar rodando e, ao mesmo tempo, incapaz de responder a qualquer requisição porque travou em um deadlock de banco de dados. Para evitar que os usuários enfrentem telas de erro eternas, utilizamos mecanismos de inspeção conhecidos como verificações de saúde. Antes de colocar um sistema em produção, garantir a resiliência exige entender exatamente como o orquestrador interage com a sua aplicação através de sondas automatizadas.

Sem uma configuração adequada, qualquer oscilação momentânea na rede ou na carga de trabalho pode fazer com que o sistema mate o container de forma agressiva. Isso gera um ciclo vicioso de reinicializações desnecessárias que consome recursos preciosos de CPU e memória. Além disso, quando novos containers entram no ar, eles frequentemente recebem tráfego antes mesmo de carregarem os dados em cache, resultando em lentidão visível. Para mitigar esses cenários, a engenharia de confiabilidade utiliza dois conceitos fundamentais que trabalham em conjunto, mas com propósitos totalmente diferentes: as sondas de vivência e as sondas de prontidão.

Entendendo a diferença entre liveness e readiness

A sonda de vivência, ou liveness probe, tem uma missão muito específica: descobrir se o container travou de vez e precisa ser completamente reiniciado do zero. Na prática, se essa verificação falhar repetidas vezes, o orquestrador destrói o processo atual e cria um novo container para ocupar o seu lugar. Um erro clássico é configurar essa verificação apontando para uma rota pesada que depende de serviços externos, como consultas a APIs de terceiros. Se a API externa cair, a sua aplicação inteira começa a ser reiniciada sem necessidade, agravando ainda mais o problema original que estava fora do seu controle.

Por outro lado, a sonda de prontidão, ou readiness probe, decide se o container está pronto para receber tráfego de rede dos usuários. Pense nisso como um caixa de supermercado que coloca a placa de 'aberto' apenas depois de ligar o sistema e contar o troco na gaveta. Se a prontidão falhar, o container não é reiniciado; ele apenas é isolado temporariamente do balanceador de carga até que consiga responder com sucesso novamente. Essa separação garante que requisições reais nunca caiam em uma instância que acabou de iniciar e ainda está aquecendo conexões ou compilando templates internos.

Como configurar liveness e readiness na prática

Configurar essas verificações exige cuidado com os tempos de espera e com os limites de tolerância a falhas. Se você definir um intervalo curto demais entre as checagens, qualquer pico momentâneo de uso de CPU será interpretado como uma falha catastrófica. Na prática, o arquivo de configuração do seu container deve equilibrar o tempo que a aplicação leva para iniciar com a frequência das inspeções de rotina. Abaixo, temos um exemplo prático de manifesto em YAML aplicando essas diretrizes em um ambiente de microsserviços:

apiVersion: v1
kind: Pod
metadata:
  name: minha-aplicacao
spec:
  containers:
  - name: app
    image: minha-imagem:v1
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

No exemplo acima, a sonda de vivência espera trinta segundos antes de começar a testar a rota de saúde, dando tempo suficiente para o binário iniciar na memória. Enquanto isso, a sonda de prontidão começa a verificar a rota de prontidão logo aos cinco segundos, permitindo que o tráfego chegue assim que os componentes essenciais estiverem ativos. Essa sintonia fina evita que o sistema sofra com reinicializações prematuras e garante uma transição suave durante atualizações de versão. Se precisar escalar infraestruturas complexas, vale a pena consultar estratégias complementares como as discutidas em como escalar runners no Kubernetes para manter a estabilidade operacional.

Armadilhas comuns e como evitar quedas de tráfego

Um dos erros mais comuns cometidos por equipes de engenharia é utilizar a mesma rota de código para ambas as verificações. Quando você aponta liveness e readiness para o mesmo endpoint que valida o banco de dados, o sistema fica vulnerável a falhas sistêmicas em cascata. Se o banco de dados sofre uma lentidão momentânea, todas as instâncias da aplicação falham na vivência ao mesmo tempo e o orquestrador decide matar todas elas simultaneamente. Isso gera um apagão total em vez de uma degradação graciosa do serviço, sobrecarregando ainda mais a infraestrutura com novas conexões simultâneas.

Para evitar esse comportamento indesejado, crie rotas isoladas e leves no seu código para cada tipo de verificação. A rota de vivência deve apenas checar se a thread principal está respondendo e se não há deadlocks graves na memória interna. Já a rota de prontidão pode realizar verificações mais profundas, como testar se as tabelas principais do banco respondem ou se o cache local está populado. Além disso, para manter uma visão clara da saúde do sistema em produção, você pode correlacionar essas métricas com o uso de recursos, garantindo que o pipeline e o ambiente estejam otimizados, conforme abordamos nas dicas sobre como acelerar builds no Docker com cache.

Considerações finais

Dominar a configuração de liveness e readiness probes é o divisor de águas entre uma aplicação frágil que cai ao primeiro sinal de estresse e um sistema resiliente que se recupera sozinho. Ao separar a lógica de vivência da lógica de prontidão, você protege seus containers contra reinicializações agressivas e impede que usuários acessem instâncias que ainda não estão prontas. Lembre-se de ajustar os parâmetros de tempo de acordo com a realidade do seu software, evitando testes excessivos que consomem recursos sem trazer valor real. Com essas práticas implementadas, sua arquitetura ganha a estabilidade necessária para operar em escala sem sustos de última hora.