Guia: checklist técnico para preparar VPS Debian com Docker Compose para aplicações PHP em produção

Por · Publicado em · 9 min de leitura

Patch panel com conectores e cabos de fibra óptica instalados em um rack
Visual profissional de infraestrutura de rede para ambientes de servidores e VPS. Foto: Brett Sayles / Pexels

guia: checklist técnico para preparar VPS Debian com Docker Compose para aplicações PHP em produção. Este passo a passo cobre sysctl, ulimits, journald, swap e cgroups. Você aplica os ajustes, valida com comandos simples e reduz riscos de OOM, perda de logs e gargalos de rede ou descritores de arquivo.

O que este checklist cobre e quando usar

O checklist foca na preparação do host Debian e do Docker para monólitos PHP ou stacks PHP em Compose. Ele prioriza estabilidade, previsibilidade e observabilidade antes de otimizações finas.

Use ao iniciar uma VPS, migrar hosts ou padronizar ambientes. Também serve para reduzir incidentes por OOM, logs sem retenção e limites do sistema.

Aplique primeiro em staging. Mudanças em kernel, cgroups e no serviço do Docker podem afetar todos os containers em execução.

  • Host Debian 11/12 com systemd e Docker instalado
  • Docker Compose v2 (CLI docker compose)
  • Stacks PHP com serviços separados (web, php‑fpm, banco, cache)

Pré-requisitos e versões recomendadas

A combinação de kernel, systemd e Docker define cgroups, logs e limites. Em Debian recente, cgroup v2 é padrão e o Docker usa driver de cgroup systemd.

Confira estes pontos antes de seguir. Garanta espaço em /var para o journald e privilégios de root.

  • Kernel e systemd atualizados com cgroup v2
  • Docker Engine 20.10+ e Compose v2
  • Acesso root ao host e espaço livre em /var
# Verificar cgroup v2
stat -fc %T /sys/fs/cgroup  # esperado: cgroup2fs

# Verificar driver de cgroup do Docker
docker info | grep -i 'Cgroup Driver'  # esperado: systemd

# Versões
docker --version
docker compose version

Quais sysctl ajustar no Debian para Docker/PHP?

Alguns parâmetros do kernel evitam saturação de filas, esgotamento de portas efêmeras e limites de conexões. Configure via /etc/sysctl.d para persistência e carregue sem reboot.

Se notar intermitência na bridge do Docker, investigue rede e filas. Veja causas e correções em conexão cai na Docker bridge.

Os valores a seguir são ponto de partida. Ajuste conforme memória, tráfego e padrão de conexões da sua aplicação.

  • Habilitar roteamento para redes Docker
  • Ampliar backlog e SYN backlog
  • Expandir portas efêmeras para muitas conexões de saída
  • Dimensionar conntrack à carga e memória
# /etc/sysctl.d/99-docker-php.conf
net.ipv4.ip_forward = 1
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.ip_local_port_range = 1024 65535

# Conntrack: comece moderado e ajuste com métricas
net.netfilter.nf_conntrack_max = 131072

# Aplicar agora
sysctl --system

# Checar
sysctl -n net.ipv4.ip_forward net.core.somaxconn net.ipv4.tcp_max_syn_backlog net.ipv4.ip_local_port_range net.netfilter.nf_conntrack_max

Como configurar ulimits no host e nos containers?

Limites de arquivos e processos evitam erros como "Too many open files". Em serviços gerenciados pelo systemd, use overrides. Em containers, defina ulimits no Compose.

Garanta que o limite do host seja maior que o do container. Caso contrário, o Docker não aplicará o valor solicitado. Reiniciar o serviço docker interrompe containers em execução. Para diagnóstico de FDs no PHP‑FPM, veja como resolver erro de open files.

  • Aumente fs.file-max e LimitNOFILE no docker.service
  • Defina ulimits por serviço no Compose
  • Alinhe limites com o PHP‑FPM (pm.max_children, sockets, conexões)
# 1) Limite global de FDs do kernel
sysctl -w fs.file-max=500000
# Para persistir: adicione fs.file-max = 500000 em /etc/sysctl.d/99-docker-php.conf

