Files
apps-registry/workloads/docs-portal/docs/arquitectura/vision-general.md
T
devops 056a7fb76a docs(docs-portal): Fase 2 - contenido narrativo real de arquitectura/decisiones/aprendizajes
Reemplaza los placeholders "TODO (fase 2+)" por narrativa completa,
grounded en el codigo/manifiestos/incidentes reales del lab (no
generico):

- ADR 0001 (por que k3d) y ADR 0002 (por que Argo CD): pasan de
  template vacio a Contexto/Opciones/Decision/Consecuencias reales,
  apoyados en known-issues.md (blackhole MTU) y en la config real de
  ecommerce-app.yaml.
- vision-general.md: el "por que" de cada frontera de confianza del
  diagrama.
- gitops-flujo.md: ejemplo real con hashes de commit (Fase 3b de
  ADR 0006, v1.0.171 -> hotfix -> v1.0.172), selfHeal explicado con el
  syncPolicy real del repo.
- red-y-exposicion.md: diagrama de terminacion TLS real, por que todo
  va "proxied", patron de diagnostico "interno sano, publico roto".
- glosario.md: 9 terminos nuevos, cada uno con ejemplo real y
  verificado del repo (Namespace, ResourceQuota, LimitRange,
  NetworkPolicy, Deployment, Service, Ingress, StatefulSet, Init
  container).
- notas-sueltas.md: MinIO/S3, limites reales del subscriber
  revalidate-storefront.ts, que se automatizaria desde cero.

Validado con `docker build --target build` (mkdocs build --strict,
mismo paso que el pipeline real) -- cero links rotos, cero warnings.
2026-08-26 23:51:18 -05:00

4.6 KiB

Visión general

Este lab corre sobre un NAS ZimaOS doméstico, sin IP pública ni presupuesto de nube — cada capa del diagrama de abajo existe por una razón concreta de ese contexto, no por moda arquitectónica. Esta página explica el "por qué" de cada frontera; el "cómo" vive en las páginas enlazadas al final de cada sección.

Flujo de una petición pública

flowchart LR
    User(["Usuario"]) -->|HTTPS| CF["Cloudflare<br/>(DNS proxied + túnel)"]
    CF -->|HTTP/2, red host| CFD["cloudflared<br/>(app ZimaOS)"]
    CFD --> NPM["Nginx Proxy Manager<br/>192.168.68.61:90"]
    NPM --> LB["k3d-lab-cluster-serverlb<br/>(k3d-proxy, 90→80)"]
    LB --> TR["Traefik<br/>(ingress del cluster)"]
    TR -->|Host: shop.cruzcloud.net| FE["frontend-svc<br/>(Next.js)"]
    TR -->|Host: commerce.cruzcloud.net| MED["medusa-svc<br/>(Medusa API)"]
    TR -->|Host: media.cruzcloud.net| MIN["minio-svc<br/>(imágenes de producto)"]
    TR -->|Host: gitea.cruzcloud.net| GIT["Gitea"]
    TR -->|Host: docs.cruzcloud.net| DOCS["docs-portal-svc<br/>(este sitio)"]

    subgraph GitOps["Control plane GitOps"]
        ARGO["Argo CD"] -->|sync| FE
        ARGO -->|sync| MED
        ARGO -->|sync| DOCS
        GIT -.->|watch repos| ARGO
    end

Componentes

Capa Qué es Dónde vive
Cloudflare Tunnel Expone *.cruzcloud.net a internet sin abrir puertos en el NAS Fuera del cluster, app nativa ZimaOS (cloudflared)
Nginx Proxy Manager Enruta por dominio hacia el cluster Fuera del cluster, contenedor nginxproxymanager
k3d Cluster Kubernetes local (multi-nodo, Docker) Host ZimaOS
Traefik Ingress controller del cluster Dentro de k3d
Argo CD Sincroniza el estado del cluster con Git (patrón App of Apps) Namespace argocd
Gitea Origen de verdad de los manifiestos y del código de las apps Contenedor propio, expuesto vía túnel

Por qué cada frontera está donde está

Cloudflare Tunnel, no port-forwarding. El NAS vive detrás de NAT residencial, sin IP pública fija. En vez de abrir puertos en el router (superficie de ataque directa contra el hogar), cloudflared abre una conexión saliente hacia Cloudflare y todo el tráfico público viaja hacia adentro por esa misma conexión — el origen nunca expone un puerto escuchando en internet. El transporte de esa conexión se fijó a HTTP/2 en vez del QUIC por defecto tras un incidente real de inestabilidad; ver ADR 0003.

Nginx Proxy Manager, fuera del cluster. No todo lo que sirve *.cruzcloud.net vive dentro de k3d — Gitea, por ejemplo, corre como contenedor Docker aparte. NPM es el único punto de enrutamiento por dominio que necesita conocer ambos mundos (cluster y no-cluster), así que vive fuera de Kubernetes a propósito, no por descuido.

k3d-lab-cluster-serverlb, la frontera de entrada al cluster. Es el load balancer que el propio k3d monta automáticamente para publicar puertos del host hacia los nodos internos — no es un componente que este lab configuró a mano, viene con la topología multi-nodo elegida en ADR 0001.

Traefik, enrutamiento por Host dentro del cluster. Una vez el tráfico entra al cluster por un único puerto (90/9443), Traefik es quien decide a qué Service mandarlo según el header Host de cada petición — así NPM solo necesita saber "todo *.cruzcloud.net va al puerto 90 del cluster", sin tener que aprender un forward_host nuevo cada vez que se agrega un servicio interno. Cuando esta capa falla en silencio (forward_host/forward_port mal apuntado en NPM), el síntoma es siempre el mismo: "internamente sano, públicamente roto" — ver Red y exposición.

Argo CD, el único escritor del cluster. Ningún pipeline de CI ni ninguna persona corre kubectl apply contra producción — Argo CD es la única pieza con permisos de escritura, y reconstruye automáticamente cualquier diferencia entre Git y el cluster real (selfHeal: true). El porqué completo de esa elección está en ADR 0002; el paso a paso de un commit real hasta quedar corriendo, en Flujo GitOps.

Gitea, autoalojado. Además de alojar el código, Gitea corre el CI (Gitea Actions) y el registry de imágenes en el mismo lugar — un solo componente autoalojado en vez de depender de la disponibilidad y los límites de un servicio externo gratuito para un lab que ya de por sí no tiene presupuesto de nube.

Ver también: Red y exposición · Flujo GitOps · Glosario