Por qué los contenedores Docker pierden conexión en la bridge y cómo resolver la intermitencia en producción
Por Kevin Marcondes · Publicado el · 9 min de lectura
Si los contenedores Docker pierden conexión en la bridge de forma intermitente, un diagnóstico acertado evita horas de prueba y error. La causa suele estar en MTU/PMTU, conntrack/NAT, rp_filter/ARP o en el DNS interno. A continuación explico cómo identificar cada raíz y aplicar correcciones seguras en producción.
Síntomas y cuándo aparece la intermitencia
La intermitencia en la bridge se manifiesta como timeouts, resets (RST) y conexiones que funcionan y de repente se rompen. A veces solo fallan cargas grandes; pings cortos pasan.
El patrón habitual: servicios bajo Docker quedan accesibles por el puerto publicado, pero clientes internos o externos ven fallos ocasionales, sobre todo en picos, cuando muchos contenedores arrancan/paran o tras cambios de red en el host.
- TCP conecta, recibe algunos KB y se queda colgado hasta timeout.
- Subidas/descargas grandes fallan; peticiones pequeñas funcionan.
- Mensajes en el kernel sobre conntrack/ARP o paquetes ‘martian’.
- DNS resuelve lento o de forma intermitente dentro de los contenedores.
Causas técnicas más comunes en la bridge de Docker
Algunas raíces aparecen repetidamente en incidentes reales de producción. Entender el mecanismo permite aplicar la corrección adecuada.
La buena noticia: la mayoría tienen diagnóstico objetivo con pocas comprobaciones en el host y en los contenedores.
- MTU/PMTU: la MTU del veth/docker0 no coincide con la red física/túneles, generando un blackhole para paquetes grandes.
- Conntrack/NAT: la tabla nf_conntrack se llena, las portas efímeras se agotan y las sesiones caen al azar.
- rp_filter/rutas: el enrutamiento asimétrico, VRRP/VPN o múltiples NICs hacen que el kernel descarte respuestas legítimas.
- ARP/cache de vecinos: entradas obsoletas o GC agresivo tras churn de contenedores.
- DNS 127.0.0.11: el DNS integrado de Docker sufre bajo alto QPS o con timeouts pobres.
- Reglas DOCKER-USER/iptables: políticas 'drop' afectan al tráfico de docker0 sin excepciones adecuadas.
Diagnóstico rápido en el host y en los contenedores
Haz un cribado objetivo antes de cambiar configuraciones. Busca señales de MTU, conntrack y caídas por firewall/enrutamiento.
Ejecuta las comprobaciones desde el host y desde un contenedor afectado. Guarda los horarios y compara con picos de tráfico.
# 1) Sinais no kernel (conntrack, ARP/neighbor, martian)
dmesg -T | egrep -i 'conntrack|nf_conntrack|neighbor|arp|martian|FRAG'
# 2) Estado de conntrack e portas efêmeras
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
ss -s
cat /proc/sys/net/ipv4/ip_local_port_range
# 3) PMTU/MTU: teste DF e caminho
GW=$(ip route | awk '/default/ {print $3; exit}')
ping -c 3 -M do -s 1472 "$GW" || echo "Possível MTU < 1500 no caminho"
tracepath -n "$GW" | tail -n +1
# 4) ARP/neigh suspeito (incomplete/failed)
ip -s neigh | egrep -i 'FAILED|INCOMPLETE' -n || true
# 5) Regras do Docker e DOCKER-USER
iptables -S DOCKER-USER 2>/dev/null || true
iptables -t nat -S | sed -n '1,120p' 2>/dev/null || true
# 6) De dentro de um container afetado: DNS e MTU
getent hosts example.com || nslookup example.com || dig +short example.com || true
ip route show
echo $(cat /sys/class/net/eth0/mtu) MTU-no-container
MTU y PMTU: detectar y corregir sin tumbar todo
Fallas solo con payloads grandes casi siempre indican MTU/PMTU. En nubes con túneles (VXLAN/GRE), la MTU efectiva suele ser 1450/1460. Si docker0/eth0 del contenedor están en 1500 aparece un blackhole.
Confirma con ping DF. Si hace falta una MTU menor, ajusta la MTU del daemon de Docker para alinear con la red. Requiere reiniciar Docker y recrear la bridge: planifica ventana.
- Valida con ping -M do hacia la gateway/servicio.
- Ajusta la MTU en el daemon de Docker para propagarla a los veth.
- Prueba de nuevo y monitoriza errores de fragmentación.
# Teste PMTU (ajuste o destino para um serviço fora do host)
ping -c 3 -M do -s 1472 $DEST || echo "Tente 1432/1400 para descobrir a MTU segura"
# Ajuste de MTU no Docker (crie/edite /etc/docker/daemon.json)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
"mtu": 1450
}
EOF
# Reinicie com cuidado (interrompe containers)
sudo systemctl restart docker
# Verifique
aioctl=$(ip -o link show docker0 | awk '{print $2,$9,$10,$11}')
echo "docker0 ->" $ioctl
ip -o link show | grep veth | head -n 3
Conntrack, NAT y puertos efímeros: límites y tuning
La tabla nf_conntrack llena derriba conexiones nuevas y puede matar las existentes. El tráfico con mucho NAT también sufre si el rango de puertos efímeros es corto.
Ajusta límites de conntrack con cautela, amplía la franja de puertos y, si gestionas el firewall manualmente, usa MASQUERADE con --random-fully para reducir colisiones de 5‑tuple.
- Monitoriza count vs max; deja margen saludable.
- Amplía ip_local_port_range en hosts con salida intensa.
- Evita reglas que obliguen a inspección cara en cada paquete.
# Medir e ajustar conntrack
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
# Exemplo: elevar (persistir em /etc/sysctl.d)
echo 'net.netfilter.nf_conntrack_max = 524288' | sudo tee /etc/sysctl.d/90-conntrack.conf
sudo sysctl --system
# Portas efêmeras mais amplas
sudo sysctl -w net.ipv4.ip_local_port_range="10240 65535"
echo 'net.ipv4.ip_local_port_range = 10240 65535' | sudo tee /etc/sysctl.d/90-ports.conf
sudo sysctl --system
# Se você administra NAT manualmente (fora das regras do Docker):
# iptables -t nat -C POSTROUTING -o eth0 -j MASQUERADE --random-fully || \
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE --random-fully
ARP, caché de vecinos y rp_filter: rutas que desaparecen
El enrutamiento asimétrico (VPN, VRRP, múltiples NICs) con rp_filter estricto hace que el kernel descarte respuestas legítimas. El caché ARP/neighbor pequeño, bajo churn, induce fallos intermitentes.
Aplica rp_filter en modo 'loose' donde haya asimetría y aumenta los umbrales del GC de vecinos. Cambia con precaución y documenta las modificaciones.
- Busca 'martian source' en los logs.
- Confirma la ruta de retorno con ip route get.
- Aumenta gc_thresh en hosts con muchos peers/contenedores.
# rp_filter atual
sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.default.rp_filter
# Tornar ‘loose’ (2) se há assimetria/VRRP/VPN
sudo sysctl -w net.ipv4.conf.all.rp_filter=2
sudo sysctl -w net.ipv4.conf.default.rp_filter=2
echo -e 'net.ipv4.conf.all.rp_filter=2\nnet.ipv4.conf.default.rp_filter=2' | \
sudo tee /etc/sysctl.d/90-rpfilter.conf
# Neighbour cache mais folgado
sysctl net.ipv4.neigh.default.gc_thresh1 net.ipv4.neigh.default.gc_thresh2 net.ipv4.neigh.default.gc_thresh3
sudo bash -c 'cat > /etc/sysctl.d/90-neigh.conf <<EOF
net.ipv4.neigh.default.gc_thresh1 = 4096
net.ipv4.neigh.default.gc_thresh2 = 8192
net.ipv4.neigh.default.gc_thresh3 = 16384
EOF'
sudo sysctl --system
# Limpar entradas problemáticas (impacta momentaneamente a resolução ARP)
sudo ip neigh flush dev docker0 || true
DNS 127.0.0.11 y firewall: cuando no es la red
La resolución integrada (127.0.0.11) puede convertirse en cuello de botella bajo alto QPS o con parámetros de timeout desfavorables. En entornos restrictivos, DOCKER-USER con DROP por defecto bloquea tráfico de la bridge.
Prueba con un DNS externo/caché y ajusta dns_opt en Compose. Revisa DOCKER-USER asegurando excepciones claras antes de un DROP amplio.
- Usa un resolvedor local (p. ej. 10.0.0.53) para cachear respuestas.
- Reduce timeout/attempts para fallar rápido y probar otro DNS.
- Permite RELATED,ESTABLISHED y tráfico desde docker0 en el firewall.
# docker-compose.yml (trecho)
services:
app:
image: example/app
dns:
- 10.0.0.53
- 1.1.1.1
dns_opt:
- timeout:1
- attempts:3
# ... restante do serviço
Observabilidad, pruebas y próximos pasos
Después de aplicar correcciones, valida bajo carga y monitoriza. Métricas de conntrack, caídas TCP y latencia de DNS ayudan a prevenir regresiones.
Implementa health checks para sacar instancias del tráfico al primer signo de fallo, y un proxy reverso bien configurado para failover/rotación de certificados.
- Recopila métricas con Prometheus/Grafana y define alertas útiles.
- Centraliza logs (kernel, iptables, apps) para correlación.
- Automatiza readiness checks y circuit breakers en la app.
- Prueba PMTU en pipelines de deploy y tras cambios de red.
- Evita la bridge 'default'; prefiere redes user-defined aisladas.
Preguntas frecuentes
¿Cómo saber si el problema es MTU/PMTU u otra cosa?
Si pings pequeños funcionan y paquetes grandes con DF fallan, es un indicio fuerte de MTU/PMTU. tracepath ayuda a revelar el salto que reduce MTU. Caídas aleatorias en picos con mensajes de nf_conntrack apuntan a conntrack/NAT. Logs de ‘martian’ sugieren rp_filter/rutas.
¿Aumentar nf_conntrack_max lo soluciona definitivamente?
Alivia picos, pero no es una solución completa. Si el patrón de tráfico crea muchas conexiones cortas, ajusta también timeouts, amplia puertos efímeros y revisa el diseño (pooling/reuso de conexiones). Monitoriza el count para evitar crecer sin necesidad.
¿Es seguro desactivar rp_filter?
Evita desactivarlo por completo. Usa el modo 'loose' (2) cuando hay enrutamiento asimétrico, VRRP o VPN. El modo estricto en hosts multihomed provoca falsos positivos y descartes. Documenta el cambio y monitoriza logs de 'martian' tras el ajuste.
¿Debo usar el DNS integrado de Docker o un resolvedor externo?
Para cargas ligeras, el DNS integrado funciona. En alto QPS o latencias sensibles, usa un resolvedor local en caché (p. ej. unbound/dnsmasq) y apunta los servicios vía dns en Compose. Ajusta dns_opt para timeouts cortos y múltiples servidores.
¿Una user-defined bridge mejora la estabilidad?
Sí. Las redes user-defined aíslan dominios de broadcast, tienen reglas más predecibles y DNS por servicio. Reducen colisiones y facilitan políticas de firewall. Evita concentrar todos los servicios en la bridge 'default'; crea redes por dominio lógico.
¿Quieres estabilizar la red de tus contenedores?
Si sufres intermitencia en la bridge de Docker y necesitas un plan de diagnóstico y corrección con bajo riesgo, hablemos sobre tu escenario y los próximos pasos prácticos.
Hablar sobre diagnóstico DockerVer también
- 502 Bad Gateway intermitente en Docker Compose con Nginx y PHP‑FPM: cómo diagnosticar y corregir timeouts y exceso de conexiones
- Cómo diagnosticar y capturar paquetes por intermitencias de red entre contenedores Docker en Debian
- Cómo detectar y corregir inconsistencias de SKUs duplicados entre WooCommerce y ERP sin perder pedidos
- Cómo resolver el error 'Too many open files' en Linux en servidores PHP‑FPM durante picos de carga