# 2) Override do systemd para o Docker
mkdir -p /etc/systemd/system/docker.service.d
cat >/etc/systemd/system/docker.service.d/override.conf <<'EOF'
[Service]
LimitNOFILE=1048576
LimitNPROC=131072
EOF
systemctl daemon-reload && systemctl restart docker

# 3) docker-compose.yml (exemplo por serviço)
# services:
#   php:
#     image: your-php-image:latest
#     ulimits:
#       nofile: 65536
#       nproc: 4096
#       core: 0

# Diagnóstico de FDs em runtime
# docker compose exec php sh -lc 'ulimit -n; ulimit -u'

Journald: retenção, tags e impacto em disco

Usar journald como log-driver centraliza logs e facilita retenção com compressão. Defina cotas e retenção para evitar saturar o disco da VPS.

Padronize a tag dos containers para filtros consistentes. Para detalhes de rotação e compactação em VPS com pouco disco, veja o tutorial de retenção de logs com journald + logrotate + rsyslog.

  • Defina Storage=persistent para manter logs após reboot
  • Limite SystemMaxUse e MaxRetentionSec
  • Use log-driver=journald com tag consistente
# /etc/systemd/journald.conf (trecho)
[Journal]
Storage=persistent
SystemMaxUse=1G
SystemMaxFileSize=128M
MaxRetentionSec=14day
RateLimitIntervalSec=30s
RateLimitBurst=10000

systemctl restart systemd-journald
journalctl --disk-usage

# /etc/docker/daemon.json (trecho)
{
  "log-driver": "journald",
  "log-opts": {"tag": "{{.Name}}"},
  "exec-opts": ["native.cgroupdriver=systemd"]
}

systemctl restart docker && sleep 2 && docker info | grep -i log

Swap e OOM: qual a estratégia segura para produção?

Uma pequena área de swap reduz OOM kills em picos curtos de memória. Em workloads PHP, mantenha swappiness baixo e monitore page faults.

Crie swapfile se faltar swap e valide. Swap em disco lento pode aumentar a latência. Para entender picos noturnos de I/O e swap, veja como resolver picos de I/O e swap em VPS.

  • Crie swapfile proporcional à RAM e ao tráfego
  • Ajuste vm.swappiness para 10–20 como ponto de partida
  • Alinhe memswap ao mem_limit em containers críticos
# Criar swapfile (ex.: 2G)
fallocate -l 2G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=2048
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# Reduzir swappiness
sysctl -w vm.swappiness=10
# Persistir em /etc/sysctl.d/99-docker-php.conf
# vm.swappiness = 10

# Conferir swap
swapon --show
cat /proc/sys/vm/swappiness

# Ajuste por container no compose (evita uso de swap pelo container)
# services:
#   php:
#     mem_limit: 1g
#     memswap_limit: 1g  # total = memória + swap; igual à mem_limit ≈ sem swap no container

Cgroups v2 e Docker Compose: como limitar recursos?

Cgroups v2 expõe limites de CPU, memória, PIDs e I/O. No Compose local, a chave deploy.* é ignorada; use campos específicos de limites.

Valide o driver de cgroup systemd e confira os limites via docker inspect e arquivos em /sys/fs/cgroup. Para um passo a passo completo, veja cgroup v2 + systemd ResourceControl no Docker.

  • Use mem_limit, memswap_limit, cpus e pids_limit no Compose
  • Ajuste blkio_config para não sufocar o disco
  • Evite deploy.resources no Compose sem Swarm
# docker-compose.yml (exemplo simplificado)
version: "3.9"
services:
  php:
    image: your-php-image:latest
    cpus: "1.5"
    mem_limit: 1g
    memswap_limit: 1g
    pids_limit: 4096
    ulimits:
      nofile: 65536
      nproc: 4096
    blkio_config:
      weight: 600

# Verificações
# docker compose up -d
# docker inspect --format '{{json .HostConfig.NanoCpus}}' <container>
# docker compose exec php sh -lc 'cat /sys/fs/cgroup/memory.max 2>/dev/null || cat /sys/fs/cgroup/memory.limit_in_bytes'

Verificações rápidas e automação do checklist

