Liveness probes reiniciam contêineres travados.
Readiness probes removem instâncias dos endpoints de serviço até que elas possam lidar com requisições.
Startup probes (Kubernetes 1.16+) protegem apps de inicialização lenta antes que a liveness entre em ação.
Handlers de probe devem ser rápidos, idempotentes e livres de middleware de autenticação que bloqueie o tráfego do kubelet.
Cartão de receita de referência rápida - pronto para copiar e colar.
mux. HandleFunc ( "GET /healthz" , func ( w http . ResponseWriter , r * http . Request ) {
w. WriteHeader (http.StatusOK)
w. Write ([] byte ( "ok" ))
})
mux. HandleFunc ( "GET /readyz" , func ( w http . ResponseWriter , r * http . Request ) {
if depsHealthy (r. Context ()) {
w. WriteHeader (http.StatusOK)
return
}
http. Error (w, "not ready" , http.StatusServiceUnavailable)
})
Quando usar isso:
Kubernetes Deployments com probes HTTP
Balanceadores de carga na nuvem que fazem health-check de pools de backend
Implantações contínuas (rolling deploys) que precisam esperar por migrações antes de receber tráfego
Grupos de autoescalonamento substituindo instâncias não saudáveis
Detecção de outliers de malha de serviço que respeita o estado de prontidão
package main
import (
" context "
" database/sql "
" errors "
" log/slog "
" net/http "
" sync "
" time "
_ " github.com/jackc/pgx/v5/stdlib "
)
type App struct {
db * sql . DB
ready sync . RWMutex
isReady bool
}
func ( a * App ) setReady ( v bool ) {
a.ready. Lock ()
a.isReady = v
a.ready. Unlock ()
}
func ( a * App ) checkReady () bool {
a.ready. RLock ()
defer a.ready. RUnlock ()
return a.isReady
}
func ( a * App ) liveness ( w http . ResponseWriter , r * http . Request ) {
w. WriteHeader (http.StatusOK)
w. Write ([] byte ( "ok" ))
}
func ( a * App ) readiness ( w http . ResponseWriter , r * http . Request ) {
if ! a. checkReady () {
http. Error (w, "starting" , http.StatusServiceUnavailable)
return
}
ctx, cancel := context. WithTimeout (r. Context (), 500 * time.Millisecond)
defer cancel ()
if err := a.db. PingContext (ctx); err != nil {
http. Error (w, "db unavailable" , http.StatusServiceUnavailable)
return
}
w. WriteHeader (http.StatusOK)
w. Write ([] byte ( "ready" ))
}
func ( a * App ) business ( w http . ResponseWriter , r * http . Request ) {
w. Write ([] byte ( `{"orders":[]}` ))
}
func main () {
db, err := sql. Open ( "pgx" , "postgres://localhost:5432/app?sslmode=disable" )
if err != nil {
slog. Error ( "db open failed" , "err" , err)
return
}
app := & App {db: db}
mux := http. NewServeMux ()
mux. HandleFunc ( "GET /healthz" , app.liveness)
mux. HandleFunc ( "GET /readyz" , app.readiness)
mux. HandleFunc ( "GET /orders" , app.business)
go func () {
time. Sleep ( 2 * time.Second)
app. setReady ( true )
slog. Info ( "readiness enabled" )
}()
slog. Info ( "listening" , "addr" , ":8080" )
if err := http. ListenAndServe ( ":8080" , mux); err != nil && ! errors. Is (err, http.ErrServerClosed) {
slog. Error ( "listen failed" , "err" , err)
}
}
O que isso demonstra:
Liveness retorna 200 sem tocar no PostgreSQL
Readiness é controlada pela flag de inicialização mais PingContext limitado
Rotas de negócios permanecem separadas dos caminhos de probe
Respostas 503 sinalizam aos balanceadores de carga para parar de enviar tráfego
Kubelet chama a liveness em um intervalo; falhas repetidas reiniciam o contêiner.
O controlador de endpoints remove pods que falham na readiness dos endpoints do Serviço.
Balanceadores de carga espelham a readiness: roteiam apenas para instâncias que retornam sucesso.
Startup probes desativam a liveness até que o app termine a inicialização lenta.
Probe Falha quando Ação do Orquestrador Liveness Processo travado, não pode servir HTTP Reiniciar pod Readiness Dependências inativas, migrações em execução Remover do LB Startup Ainda inicializando após initialDelaySeconds Esperar antes da liveness
Campo Orientação periodSeconds10s típico para readiness; liveness um pouco mais longo timeoutSecondsDeve exceder o pior caso do handler; manter handler abaixo de 1s failureThreshold3 falhas comuns antes da ação successThreshold1 para readiness após recuperação
// Isenta probes de middleware de autenticação caro
func skipProbePaths ( next http . Handler ) http . Handler {
return http. HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
switch r.URL.Path {
case "/healthz" , "/readyz" , "/startupz" :
next. ServeHTTP (w, r)
return
}
authMiddleware (next). ServeHTTP (w, r)
})
}
Verificação de banco de dados na liveness - Um pico no DB reinicia todos os pods; use readiness apenas para verificações de dependência.
Autenticação em /healthz - Kubelet não envia seus tokens de serviço; probes recebem 401 e pods reiniciam.
Handlers de readiness lentos - Verificações longas bloqueiam threads do kubelet e causam instabilidade na readiness; use timeouts curtos.
Retornar 200 durante migrações - Tráfego atinge incompatibilidade de esquema; mantenha readiness como falsa até que as migrações concluam.
Mesmo caminho para liveness e readiness - Você não pode distinguir entre travado e falha de dependência.
Tráfego de probe em métricas - Exclua /healthz de dashboards RED ou rotule probe=true separadamente.
Porta administrativa apenas TLS - Garanta que as probes atinjam a porta e o esquema para os quais o kubelet ou LB está configurado.
3730363230327c3638346f6967637c6f692e73656469756765646f63
Alternativa Use Quando Não Use Quando HTTP /healthz Apps Kubernetes padrão Processo não tem servidor HTTP (use exec/tcp) Protocolo gRPC health Serviços exclusivamente gRPC Microserviços REST simples Probe Exec Scripts de verificação CLI Você pode expor HTTP barato em vez disso Socket TCP Estar ouvindo é suficiente Você precisa de validação de dependência
Qual código de status as probes devem retornar?
200 para saudável, 503 para não pronto.
Evite 401/403 em caminhos de probe.
A readiness deve verificar todas as dependências?
Verifique apenas os requisitos rígidos para atender tráfego.
Recursos opcionais podem degradar sem falhar na readiness se documentados.
Quão rápida a liveness deve ser?
Idealmente sub-milissegundo - sem I/O, apenas verificações em processo.
Para que serve o startupProbe?
Ele impede mortes por liveness enquanto o app carrega caches grandes ou executa migrações na primeira inicialização.
A readiness pode apresentar instabilidade durante implantações?
Sim, se você habilitar a readiness antes que o aquecimento termine.
Atrasar a readiness até que caches e pools de conexão estejam aquecidos.
Preciso de portas separadas?
Opcional.
Muitas equipes servem probes na porta HTTP principal com caminhos dedicados.
Como os health checks do ALB diferem?
ALB usa códigos e caminhos HTTP que você configura, semelhante à readiness.
Eles não reiniciam instâncias - eles param de rotear.
As probes devem acessar o banco de dados a cada 10s?
Ping leve com timeout é comum.
Consultas pesadas pertencem ao monitoramento, não às probes.
E quanto ao health gRPC?
Implemente o RPC Check de grpc.health.v1.Health para serviços nativos gRPC.
Como testo probes localmente?
curl -i localhost:8080/readyz enquanto para o PostgreSQL e verifica se retorna 503.
A readiness pode retornar JSON?
Sim, mas os orquestradores só se importam com códigos de status.
Mantenha corpos pequenos para depuração humana.
Quais cabeçalhos as probes devem enviar?
Nenhum é necessário.
Evite exigir cabeçalhos personalizados que o kubelet não possa configurar facilmente.
Versões de Stack: Esta página foi escrita para Go 1.26.x (padrão GC Green Tea, modernizadores go fix - verifique o patch na compilação) , chi (última - verifique na compilação), gin (última - verifique na compilação), echo (última - verifique na compilação), google.golang.org/grpc (última - verifique na compilação), sigs.k8s.io/controller-runtime (última - verifique na compilação), kubebuilder (última - verifique na compilação), tinygo (última - verifique os alvos de placa na compilação), wazero (última - verifique na compilação) e golangci-lint (última - verifique o conjunto de linters na compilação).