Tres incidentes resueltos en la sesión del 2026-08-12/13: 504 intermitente por QUIC inestable en cloudflared, precios null por falta de region_id en el Store API de Medusa v2 (se descarta la hipótesis inicial de regiones COP duplicadas con evidencia directa en Postgres), e imágenes en blanco por un proxy host mal configurado en Nginx Proxy Manager para media.cruzcloud.net. Se agregan también dos notas de referencia en known-issues.md: la topología Cloudflare Tunnel -> NPM -> k3d, y el requisito de region_id explícito en StoreGetProductsParams.
4.9 KiB
Known issues
Blackhole de red cross-node en el cluster k3d (MTU/PMTUD, flannel VXLAN)
Estado: workaround aplicado, fix definitivo pendiente.
Síntoma: cualquier pod que necesite hablar con commerce-postgres-0
(StatefulSet, sin réplicas, fijo a un nodo) falla de forma consistente y
reproducible al 100% cuando queda agendado en un nodo distinto al de
Postgres. El handshake TCP (SYN/ACK, nc, ping) funciona perfecto entre
nodos, pero el primer paquete de datos real de la sesión (protocolo Postgres,
pg_isready incluido) nunca llega — se cuelga hasta hacer timeout.
Diagnóstico:
- Confirmado aislando el nodo con
nodeNameen pods de prueba: 100% de fallos (186/186 intentos) agendando cross-node (agent-0→ Postgres enserver-0); 100% de éxito agendando en el mismo nodo. - MTU dentro de los pods (interfaz
flannel.1/VXLAN) es 1450 en ambos nodos — consistente, no es un mismatch obvio a nivel flannel. pingsin-M do(permite fragmentación) no muestra pérdida de paquetes hasta payloads de 2000 bytes entre los contenedores Docker de los nodos.- Encaja con un blackhole de PMTU Discovery: el bridge Docker externo que conecta los contenedores de los nodos k3d probablemente tiene un MTU real menor a 1500, y los paquetes TCP con el bit DF puesto (como los de la sesión de Postgres) se pierden en vez de fragmentarse o generar el ICMP "fragmentation needed" que permitiría el ajuste automático.
Workaround temporal (aplicado en workloads/ecommerce/commerce/medusa.yaml):
podAffinity con requiredDuringSchedulingIgnoredDuringExecution sobre
medusa-deploy, forzando que sus pods se agenden siempre en el mismo nodo
que commerce-postgres-0 (matchLabels: app: commerce-postgres,
topologyKey: kubernetes.io/hostname). Esto evita el tráfico cross-node
entre Medusa y Postgres, pero no resuelve el problema de fondo — cualquier
otro workload que necesite cruzar nodos para hablar con Postgres (u otro
servicio) puede pisar el mismo blackhole.
TODO — fix definitivo pendiente:
Ajustar el MTU del cluster k3d a un valor seguro (1400) de forma
consistente en la red Docker del cluster y en flannel, para eliminar el
blackhole de raíz y poder quitar el podAffinity (o dejarlo como
optimización, no como requisito de disponibilidad).
Topología de red: Cloudflare Tunnel → Nginx Proxy Manager → k3d
Estado: referencia de arquitectura — no es un issue abierto, pero el
patrón de falla que describe ya se repitió una vez (ver
docs/playbooks/incidente-medusa-imagenes-proxy-npm-2026-08.md) y puede
volver a aparecer con otro subdominio.
Ruta real de una petición pública a *.cruzcloud.net:
Internet → Cloudflare (DNS proxied, túnel) → contenedor `cloudflared`
(app nativa de ZimaOS, red Host) → Nginx Proxy Manager
(contenedor `nginxproxymanager`, config en
/DATA/AppData/nginxproxymanager/data/) → 192.168.68.61:90
→ `k3d-lab-cluster-serverlb` (k3d-proxy, publica 90→80 y 9443→443)
→ Traefik (ingress del cluster) → Service correspondiente,
enrutado por el header `Host`.
Los proxy hosts de NPM viven en
/DATA/AppData/nginxproxymanager/data/database.sqlite (tabla
proxy_host) y NPM regenera solo el .conf correspondiente en
data/nginx/proxy_host/<id>.conf cuando cambia la fila en la base —
no hace falta editar el .conf a mano, y si se edita a mano puede
sobreescribirse en cualquier cambio posterior desde la UI/DB.
Patrón de diagnóstico: si un subdominio *.cruzcloud.net responde
500 Internal Server Error con header Server: openresty cuando se
accede públicamente, pero el mismo path funciona bien contra el
ingress interno del cluster (curl -H "Host: <subdominio>" http://<IP-del-nodo>/...), el problema no está en el cluster ni en
la app — está en el proxy host de NPM para ese subdominio. Revisar
forward_host/forward_port en la tabla proxy_host y compararlos
contra un host que sí funcione (ej. shop.cruzcloud.net,
commerce.cruzcloud.net, ambos con forward_host='192.168.68.61',
forward_port=90).
Nota de arquitectura: Medusa v2 Store API requiere region_id explícito
Estado: no es un issue, es un requisito de la API que causó un
incidente real por no ser conocido — ver
docs/playbooks/incidente-medusa-precios-region-id-2026-08.md.
El endpoint /store/products de Medusa v2 (validado por
StoreGetProductsParams, .strict()) no acepta currency_code ni
country_code como parámetros para resolver el contexto de precio
(calculated_price). El único parámetro válido para ese fin es
region_id, apuntando a una región existente y configurada vía Admin
API. Cualquier integración nueva contra el Store API de Medusa v2 que
necesite precios calculados debe pasar region_id explícito — no
asumir que currency_code o country_code son suficientes, aunque lo
sean en Medusa v1 o en otras APIs de e-commerce.