wlls / devops / healthcheck-no-docker-compose-como-configurar-direito
devops

Healthcheck no Docker Compose: como configurar direito

wander·23 de set.·5 min de leitura

Um container em estado running só diz que o processo principal está vivo. Não diz que o banco aceita conexões nem que a API responde. O healthcheck cobre essa diferença: ele roda um comando periódico dentro do container e marca o serviço como healthy ou unhealthy.

Este post mostra como configurar isso no Compose e como usar o resultado para ordenar a subida dos serviços.

Premissas e limitações

Leia isto antes de copiar qualquer coisa.

  • Cobertura da pesquisa insuficiente. A única fonte extraída foi a página de referência de serviços do Compose (docs.docker.com/reference/compose-file/services/), e o texto veio truncado antes das seções healthcheck e depends_on. Nada do que segue sobre esses atributos foi confirmado a partir do material coletado.
  • Origem do conteúdo. Os campos, os valores padrão e o comportamento descritos aqui vêm do conhecimento geral sobre o Compose, não de citação direta da documentação. Confirme cada item na seção healthcheck e na seção depends_on da mesma página de referência, e na referência de HEALTHCHECK do Dockerfile.
  • Nada foi executado. Os exemplos abaixo não foram testados neste ambiente. Ajuste versões de imagem e comandos ao seu caso.
  • Os exemplos usam postgres:18 e nginx, que aparecem nos exemplos da página de referência. Os demais nomes de serviço e imagens são ilustrativos.

Os campos do healthcheck

O bloco healthcheck fica dentro de um serviço:

services:
  db:
    image: postgres:18
    environment:
      POSTGRES_USER: app
      POSTGRES_DB: app
      POSTGRES_PASSWORD: example
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s

O que cada campo faz:

  • test: o comando que decide a saúde. Exit code 0 significa saudável, 1 significa não saudável.
  • interval: intervalo entre execuções do teste.
  • timeout: tempo máximo que uma execução pode levar antes de contar como falha.
  • retries: quantas falhas consecutivas são necessárias para marcar o container como unhealthy.
  • start_period: janela inicial em que falhas não contam contra retries, para dar tempo de o serviço subir.
  • start_interval: intervalo de teste durante o start_period. É mais recente e depende da versão do Compose e do Engine. Verifique se seu ambiente suporta.

Pelo que conheço, os padrões são interval: 30s, timeout: 30s, retries: 3 e start_period: 0s. Confirme na documentação. Repare que 30 segundos de intervalo com 3 tentativas significa mais de um minuto até detectar uma falha, o que raramente serve para um ambiente de desenvolvimento.

As formas de test

Existem três formas, e a escolha importa:

# 1. CMD: executa o binário direto, sem shell
test: ["CMD", "pg_isready", "-U", "app"]

# 2. CMD-SHELL: passa a string para o shell do container
test: ["CMD-SHELL", "pg_isready -U app || exit 1"]

# 3. String simples: equivale a CMD-SHELL
test: pg_isready -U app

# Desativar um healthcheck herdado da imagem
test: ["NONE"]

Use CMD quando não precisar de pipe, redirecionamento ou variável de ambiente. Use CMD-SHELL quando precisar, por exemplo para expandir $POSTGRES_USER. Nesse caso, escape o cifrão no Compose ($$POSTGRES_USER), senão o Compose tenta interpolar a variável no host antes de o container ver o comando.

Exemplos por tipo de serviço

Postgres

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
  interval: 5s
  timeout: 3s
  retries: 10
  start_period: 15s

pg_isready verifica se o servidor aceita conexões. Ele não valida se o schema está pronto nem se as migrações rodaram.

Serviço HTTP

healthcheck:
  test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
  interval: 10s
  timeout: 3s
  retries: 3
  start_period: 30s

A flag -f faz o curl retornar erro em respostas HTTP 4xx e 5xx. Sem ela, um 500 passaria como sucesso.

Se a imagem não tiver curl, tente wget:

test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]

Em imagens mínimas (distroless, scratch), pode não haver nenhum dos dois. Nesse caso, faça o binário da aplicação expor um subcomando de verificação, ou adicione uma ferramenta pequena à imagem.

Ordenando a subida com depends_on

O healthcheck sozinho só muda o status. Para o Compose esperar por ele, use a forma longa de depends_on:

services:
  api:
    build: ./api
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:18
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
      interval: 5s
      timeout: 3s
      retries: 10

A forma em lista (depends_on: [db]), como no exemplo do serviço proxy na página de referência, só controla a ordem de início. O material coletado não indica que ela espere o serviço ficar saudável, e pelo que conheço ela não espera. Se a API precisa do banco pronto, use condition: service_healthy.

Existem outras condições, como service_started e service_completed_successfully. Vale ler a lista completa na documentação de depends_on.

Armadilhas comuns

  • Imagem sem curl ou wget. O teste falha com "executable not found" e o container fica unhealthy para sempre. Confirme o binário com docker compose exec <servico> which curl.
  • start_period curto demais. Aplicações JVM ou com migrações pesadas passam do tempo e acumulam falhas antes de subir.
  • Health endpoint que só devolve 200. Um /health que não toca nas dependências diz que o processo está de pé, não que o serviço funciona. Decida conscientemente o que ele deve verificar.
  • Cifrão sem escape. $VAR é interpolado pelo Compose no host. Use $$VAR para que o shell do container resolva.
  • timeout maior que interval. Execuções se sobrepõem em cenários de lentidão e o resultado fica difícil de interpretar.
  • Esperar que unhealthy reinicie o container. Por si só, o healthcheck não reinicia nada no Compose. Ele muda o status. Reinício depende de restart e do processo terminar.

Como validar

docker compose up -d
docker compose ps
docker inspect --format '{{json .State.Health}}' <container>

O docker compose ps mostra (healthy), (unhealthy) ou (health: starting) no status. O docker inspect mostra as últimas execuções, com saída e exit code, o que ajuda a entender por que um teste falha.

Próximo passo

Pegue um serviço do seu Compose que outro serviço consome, adicione um healthcheck com start_period realista e troque o depends_on em lista por condition: service_healthy. Depois, confira na documentação oficial os padrões e o suporte a start_interval na sua versão do Compose, já que esses pontos não foram verificados aqui.

#docker-compose#healthcheck#depends-on#postgres#pg-isready#docker