Destino Dev

Blog

Health checks e readiness probes em containers Docker para Node.js: passo a passo

Por John Pires · 08 de março de 2026

Health checks e readiness probes em containers Docker para Node.js: passo a passo

1) Por que aprender isso em 2026

O problema que resolve

Aplicacoes em containers sao replicaveis e moveis, mas sem verificacoes ativos elas falham de maneiras silenciosas: processos travam, dependencias externas estouram e orquestradores mantem instancias inutilizaveis no ar. Health checks e readiness probes permitem detetar e reagir automaticamente a falhas, reduzindo tempo de indisponibilidade e melhorando o comportamento em producao.

Contexto 2026: orquestradores e CI/CD

Em 2026, implantar containers continua sendo padrao. Kubernetes, Docker Swarm e pipelines CI/CD (GitHub Actions, GitLab CI) assumem que containers informem seu estado. Saber como expor endpoints de saude no Node.js e configurar probes em Dockerfile, docker-compose e manifestos Kubernetes e pipeline de CI e essencial para qualquer engenheiro DevOps ou desenvolvedor backend.

Resultado pratico: com probes basicas voce consegue que um orchestrator remova pods com falha, que CI pare o deploy se a app nao subir corretamente e que sistemas de monitoramento alertem so quando realmente necessario.

Tip: probes nao substituem logs e metrics. Elas sao sinais booleanos simples pensados para controle de ciclo de vida do container.

2) Configuracao do ambiente

Ferramentas que vamos usar

Para seguir os passos precisa de: Docker (desktop ou engine), Node.js 18+, npm/yarn, curl (ou httpie) e opcionalmente um cluster Kubernetes (minikube, kind). Para CI usaremos GitHub Actions como exemplo. Instale localmente o Docker e o Node.js para testes antes de migrar para um cluster.

Estrutura do projeto

Vamos criar um projeto pequeno com: package.json, app.js, um Dockerfile, docker-compose.yml e um exemplo de manifest Kubernetes. A estrutura basica:

  • package.json
  • app.js
  • Dockerfile
  • docker-compose.yml
  • k8s/deployment.yml

Crie uma pasta vazia e inicialize npm com npm init -y. Em seguida instale express: npm install express. Esses comandos assumem que voce esta em um terminal com Node.js instalado.

3) Hello World progressivo

Node.js com endpoints de health e readiness

Primeiro passo: o servidor Node.js deve expor dois endpoints claros: /healthz (liveness) e /ready (readiness). Liveness responde se o processo esta vivo. Readiness responde se a aplicacao esta apta a receber trafego (conexoes a banco, caches prontos, dependencias saudaveis).

Crie um arquivo app.js com um exemplo simples que simula dependencias. O codigo abaixo cria dois endpoints e um mecanismo para simular que a aplicacao so fica pronta apos um timeout para ilustrar probes.

// app.js
const express = require('express')
const app = express()
const port = process.env.PORT || 3000

let ready = false

// Simula inicializacao de dependencia assincrona
setTimeout(() => {
  ready = true
  console.log('Dependencias prontas, app pronta para receber trafego')
}, 5000)

app.get('/healthz', (req, res) => {
  // Liveness: processo vivo? basta responder 200
  res.status(200).send('ok')
})

app.get('/ready', (req, res) => {
  // Readiness: depende de variavel ready
  if (ready) return res.status(200).json({ ready: true })
  return res.status(503).json({ ready: false })
})

app.get('/', (req, res) => {
  res.send('app principal: respondendo')
})

app.listen(port, () => {
  console.log(`Server listening on port ${port}`)
})

O que esse bloco faz: cria um servidor express que retorna 200 em /healthz enquanto o processo estiver vivo e 503 em /ready ate que as dependencias sejam consideradas prontas.

Depois de executar node app.js localmente, voce deve ver a mensagem de inicializacao e poder testar com curl localhost:3000/ready que inicialmente retorna 503 e, apos 5s, passa a 200.

Dockerfile com healthcheck embutido

Agora empacotamos em um container. Docker tem instrucao HEALTHCHECK que permite ao engine executar um comando para verificar se o container esta vivo. Para comportamento de readiness no nivel do orchestrador, preferimos que o processo exponha endpoints e o orchestrador (docker-compose ou k8s) faça as probes.

# Dockerfile
FROM node:18-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=3 \
  CMD wget -qO- http://localhost:3000/healthz || exit 1
CMD ["node", "app.js"]

O que esse Dockerfile faz: instala dependencias, expoe a porta e define um HEALTHCHECK que usa wget para acessar /healthz. Se o comando falhar repetidas vezes o Docker marca o container como unhealthy.

Teste localmente com:

docker build -t node-health-example .
docker run -p 3000:3000 --name node-health node-health-example

Depois, rode docker ps e docker inspect --format='{{json .State}}' node-health para ver o estado health. Durante os primeiros 5s a probe deve reportar healthy apos o start-period.

4) Mini-projeto pratico

docker-compose com healthcheck e dependencia de serviço

Vamos compor um exemplo com um serviço que depende de um banco (simulado por um serviço dummy). Usaremos docker-compose para demonstrar ordem de start e condicionais simples.

# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - '3000:3000'
    depends_on:
      - dummydb
    healthcheck:
      test: [ 'CMD', 'wget', '-qO-', 'http://localhost:3000/healthz' ]
      interval: 10s
      timeout: 5s
      retries: 3
    environment:
      - DUMMYDB_HOST=dummydb

  dummydb:
    image: alpine
    command: sh -c "sleep 3000"
    healthcheck:
      test: [ 'CMD-SHELL', 'echo ok' ]
      interval: 30s

