Healthcheck e restart policy
Um container 'rodando' e um container funcionando não são a mesma coisa — e o que o Docker faz quando ele cai depende de uma configuração que não vem ligada por padrão.
docker ps mostra "Up 3 hours" pra um container travado, sem responder nenhuma requisição, do mesmo jeito que mostra pra um saudável — o processo continua vivo, só não faz mais nada útil. Docker, por padrão, não sabe diferenciar essas duas situações. HEALTHCHECK e restart policy juntos resolvem isso: um define como detectar que algo está errado, o outro define o que fazer a respeito.
HEALTHCHECK no Dockerfile
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1--interval de quanto em quanto tempo rodar a checagem (aqui: a cada 10s)
--timeout quanto tempo esperar a checagem responder antes de considerar falha
--retries quantas falhas seguidas até marcar o container como "unhealthy"
CMD o comando que decide sucesso/falha pelo código de saída (0 = saudável, qualquer outro = falha)Com isso, docker ps passa a mostrar (healthy), (unhealthy) ou (health: starting) ao lado do container — informação que antes simplesmente não existia.
Healthcheck no compose (não precisa estar só no Dockerfile)
services:
api:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 3s
retries: 3Declarar no compose é útil quando a mesma imagem é reusada em contextos diferentes e você quer um healthcheck específico pra um deploy — o valor do compose sobrescreve o que estiver no Dockerfile.
restart policy: o que fazer quando o container cai
no nunca reinicia sozinho (padrão quando "restart" não é declarado)
always sempre reinicia, mesmo depois de "docker stop" seguido de reinício do daemon Docker
on-failure só reinicia se o processo sair com código de erro (diferente de 0) — saída limpa não reinicia
unless-stopped como "always", mas respeita um "docker stop" manual: se você parou de propósito, não volta sozinhoservices:
api:
build: .
restart: unless-stoppedEm produção, unless-stopped é o mais comum: se o container crashar, reinicia sozinho; se alguém (ou um script de deploy) parar o container de propósito, ele não fica ressuscitando no meio de uma manutenção. on-failure faz sentido pra jobs que devem rodar uma vez e terminar — reiniciar só importa se deram erro.
depends_on com condition: service_healthy
Um depends_on simples (o que a trilha de fundamentos usou) só espera o container do outro serviço iniciar — não que ele esteja pronto pra aceitar conexão. Um Postgres recém-iniciado ainda gasta um tempo inicializando antes de aceitar conexões; uma API que sobe rápido demais pode tentar conectar antes disso e cair. Combinando depends_on com o healthcheck do banco, dá pra esperar de verdade.
services:
api:
build: .
depends_on:
db:
condition: service_healthy # espera "db" ficar healthy, não só "started"
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 5Exercício
Um worker de fila (processa jobs em background) tem restart: on-failure e termina normalmente (código 0) depois de processar todos os jobs pendentes uma única vez, por design. Depois de um deploy, o time percebe que o worker não está mais rodando — docker ps -a mostra ele como "Exited (0)". Isso é um bug do restart policy?