Depois dos ajustes, execute verificações objetivas. Elas confirmam sysctl, limites, logs e cgroups de forma repetível.

Automatize com Ansible ou scripts. Se um valor divergir, corrija nos arquivos persistentes: sysctl.d, daemon.json e overrides do systemd.

Item Comando Saída esperada
Cgroup v2 stat -fc %T /sys/fs/cgroup cgroup2fs
Driver de cgroup do Docker docker info | grep -i 'Cgroup Driver' systemd
Portas efêmeras sysctl -n net.ipv4.ip_local_port_range 1024 65535
Backlogs (somaxconn/SYN) sysctl -n net.core.somaxconn net.ipv4.tcp_max_syn_backlog >= 1024 / >= 1024
Conntrack sysctl -n net.netfilter.nf_conntrack_max > 65536 (ajustar à carga)
Swap e swappiness swapon --show; cat /proc/sys/vm/swappiness swap ativo; 10–20
Journald retenção journalctl --disk-usage <= cota definida (ex.: ~1G)
Limite de FDs (host) cat /proc/sys/fs/file-max >= 500000 (ajuste conforme)
Limite de FDs (container) docker compose exec php sh -lc 'ulimit -n' >= 65536
# Validação resumida
set -euo pipefail
printf "Cgroup: "; stat -fc %T /sys/fs/cgroup
printf "Cgroup Driver: "; docker info 2>/dev/null | awk -F: '/Cgroup Driver/{print $2}'
printf "Ports: "; sysctl -n net.ipv4.ip_local_port_range
printf "Backlogs: "; sysctl -n net.core.somaxconn net.ipv4.tcp_max_syn_backlog
printf "Conntrack: "; sysctl -n net.netfilter.nf_conntrack_max
printf "Swap: "; swapon --show | tail -n +2 | wc -l; cat /proc/sys/vm/swappiness
journalctl --disk-usage || true
printf "FDs host: "; cat /proc/sys/fs/file-max
# FDs container (requer serviço 'php')
docker compose exec -T php sh -lc 'echo -n "FDs container: "; ulimit -n' || true

Perguntas frequentes

Qual swappiness usar em produção para PHP em Docker?

Use swappiness baixo, entre 10 e 20, para reduzir trocas agressivas e latência. Mantenha uma pequena área de swap para amortecer picos curtos de memória. Monitore OOM kills e page faults e ajuste ao perfil de tráfego e à RAM do host.

É melhor usar journald ou json-file para logs de containers?

Para VPS, journald facilita retenção e compressão com o mesmo mecanismo do host. Ele evita crescimento descontrolado do json-file. Se usar json-file, aplique max-size e max-file. Com journald, defina SystemMaxUse e retenção e monitore com journalctl --disk-usage.

O deploy.resources do Compose funciona fora do Swarm?

Não. O deploy.resources é ignorado no Compose tradicional. Para impor limites, use cpus, mem_limit, memswap_limit, pids_limit, blkio_config e ulimits. Valide com docker inspect e lendo arquivos em /sys/fs/cgroup dentro do container.

Qual valor de nofile devo definir para PHP‑FPM?

Comece com 65536 por container PHP e ajuste com métricas. Considere conexões simultâneas, sockets, arquivos e logs. No host, mantenha fs.file-max e LimitNOFILE bem acima dos valores dos containers. Meça o pico real de FDs em horários críticos.

Como evitar que logs ocupem todo o disco da VPS?

Limite o journald com SystemMaxUse e MaxRetentionSec e padronize tags. Se usar json-file, configure max-size e max-file. Monitore com journalctl --disk-usage e crie alertas antes de 80% do disco. Limpezas periódicas de imagens e volumes também ajudam.

Preciso desativar completamente a swap em produção?

Geralmente, não. Uma pequena swap ajuda a evitar OOM kills em picos breves. Desativar totalmente aumenta o risco de reinícios de processos. Prefira swappiness baixo e limites claros por container (mem_limit e memswap_limit) para controlar consumo sem sufocar o host.

Quer revisar seu checklist antes do deploy?

Envie seu docker-compose.yml e as saídas das verificações. Podemos revisar limites, sysctl e journald para um início mais tranquilo.

Conversar sobre o checklist

Veja também