Files
apps-registry/workloads/docs-portal/docs/arquitectura/glosario.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

207 lines
8.3 KiB
Markdown

# Glosario
> Pensado para alguien que ve estos términos por primera vez. Definiciones
> cortas primero, detalle técnico después. Se irá expandiendo en fases
> siguientes — por ahora cubre los términos que ya aparecen en el resto
> del sitio.
## GitOps
**En una frase:** el estado deseado del sistema vive en Git, y un
proceso automático (no una persona con `kubectl`) se encarga de que el
cluster real coincida con lo que dice Git.
**Detalle:** en vez de ejecutar comandos contra el cluster a mano, se
edita un archivo YAML, se hace commit, y una herramienta (aquí, Argo CD)
detecta el cambio y lo aplica. Si alguien cambia algo directo en el
cluster sin pasar por Git, GitOps lo revierte (`selfHeal`) — Git es la
única fuente de verdad.
## Tunnel (Cloudflare Tunnel)
**En una frase:** una forma de exponer un servicio interno a internet
sin abrir puertos en el router/firewall.
**Detalle:** un proceso (`cloudflared`) corre dentro de la red local y
abre una conexión saliente hacia Cloudflare. El tráfico público llega a
Cloudflare y viaja hacia adentro por esa misma conexión — no hace falta
port-forwarding ni IP pública propia.
## Argo CD
**En una frase:** el "robot" que sincroniza el cluster Kubernetes con
lo que está escrito en Git.
**Detalle:** vigila uno o más repos Git, compara el estado declarado
(manifiestos YAML/Kustomize) contra el estado real del cluster, y
aplica la diferencia. Ver [flujo GitOps](gitops-flujo.md).
## Manifest (manifiesto)
**En una frase:** un archivo YAML que describe qué quieres que exista
en Kubernetes (un Deployment, un Service, un Ingress...).
**Detalle:** Kubernetes no se controla escribiendo código imperativo
("crea un pod"), sino declarando el resultado deseado ("quiero 2
réplicas de esta imagen corriendo"). El manifiesto es ese documento.
## App of Apps
**En una frase:** un patrón donde una Application de Argo CD no
despliega una app directamente, sino que despliega *otras*
Applications.
**Detalle:** en este lab, `application.yaml` (raíz) vigila la carpeta
`apps/` de `apps-registry`; cada archivo ahí dentro es una Application
hija que a su vez apunta a un workload real. Permite agregar una app
nueva con un solo archivo YAML nuevo.
## Kustomize
**En una frase:** una forma de componer manifiestos de Kubernetes sin
plantillas (a diferencia de Helm).
**Detalle:** un archivo `kustomization.yaml` lista qué recursos YAML
incluir y qué parches aplicarles, sin necesidad de un lenguaje de
templating separado.
## Namespace
**En una frase:** una partición lógica dentro del mismo cluster físico
— agrupa recursos relacionados y les pone un límite alrededor.
**Detalle:** este lab tiene un namespace por dominio de negocio
(`ecommerce`, `docs-portal`) más `argocd` para el propio Argo CD. Todo
lo que gobierna a un namespace (cuotas, políticas de red) vive en
`platform-infra`, separado de los manifiestos de la app — así una app
nueva no puede "olvidarse" de traer su propia gobernanza.
## ResourceQuota
**En una frase:** el techo total de recursos que un namespace entero
puede consumir, sumando todos sus pods.
**Detalle:** la cuota real de `ecommerce`
(`platform-infra/ecommerce-governance/resourcequota.yaml`):
```yaml
hard:
requests.cpu: "3"
requests.memory: 4Gi
limits.cpu: "8"
limits.memory: 8Gi
pods: "12"
persistentvolumeclaims: "6"
requests.storage: 80Gi
```
Si un Deployment nuevo pidiera más `requests.memory` del que queda
disponible bajo ese techo, Kubernetes rechaza el pod directamente — no
lo deja arrancar y luego fallar.
## LimitRange
**En una frase:** los valores por defecto (y los mínimos/máximos) que
aplican a un contenedor *individual* dentro de un namespace, para
cuando el manifiesto no los declara explícitos.
**Detalle:** complementa a `ResourceQuota` (que mira el namespace
entero) a nivel de un solo contenedor. La de `ecommerce`
(`limitrange.yaml`) pone `defaultRequest: 100m/128Mi`,
`default: 500m/512Mi` (límites si el contenedor no los declara), y un
rango permitido de `10m/16Mi` a `2 CPU/1Gi` por contenedor — evita
tanto el contenedor que no pide nada y termina compitiendo mal por
recursos, como el que pide de más y se come la cuota del namespace
entero él solo.
## NetworkPolicy
**En una frase:** un firewall a nivel de Kubernetes — qué tráfico de
red se permite entrar (o salir) de un pod.
**Detalle:** sin ninguna `NetworkPolicy`, todos los pods de un cluster
pueden hablarse entre sí libremente. La de `ecommerce`
(`networkpolicy.yaml`) usa `podSelector: {}` (aplica a todos los pods
del namespace) y permite ingress solo desde `namespaceSelector: {}`
(cualquier namespace del cluster, típicamente Traefik llegando desde
`kube-system` o el namespace de ingress) — bloquea tráfico externo al
cluster que intentara saltarse Traefik y pegarle directo a un Service
interno.
## Deployment
**En una frase:** el controlador para cargas de trabajo **sin
estado** — réplicas intercambiables entre sí, ninguna con identidad
propia.
**Detalle:** `frontend-deploy` es un Deployment de 2 réplicas: no
importa cuál de las dos atienda una petición, ambas sirven exactamente
lo mismo y ninguna guarda datos propios en disco. Si un pod muere,
Kubernetes crea otro cualquiera para reemplazarlo — no hay "el pod
original" que recuperar. Contrastar con **StatefulSet** abajo.
## Service
**En una frase:** un nombre de red estable que apunta a un grupo de
pods, aunque esos pods cambien.
**Detalle:** los pods son efímeros (mueren y se recrean con IP nueva
cada vez); un Service (ej. `frontend-svc`, `postgres-svc`) les da un
nombre DNS interno fijo (`frontend-svc.ecommerce.svc.cluster.local`,
o simplemente `frontend-svc` desde dentro del mismo namespace) que no
cambia aunque los pods de atrás sí. `postgres-svc` en este lab es
además un Service `clusterIP: None` ("headless") — necesario porque
`commerce-postgres` es un StatefulSet y cada pod necesita su propia
identidad de red estable, no una IP compartida balanceada entre
réplicas.
## Ingress
**En una frase:** la regla que dice "las peticiones a este dominio y
esta ruta van a este Service", para tráfico HTTP que entra al cluster.
**Detalle:** `ecommerce-ingress` enruta por *path*, no solo por
dominio: `shop.cruzcloud.net/api/catalog` va a `catalog-api-svc`, y
todo lo demás (`/`) va a `frontend-svc` — un solo objeto Ingress con
dos backends distintos según el prefijo de la URL. Es Traefik (el
Ingress Controller del cluster) quien lee estos objetos y hace el
enrutamiento real; el Ingress en sí es solo la declaración de la
regla, no el componente que la ejecuta.
## StatefulSet
**En una frase:** el controlador para cargas de trabajo **con
estado** — cada réplica tiene identidad propia y almacenamiento propio
que sobrevive a que el pod se reinicie.
**Detalle:** `commerce-postgres` es un StatefulSet, no un Deployment,
porque el frontend puede tener 2 réplicas idénticas sin datos propios,
pero Postgres no — sus datos tienen que vivir en un disco específico
que sobreviva un reinicio del pod y sepa exactamente cuál pod es
"el suyo". Cada pod de un StatefulSet obtiene su propio
`PersistentVolumeClaim` vía `volumeClaimTemplates` (acá,
`postgres-data`, 10Gi en `local-path`) y un nombre de red estable y
numerado (`commerce-postgres-0`), a diferencia de los nombres
aleatorios de un Deployment. Meilisearch, Redis y MinIO en este lab
siguen el mismo patrón por la misma razón — todos guardan datos en
disco que tienen que sobrevivir al pod.
## Init container
**En una frase:** un contenedor que corre **antes** que los
contenedores principales de un pod, y tiene que terminar bien (exit
0) para que el resto arranque.
**Detalle:** `medusa-deploy` usa dos, y a propósito están separados en
vez de ser uno solo: `wait-for-postgres` (`pg_isready` en loop, solo
espera a que Postgres acepte conexiones) y `migrations`
(`db:migrate`, corre las migraciones de verdad). Un incidente real
mostró por qué separarlos importa: cuando el chequeo de disponibilidad
reusaba la misma `DATABASE_URL` completa de la app (con
`?sslmode=disable` incluido), el parser de `pg_isready` no la entendía
y el pod quedaba atascado en `Init` — reportado como si fuera
`CrashLoopBackOff`, sin serlo. El fix fue que el chequeo de
disponibilidad use el mínimo de parámetros posible
(host/puerto/usuario/db), nunca la URI completa pensada para la app.
Ver el [playbook del crashloop de Medusa](../playbooks/incidente-crashloop-medusa.md).