# 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).