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 · Publicado em · 9 min de leitura

Mãos digitando em notebook com editor de código aberto na tela
Editor de código no notebook, foco em desenvolvimento e produtividade. Foto: Alicia Christin Gerald / Pexels

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 Swarm

Veja também