O que acontece aqui: dummydb e um container que literalmente dorme (simulando dependencia). app depende de dummydb para iniciar, mas a readiness do app continua sendo determinada pelo endpoint /ready e pelo HEALTHCHECK da service. Note que docker-compose only honoured depends_on para ordem de start, nao para readiness — composable nao bloqueia ate que healthcheck de dependencia esteja healthy em todas as versoes, entao planeje isso.

Manifeste Kubernetes com liveness e readiness

Em Kubernetes voce deve configurar probes diretamente no spec do container. Exemplo abaixo mostra como configurar livenessProbe e readinessProbe usando HTTP GET. Isso permite que o kubelet reinicie o container quando necessario e que Services so encaminhem trafego para pods prontos.

# k8s/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-health-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: node-health
  template:
    metadata:
      labels:
        app: node-health
    spec:
      containers:
        - name: node-health
          image: node-health-example:latest
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 2
            periodSeconds: 3
            failureThreshold: 5
          livenessProbe:
            httpGet:
              path: /healthz
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 10
            failureThreshold: 3

O que acontece quando aplica esse manifest: o kubelet usa readiness para decidir se o pod recebe trafego e liveness para reiniciar containers travados. Note que readiness tem initialDelay menor para detectar disponibilidade mais rapida, enquanto liveness usa intervalo maior para evitar reinicios desnecessarios.

CI/CD: GitHub Actions checando health antes de promover artefato

Um passo comum em pipelines e garantir que a imagem constrida responde ao health check antes de subir para registries ou promover para ambientes superiores. Exemplo basico de job que constrói imagem, executa container e aguarda healthcheck com curl.

# .github/workflows/health-check.yml (trecho)
name: build-and-test-health
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t node-health:ci .
      - name: Run container
        run: docker run -d --name node-health-ci -p 3000:3000 node-health:ci
      - name: Wait for readiness
        run: |
          for i in $(seq 1 20); do
            if curl -sSf http://localhost:3000/ready >/dev/null 2>&1; then
              echo 'ready'
              exit 0
            fi
            echo 'waiting...'
            sleep 2
          done
          echo 'readiness timed out' && exit 1

Esse job falha se a readiness nao for atingida em tempo util, protegendo ambientes seguintes de deploy com uma imagem que nao esta funcional.

Erros comuns e dicas praticas

1. Health endpoint que faz trabalho pesado

Armadilha: implementar checks profundos e caros no endpoint de health. Probes devem ser rapidas e deterministicas. Se precisar rodar verificacoes pesadas, exponha um endpoint separado ou crie um job de verificacao assíncrona.

2. Confiar apenas no Docker HEALTHCHECK

O Docker HEALTHCHECK eh util para o engine local, mas orquestradores como Kubernetes ignoram o HEALTHCHECK do Dockerfile. Em K8s configure liveness/readiness no manifesto. Nao confie apenas no Dockerfile quando usar K8s.

Mais dicas:

  • Use status codes HTTP: 200 para ok, 503/500 para nao pronto ou falha.
  • Configure initialDelay apropriadamente para evitar falso-positivos durante startup.
  • Tenha metricas para entender porque uma readiness cai: logs, traces e metrics complementam probes.
Pratica: mantenha endpoints de probe simples. Se algo complexo falhar, exponha um indicador simples que reflita o estado consolidado.

5) Recursos para continuar estudando

Documentacao oficial e guias

Leia documentacao oficial do Docker sobre HEALTHCHECK e a documentacao do Kubernetes sobre livenessProbe e readinessProbe. Esses guias explicam parametros e o comportamento em cada runtime.

Tutorials e ferramentas

Explore: kubelet probe examples, docker-compose nuances e ferramentas de teste como kubeval para validar manifestos, e kind/minikube para criar clusters locais. Ferramentas de observabilidade (Prometheus, Grafana, Loki) ajudam a correlacionar probes e logs.

Recomendo praticar criando pipelines simples no GitHub Actions que constroem, rodam e validam probes automaticamente. Isso traz confiança no deploy continuo.

Conclusao pratica

Health checks e readiness probes sao pequenos contratos entre sua aplicacao e a infraestrutura. Implementar endpoints simples no Node.js, configurar HEALTHCHECK no Dockerfile e probes no Kubernetes e nas pipelines permite que o sistema detecte falhas rapidamente e reaja de forma automatizada. Isso reduz MTTR e melhora a confiabilidade.

Passos sequentialmente praticos para aplicar o que vimos:

  1. Expor /healthz e /ready no Node.js com respostas rapidas e deterministicas.
  2. Adicionar HEALTHCHECK no Dockerfile para feedback local e em CI.
  3. Configurar readiness e liveness no manifest de Kubernetes para controle fino.
  4. Adicionar etapa de verificacao de readiness nos pipelines (GitHub Actions).

Voce agora tem um fluxo de trabalho completo: codigo que expoe probes, container que reporta health e orquestrador que decide quando reiniciar ou rotear trafego. Em producao, combine isso com logs estruturados e metricas para diagnostico rapido.

Terminando: implemente probes pequenas, padronize respostas HTTP e configure tempos coerentes com o tempo real de inicializacao de suas dependencias. Assim voce evita reinicios desnecessarios e garante que o trafego sempre passe para instancias aptas.

Assuntos: Node.js, Docker, Kubernetes, github-actions

Leia também