Guia: health checks e readiness probes para aplicações PHP em Docker Swarm com dependência de banco e cache — práticas que funcionam
Por Kevin Marcondes · Publicado em · 9 min de leitura
Guia: health checks e readiness probes para aplicações PHP em Docker Swarm com dependência de banco e cache. Você verá como escrever um healthcheck profundo em PHP, orquestrar dependências no entrypoint e implementar readiness de verdade via proxy. Incluímos exemplos de stack.yml, scripts e critérios de tempo para reduzir erros 502 e loops de restart.
Saúde vs readiness no Swarm: visão prática
Health check verifica se o container está operacional. Readiness indica se a instância pode receber tráfego sem erros. Em Docker Swarm, o HEALTHCHECK não remove tasks do balanceamento da mesh, então ele não controla tráfego sozinho.
A abordagem sólida para PHP com banco e cache inclui: um HEALTHCHECK profundo em PHP, um entrypoint que espera dependências, e um proxy (Traefik/HAProxy) validando um endpoint /ready. Rolling updates com start-first e delays aquecem novas réplicas.
Se você usa Compose no dia a dia, veja o guia complementar health checks em Docker Compose para PHP para entender o que reaproveitar e o que muda no Swarm.
- Health check: estado do container (exit code).
- Readiness: apto a receber tráfego sem erros de dependência.
- Swarm não usa HEALTHCHECK para filtrar tráfego na mesh.
- Use proxy com checagem HTTP para readiness.
- Use update_config para atualizações graduais.
Como escrever um healthcheck de PHP que valida banco e cache?
Um healthcheck eficaz testa as dependências críticas. No PHP-FPM, rode um script PHP via CLI que tenta SELECT 1 no Postgres (ou MySQL) e PING no Redis. Se uma etapa falhar, retorne status 1. Configure intervalos curtos e start_period para evitar falsos negativos na inicialização.
O exemplo abaixo espera variáveis como DB_DSN, DB_USER, DB_PASS e REDIS_URL. Ele usa a extensão Redis se disponível e faz fallback para TCP simples.
<?php
declare(strict_types=1);
function fail(string $msg): void {
fwrite(STDERR, $msg.PHP_EOL);
exit(1);
}
$errors = [];
$dbDsn = getenv('DB_DSN') ?: '';
$dbUser = getenv('DB_USER') ?: '';
$dbPass = getenv('DB_PASS') ?: '';
if ($dbDsn) {
try {
$pdo = new PDO($dbDsn, $dbUser, $dbPass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 2,
]);
$pdo->query('SELECT 1');
} catch (Throwable $e) {
$errors[] = 'db';
}
}
$redisUrl = getenv('REDIS_URL') ?: '';
if ($redisUrl) {
$parts = parse_url($redisUrl);
$host = $parts['host'] ?? '127.0.0.1';
$port = (int)($parts['port'] ?? 6379);
$pass = $parts['pass'] ?? null;
try {
if (class_exists('Redis')) {
$r = new Redis();
$r->connect($host, $port, 1.5);
if ($pass) { $r->auth($pass); }
$r->ping();
} else {
$fp = @fsockopen($host, $port, $errno, $errstr, 1.5);
if (!$fp) { throw new RuntimeException('redis tcp failed'); }
fclose($fp);
}
} catch (Throwable $e) {
$errors[] = 'redis';
}
}
if ($errors) {
fail('Unhealthy: '.implode(',', $errors));
}
echo "OK\n";
Configurando o HEALTHCHECK e a stack do Swarm
Defina o HEALTHCHECK no Dockerfile e referencie-o no serviço da stack. Use retries, interval e start_period compatíveis com o tempo de boot e warming da aplicação. Start_period curto demais causa falso negativo. Em Swarm, combine com update_config para atualizações seguras.
O exemplo mostra 3 réplicas, ordem start-first e rollback automático ao detectar falhas durante o monitoramento do update. Lembre que o HEALTHCHECK por si só não controla a entrega de tráfego na mesh.
version: "3.9"
services:
app:
image: registry.example.com/myapp:latest
env_file:
- app.env
healthcheck:
test: ["CMD", "php", "/app/.health/deep-healthcheck.php"]
interval: 10s
timeout: 3s
start_period: 20s
retries: 3
deploy:
replicas: 3
update_config:
parallelism: 1
order: start-first
delay: 10s
failure_action: rollback
monitor: 15s
restart_policy:
condition: any
max_attempts: 3
window: 30s
networks: ["frontend", "backend"]
web:
image: nginx:alpine
ports: ["80:80"]
networks: ["frontend", "backend"]
networks:
frontend:
driver: overlay
backend:
driver: overlay
Como implementar readiness de verdade no Swarm?
Readiness efetivo em Swarm depende do seu balanceador/proxy. Configure um endpoint HTTP /ready na aplicação e faça o proxy remover instâncias que falham na checagem. O HEALTHCHECK interno continua útil, mas não controla o tráfego da mesh.
Combine readiness no proxy com start-first e pequenos delays. Assim a nova task aquece caches e conexões antes de receber tráfego. Veja exemplos práticos de HAProxy com health checks e roteamento gradual com canary usando Traefik.
| Mecanismo | Garante readiness? | Onde configurar | Observações |
|---|---|---|---|
| Docker HEALTHCHECK | Não, no Swarm não filtra tráfego | Dockerfile/stack | Bom para diagnóstico e gates internos; a mesh ignora o status |
| Health check no proxy (HAProxy/Traefik) | Sim, retira réplicas ruins do pool | Config do proxy | Checa HTTP /ready; pode incluir verificação de DB/cache via app |
| Rolling update start-first + delay | Parcial | deploy.update_config | Aquece antes do switch; não valida saúde de fato |
Orquestrando dependências com entrypoint "wait-for"
Como depends_on não resolve readiness em Swarm, use um entrypoint que espera banco e cache antes de iniciar o PHP-FPM. Não bloqueie indefinidamente: imponha timeout e falhe com exit 1 para que o orquestrador tente reiniciar.
O script abaixo usa nc para checar TCP. Adapte portas e variáveis conforme seu ambiente (ex.: Postgres 5432, Redis 6379).
#!/usr/bin/env sh
set -e
wait_for_host() {
host="$1"; port="$2"; name="$3"; timeout="${4:-30}"
echo "Waiting for $name at $host:$port..."
for i in $(seq 1 "$timeout"); do
if nc -z "$host" "$port" >/dev/null 2>&1; then
echo "$name is up"; return 0
fi
sleep 1
done
echo "Timeout waiting for $name"; return 1
}
[ -n "$DB_HOST" ] && wait_for_host "$DB_HOST" "${DB_PORT:-5432}" "database"
[ -n "$REDIS_HOST" ] && wait_for_host "$REDIS_HOST" "${REDIS_PORT:-6379}" "redis"
exec php-fpm -F
Estratégias por dependência: o que checar em cada uma
Cada dependência pede um tipo de verificação. Evite checks caros em produção. Prefira operações leves e idempotentes. Agrupe sinais em um endpoint /ready que retorne 200 somente quando tudo estiver estável.
Para PHP-FPM, exponha um endpoint interno leve. Para DB e cache, valide conectividade e operações mínimas.
- PHP-FPM: endpoint HTTP leve (ex.: /ready) que faz uma operação simples de aplicação.
- PostgreSQL/MySQL: SELECT 1 com timeout curto; evite migrações no healthcheck.
- Redis: PING e set/get de chave efêmera com TTL baixo.
- Filas (ex.: RabbitMQ): conexão + declare de fila passiva, sem consumir mensagens.
- Sistemas externos: HEAD/GET com timeouts e circuit breaker na aplicação.
Como confirmar que funcionou e monitorar no tempo?
Verifique a saúde dos containers e o estado do serviço após o deploy. Use docker service ps para acompanhar a rolagem de atualização. Inspecione o status do healthcheck e valide o endpoint /ready passando pelo proxy.
Monitore falhas de healthcheck e taxas de erro de readiness. Integre logs e alertas. Para métricas e erros de aplicação, veja métricas do PHP-FPM para Prometheus e um serviço de observabilidade PHP com Sentry.
- Confirme health status nas tasks.
- Valide /ready via proxy antes de liberar tráfego.
- Colete logs e métricas do PHP-FPM e do proxy.
# Ver tasks e atualizações
docker service ps --no-trunc my_app
# Inspecionar uma task específica
ID=$(docker service ps -q my_app | head -n1)
docker inspect $ID | jq '.[0].Status.ContainerStatus.ContainerID'
# Testar readiness via proxy (ajuste host)
curl -fsS http://app.example.com/ready || echo "not ready"
Erros comuns que quebram healthchecks em produção
Alguns padrões causam instabilidade e loops de restart desnecessários. Revise estes pontos antes de subir para produção e após mudanças de infraestrutura.
Evite checks caros, tempos apertados e dependências ocultas. Teste sob latência realista. Este guia foca o Swarm; para Compose, use o material linkado acima.
- HEALTHCHECK sem start_period e interval adequados.
- Script de check que faz I/O pesado ou locks de banco.
- Timeouts longos que atrasam a detecção de falhas reais.
- Confiar na mesh do Swarm para readiness do tráfego.
- depends_on esperado como gate de readiness no Swarm.
- Endpoint /ready que executa migrações por engano.
Perguntas frequentes
Docker Swarm usa o HEALTHCHECK para tirar réplicas do balanceamento?
Não. O Swarm mantém tasks RUNNING no pool, mesmo se o HEALTHCHECK falhar. Para readiness de tráfego, use health checks no proxy (ex.: checar /ready) ou um balanceador externo que remova instâncias ruins.
Devo validar banco e Redis no healthcheck do PHP?
Sim, quando são dependências críticas. Valide com operações leves, como SELECT 1 e PING. Use timeouts curtos e não faça migrações ou tarefas caras no healthcheck para evitar instabilidade.
O que usar para controlar ordem e aquecimento no update do Swarm?
Use update_config com order=start-first, delay e monitor. Isso aquece a nova task antes de desligar a antiga. Ainda assim, combine com readiness no proxy para só liberar tráfego quando o /ready responder 200.
Posso usar depends_on para garantir que o banco esteja pronto no Swarm?
Não. depends_on não é um gate de readiness no Swarm. Use um entrypoint que espera as portas do banco e cache com timeout e falha controlada, além de healthchecks e readiness no proxy.
Qual intervalo e timeout devo usar nos healthchecks?
Depende do tempo de boot e da latência esperada. Em geral, intervalos de 10–30s, timeout de 2–5s e start_period suficiente para warming funcionam bem. Ajuste com base em testes sob carga e monitore falsos positivos.
Quer tornar seus health checks no Swarm confiáveis?
Se precisa revisar o HEALTHCHECK em PHP, o readiness no proxy e o update do serviço, fale para desenharmos uma estratégia segura para sua stack.
Conversar sobre health checks no SwarmVeja também
- Guia prático: como configurar failover ativo-passivo entre duas VPS com Keepalived, HAProxy e lsyncd para uploads sincronizados
- Guia: checklist técnico para preparar VPS Debian com Docker Compose para aplicações PHP em produção
- Guia prático para dimensionamento de VPS e tuning de PHP‑FPM para lojas Magento/OpenMage com picos sazonais: do sizing ao teste de carga
- guia prático: reconstruir índices no PostgreSQL em produção usando CREATE INDEX CONCURRENTLY e índices parciais (passo a passo seguro)