Quando um pod com sidecar proxy injetado é encerrado, requisições de longa duração podem ser descartadas ou falhar. Por padrão, o Istio interrompe forçadamente o sidecar proxy 5 segundos após receber o sinal de encerramento (terminationDrainDuration = 5s). Requisições que excedem essa janela são terminadas independentemente do estado de processamento.
Sintomas
Após a parada de um pod com sidecar proxy injetado, ocorrem dois tipos de falhas:
Requisições de entrada são descartadas. Requisições de longa duração enviadas a esse pod se perdem durante o processamento porque o proxy desliga antes da conclusão das requisições.
Requisições de saída falham. As requisições que a aplicação envia para outros serviços por meio do proxy falham porque o proxy já foi interrompido.
Causa raiz
Com a injeção do sidecar proxy, todo o tráfego do pod flui através dele. Quando o Kubernetes inicia o encerramento de um pod, dois processos ocorrem em paralelo:
O Kubernetes remove o pod dos endpoints do Service. O novo tráfego deixa de ser roteado para esse pod.
O Istio inicia a drenagem do sidecar proxy. Ao receber o sinal SIGTERM, o
istio-agentinstrui o Envoy a iniciar uma drenagem controlada: ele rejeita novas conexões enquanto permite a conclusão das existentes. Após o término daterminationDrainDuration, o Istio encerra o proxy forçadamente.
A terminationDrainDuration padrão é de 5 segundos. Durante essa janela:
Nenhum novo tráfego de entrada é aceito.
As conexões de entrada existentes continuam sendo processadas.
As conexões de saída permanecem funcionais.
Se alguma requisição durar mais de 5 segundos, o proxy será encerrado e todas as conexões de entrada e saída restantes serão descartadas.
Ciclo de vida de encerramento do Kubernetes
Compreender a sequência de encerramento de pods do Kubernetes é essencial para configurar os timeouts corretamente:
O Kubernetes envia um sinal SIGTERM para todos os containers no pod.
Cada container lida com o sinal conforme sua própria lógica (por exemplo, o Istio inicia a drenagem do proxy).
O Kubernetes aguarda até
terminationGracePeriodSeconds(padrão: 30 segundos) para que todos os containers sejam encerrados.Caso algum container ainda esteja em execução após o período de carência, o Kubernetes envia um SIGKILL para forçar o encerramento.
A principal restrição de tempo é:
preStop hook duration + terminationDrainDuration < terminationGracePeriodSeconds
Se o tempo combinado exceder terminationGracePeriodSeconds, o Kubernetes enviará um SIGKILL e encerrará forçadamente todos os containers, ignorando completamente a drenagem controlada.
Soluções
Solução 1: Estender a duração da drenagem de encerramento
Aumente a duração da drenagem para dar tempo suficiente às conexões de longa duração para que sejam concluídas. Essa abordagem funciona melhor quando é possível estimar a duração máxima da requisição.
Faça login no console do ASM. No painel de navegação à esquerda, escolha .
Na página Mesh Management, clique em nome da instância do ASM. No painel de navegação à esquerda, escolha .
Na página Sidecar Proxy Setting, clique em aba Namespace.
Selecione um namespace na lista suspensa Namespace. Clique em Lifecycle Management, selecione Sidecar Proxy Drain Duration at Pod Termination, insira um valor que exceda a duração mais longa esperada para suas requisições e clique em Update Settings.
Nota
A duração da drenagem deve ser menor que o
terminationGracePeriodSeconds
do pod (padrão: 30 segundos). Se a duração da drenagem exceder o período de carência, o Kubernetes enviará um SIGKILL e encerrará forçadamente todos os containers, ignorando a drenagem controlada.
Solução 2: Usar um hook preStop para aguardar requisições ativas
Quando as durações das requisições são imprevisíveis, configure um hook de ciclo de vida preStop no sidecar proxy. O hook verifica periodicamente as conexões ativas e atrasa o desligamento do proxy até que todas as requisições sejam concluídas, em vez de depender de um timeout fixo.
Como funciona: O script preStop verifica a cada segundo se há conexões TCP não relacionadas ao Envoy. Assim que todas as conexões da aplicação forem fechadas, o sidecar proxy será encerrado de forma controlada após a drenagem padrão de 5 segundos.
Faça login no console do ASM. No painel de navegação à esquerda, escolha .
Na página Mesh Management, clique em nome da instância do ASM. No painel de navegação à esquerda, escolha .
Na página Sidecar Proxy Setting, clique em aba Namespace.
-
Selecione um namespace na lista suspensa Namespace. Clique em Lifecycle Management, selecione Lifecycle of Sidecar Proxy, insira o seguinte JSON no editor de código e clique em Update Settings.
Os dois hooks têm finalidades diferentes:
Hook
Finalidade
postStartExecuta
pilot-agent waitpara garantir que o sidecar proxy esteja totalmente pronto antes que o container da aplicação comece a aceitar tráfego.preStopVerifica periodicamente conexões TCP ativas (excluindo as próprias conexões do Envoy). O sidecar proxy só é desligado após o fechamento de todas as conexões da aplicação.
{ "postStart": { "exec": { "command": [ "pilot-agent", "wait" ] } }, "preStop": { "exec": { "command": [ "/bin/sh", "-c", "while [ $(netstat -plunt | grep tcp | grep -v envoy | wc -l | xargs) -ne 0 ]; do sleep 1; done" ] } } }
Nota
O tempo total gasto no hook
preStop
mais a duração da drenagem não deve exceder o
terminationGracePeriodSeconds
do pod. Se suas cargas de trabalho tiverem requisições de duração muito longa, aumente o
terminationGracePeriodSeconds
no nível do pod adequadamente.
Qual solução escolher
|
Cenário |
Solução recomendada |
|
Durações de requisição previsíveis (por exemplo, menos de 60 segundos) |
Solução 1: Defina a duração da drenagem com um valor que exceda sua requisição mais longa esperada. |
|
Durações de requisição variáveis ou imprevisíveis |
Solução 2: Utilize um hook |
|
Coexistência de requisições de longa e curta duração |
Combine ambas: defina uma duração de drenagem razoável como rede de segurança e adicione o hook |