Cinco niveles de madurez de la plataforma debajo del LLM: del servidor con Linux al cluster listo para vLLM
TL;DR
El post de las siete capas del stack de inferencia LLM daba por supuestas muchas piezas: un cluster Kubernetes operativo, GitOps reconciliando, identidades resueltas, GPUs visibles para el scheduler, observabilidad capaz de transportar gen_ai.*. Antes de que vLLM tenga sentido, hay que llegar a ese punto de partida, y se llega por niveles. Este post define cinco niveles de madurez de la plataforma que vive debajo del LLM, desde un servidor bare metal con Linux instalado (nivel 0) hasta un cluster listo para correr la capa de inferencia (nivel 4) y el handoff al post anterior (nivel 5). Cada nivel desbloquea una capacidad concreta —ejecutar contenedores con reproducibilidad, reconstruir el cluster desde git, autenticar humanos vía OIDC, programar GPUs con MIG y métricas DCGM, demostrar compliance sin intervención manual— y cada uno tiene un test de validación que decide si estás de verdad ahí o solo te lo cuentas. Para cada nivel: qué piezas OSS lo cubren en 2026 (Cilium, RKE2, Flux, cert-manager, Defguard, NVIDIA GPU Operator, KEDA, Trivy, Kyverno…), el orden de despliegue dentro del nivel, las decisiones que cuesta caro saltarse, y los antipatrones que te bajan de nivel cuando creías estar arriba. La tesis: subir de nivel cuesta poco esfuerzo si lo haces a tiempo, y mucho refactor si pretendes saltártelo. La inferencia LLM exige al menos nivel 4; quien intenta servir LLMs desde un nivel 1 o 2 acaba pagando con incidentes nocturnos lo que se ahorró en plataforma.
Estás aquí: los cinco niveles de un vistazo
Antes del detalle, la escalera. Cada peldaño añade una capacidad ausente en el anterior. El test del nivel es la pregunta cuya respuesta honesta dice si ya estás en él.
Los niveles no son intercambiables. Un cluster en nivel 2 no puede correr LLMs en producción con garantías: técnicamente carga el pod de vLLM, pero al primer incidente nocturno se descubre que no hay TLS, ni identidades, ni alerting, ni métricas GPU, ni forma de saber quién cambió qué. Subir un nivel después de tener LLMs ya en producción cuesta órdenes de magnitud más que subirlo cuando el cluster aún está vacío.
La analogía: del puesto callejero al restaurante con estrella
Imagina la escala de un negocio de hostelería. Nivel 0 es el puesto callejero: una plancha, una bombona, un cocinero que improvisa. Puede vender comida — funciona — pero cualquier cosa que se desvíe del día normal (una inspección sanitaria, un cliente alérgico, un pedido de 200 raciones) le tira el negocio. Nivel 1 es el bar de tapas: cocina dimensionada, carta corta repetible, varios turnos. El cocinero ya no improvisa cada día; trabaja sobre un menú escrito, aunque las recetas viven en la cabeza del jefe. Nivel 2 es el restaurante con menú del día: hay procedimientos escritos, proveedores fijos, control de stock, libro de incidencias. Si el cocinero principal se cae enfermo, el segundo puede sacar el servicio sin estragos. Nivel 3 es el restaurante con carta y servicio formal: trazabilidad de cada ingrediente, alérgenos en la carta, certificación sanitaria, contrato con los proveedores, formación obligatoria del personal. Nivel 4 es la cocina especializada en un producto complejo (sushi, alta cocina, panadería artesanal): herramientas específicas que el restaurante normal no necesita (horno de leña, cuchillos especiales, cámara de fermentación), procesos calibrados, métricas de calidad. Nivel 5 es el restaurante con estrella Michelin: el sistema entero funciona, el plato es el resultado de la organización, no del talento de una persona.
La analogía aguanta hasta el final, incluido el detalle más interesante: se puede operar a cualquier nivel, pero las promesas que se pueden cumplir son distintas. El puesto callejero no puede prometer una experiencia consistente a 80 comensales con reserva. El cluster en nivel 1 no puede prometer servicio LLM productivo multi-tenant con SLA. En ambos casos el problema no es de capacidad técnica del último componente (la plancha cocina; el pod arranca); es de capacidad organizativa del sistema entero.
Vamos nivel por nivel.
Nivel 0 — Caótico: el servidor con Linux y nada más
La capacidad que da. Ejecutar contenedores con docker/podman, ejecutar binarios, conectar el servidor a la red. El operador puede entrar por SSH, hacer cosas, y ver resultados.
El test del nivel. “Si reinstalo el servidor desde cero, ¿puedo dejarlo idéntico a como estaba en una tarde, usando sólo notas guardadas?”. Si la respuesta es no (porque los pasos están en la cabeza del que lo montó, en .bash_history, en un wiki desactualizado), estás en nivel 0.
Piezas mínimas que dejar resueltas antes de subir a nivel 1.
| Pieza | Decisión sugerida en 2026 | Por qué importa al subir |
|---|---|---|
| Distribución Linux | Debian estable u Ubuntu LTS | Soporte largo, predecible, kernel reciente disponible |
| Kernel | LTS reciente (≥ 6.6) con BPF y schedulers modernos | Cilium/eBPF, drivers NVIDIA recientes lo exigen |
| Drivers NVIDIA | Versión que casa con la CUDA del motor LLM que vas a servir | Mismatch driver/CUDA bloquea vLLM antes de empezar |
| Container runtime | containerd | Estándar CNCF, integrado con RKE2/kubeadm |
| Filesystem raíz | XFS o ext4 + LVM thin pools | Snapshots, ampliación en caliente |
| Sincronización horaria | chrony con servidores propios | TLS, logs correlados, certificados cortos lo exigen |
| Red de gestión | VLAN dedicada, ACLs en switch | Aislar plano de control del tráfico de carga |
| Red de cluster | LACP + jumbo frames + BGP (si vas a Cilium) | NVLink intra-nodo no salva la red de servicio |
| BMC / IPMI | Acceso fuera de banda con TLS y MFA | Recuperación cuando el sistema operativo no arranca |
Antipatrones que te dejan clavado en nivel 0.
- Servidores mascota (con nombre propio, configurados a mano, no reemplazables).
- Cambios aplicados con
vidirecto sobre/etc/...sin commit a un repo. - Despliegue con
docker-composesin healthchecks ni reinicio automático. - Inventario que vive en una hoja Excel que nadie actualiza.
Orden de despliegue dentro del nivel. Imagen del sistema desde PXE/cloud-init con configuración inicial (LVM, hostname, red, SSH key, chrony) → bootstrap de bastion/jump host → inventario en Ansible (o equivalente declarativo aunque luego se reemplace) → drivers NVIDIA + container runtime → smoke test (un contenedor CUDA pasa nvidia-smi). En este punto, el servidor está listo para que entre Kubernetes.
Nivel 1 — Repetible: cluster Kubernetes operativo
La capacidad que da. Programar contenedores con scheduler, abstracción de red entre pods, volúmenes persistentes, lifecycle de cargas, escalado horizontal manual.
El test del nivel. "¿Puedo perder un nodo y que las cargas se reprogramen sin intervención humana?". Si sí, estás en nivel 1. Si no — porque los pods están pinneados a nodos, porque no hay réplicas, porque las PVCs no se reattachean — sigues en 0 con Kubernetes encima.
Piezas mínimas del nivel.
| Pieza | Decisión sugerida en 2026 | Alternativa principal |
|---|---|---|
| Distribución k8s | RKE2 (CIS-hardened por defecto, sin sobrecosto comercial) | k3s para edge muy pequeño, kubeadm puro para casos custom |
| CNI | Cilium con kube-proxy replacement, BGP, Gateway API | Calico (sin BGP no compite contra Cilium en 2026) |
| CSI block + filesystem + object | Rook-Ceph (RBD + CephFS + RGW S3-compatible) | OpenEBS Mayastor + Garage para deployments pequeños |
| Ingress | Cilium Gateway API (mejor unificar con CNI) | NGINX Ingress, Traefik |
| Cert básico | Self-signed bootstrap | (cert-manager entra en nivel 3) |
| Manejo de cargas | kubectl apply + Helm desde terminal | Sin GitOps todavía |
| Container registry | Cualquier registry interno (o externo de confianza) con TLS | (registry interno gestionado entra en nivel 2) |
Antipatrones que te bajan a nivel 0.
- Servicios desplegados con
kubectl applydesde la terminal de una persona y sin guardar el YAML en ninguna parte. - Volúmenes persistentes sin política de backup.
- “Cluster de un nodo” como producción permanente — un solo punto de fallo arquitectónico.
- CNI sin NetworkPolicy disponible o sin BGP cuando la red lo requiere.
Orden de despliegue dentro del nivel. RKE2 instalado en al menos tres nodos para control plane HA → Cilium instalado en modo kube-proxy replacement + BGP control plane → Rook-Ceph en al menos tres nodos cubriendo block (RBD) + filesystem (CephFS) + object (RGW S3-compatible) con replicación 3× o Erasure Coding según pool → smoke test (un Deployment con PVC arranca, los pods se reschedulean al cordon de un nodo, los datos persisten).
Nivel 2 — Definido: el cluster se reconstruye desde git
La capacidad que da. El estado del cluster vive en un repositorio. Cualquier cambio pasa por commit. Cualquier persona puede reconstruir el cluster (o uno equivalente) desde el repo y los backups. La observabilidad básica avisa cuando algo se rompe.
El test del nivel. “Si pierdo el cluster entero, ¿puedo recrearlo en X horas desde el repo + los backups, sin intervención manual fuera del bootstrap?”. Las dos horas son negociables; lo que define el nivel es que el repo + los backups bastan, no que la persona-que-sabe esté disponible.
Piezas mínimas del nivel.
| Pieza | Decisión sugerida en 2026 | Por qué |
|---|---|---|
| Forge | Forgejo (o Gitea, GitLab CE) | OSS auto-alojado, fork comunitario de Gitea, gobernanza abierta |
| Reconciliador GitOps | Flux | CNCF graduado, multi-tenancy nativo, lightweight |
| Registry de imágenes | Forgejo Container Registry | Junto al código, sin pieza extra |
| TSDB métricas | VictoriaMetrics + vmagent | Throughput superior a Prometheus puro, retención larga, compatible PromQL |
| Visualización | Grafana | Estándar de facto |
| Logs | Loki o Vector | OSS, integrado con Grafana |
| Alerting | Alertmanager + Keep (orquestador OSS) | Keep añade enrutamiento multi-canal sin lock-in |
| Backups DB | Barman Cloud (Postgres) | Estándar para CNPG |
| Backups objeto / dataset | Ceph RGW multisite + snapshots CephFS | Cross-pool y cross-site |
Antipatrones que te bajan a nivel 1.
kubectl applyaplicado en producción fuera del repo (drift no detectado).- Branches
maincon permisos de escritura para humanos sin revisión. - Repo monolítico sin separación tenant/infra/apps (cambios cruzados no auditables).
- Métricas que no se conservan más de 7 días (sin SLO observable a un mes vista).
- Alerting que dispara para todo (fatiga) o para nada (silencio).
Orden de despliegue dentro del nivel. Forgejo desplegado primero (es prerrequisito de todo lo demás) → Flux instalado y apuntando al repo de manifests → repositorio inicial con Helm releases de Cilium y Rook-Ceph reconciliados por Flux (sustituyendo los kubectl apply del nivel 1) → VictoriaMetrics + Grafana + Loki vía Helm/Flux → backups Postgres y snapshots Ceph programados → smoke test (tira el cluster, restaura desde repo + backup, los servicios vuelven).
Nivel 3 — Gestionado: identidades, certificados, secretos y políticas
La capacidad que da. Cualquier humano que opera el cluster lo hace con identidad propia (no kubeconfig compartido), con MFA y con permisos limitados. TLS interno automático. Secretos versionados encriptados. Políticas que rechazan configuraciones inseguras antes de que entren al cluster. Auditoría completa de quién hizo qué.
El test del nivel. “Si un atacante consigue el portátil de un administrador, ¿qué puede hacer en producción?”. En nivel 3 la respuesta es “poco”: MFA bloquea el segundo factor, las políticas Kyverno bloquean cambios destructivos sin aprobación, las NetworkPolicies impiden lateral movement, los secretos están encriptados con KMS externo, el audit log queda. En nivel 2, “todo”.
Piezas mínimas del nivel.
| Pieza | Decisión sugerida en 2026 | Por qué |
|---|---|---|
| IdP / OIDC | Defguard | OSS español, WireGuard + OIDC + 2FA, multi-org |
| Federación con cluster | OIDC en kube-apiserver, OIDC en Forgejo, OIDC en Grafana | SSO consistente |
| PKI interna | cert-manager + Trust Manager | Estándar de facto, ACME y CA interna |
| ACME externo | Let’s Encrypt para certs de borde | Sin pago, automatizado |
| Secretos en git | SOPS + age o KMS externo | Versionable, encriptado en repo |
| Sync de secretos | External Secrets Operator | Pull desde KMS / Vault al cluster |
| Policy as code | Kyverno (o OPA Gatekeeper) | Kyverno tiene menos curva de aprendizaje |
| NetworkPolicy | Cilium NetworkPolicy + L7 | Default deny per namespace |
| Runtime security | Tetragon (Cilium) | eBPF, complementa NetworkPolicy con detección |
| Vulnerability scanning | Trivy en pipeline CI + admission | SBOM por imagen, bloqueo de CVE críticas |
| Audit log | kube-apiserver con --audit-policy-file enviado a Loki | Trazabilidad regulatoria |
Políticas Kyverno mínimas a tener vivas.
- Deny de imágenes
:latesto sin sha digest. - Deny de pods sin
securityContext.runAsNonRoot=true. - Deny de pods sin
resources.limits(CPU + memoria). - Deny de Services sin label
owner=<equipo>. - Deny de cambios en namespaces críticos (
kube-system,flux-system) sin label de aprobación.
Antipatrones que te bajan a nivel 2.
kubeconfigcompartido entre administradores.- Secretos en
data:plano del manifest commiteado al repo. - NetworkPolicy ausente en namespaces nuevos por defecto (allow-all implícito).
kubectl editokubectl patchen producción sin pasar por el repo.
Orden de despliegue dentro del nivel. Defguard desplegado y enrolado con WireGuard / OIDC → integración OIDC con kube-apiserver, Forgejo y Grafana → cert-manager instalado y emitiendo certificados internos (CA propia para mTLS, Let’s Encrypt para borde) → SOPS configurado y External Secrets Operator instalado → migración de secretos plano → encriptado → Kyverno con políticas iniciales y modo audit, después enforce → NetworkPolicy default-deny por namespace → Tetragon habilitado → smoke test (intentar saltarse cada política y comprobar que las admisiones rechazan).
Nivel 4 — Optimizado para GPU: el cluster ya sabe lo que es una H100
La capacidad que da. El scheduler de Kubernetes ve las GPUs, las distingue, las puede particionar (MIG) o multiplexar (time-slicing), exponer métricas DCGM, autoescalar con KEDA usando métricas de la propia carga LLM (vllm:num_requests_running, vllm:gpu_cache_usage_perc), transportar trazas con semantic conventions GenAI. Todo lo necesario para que el stack de inferencia LLM se apoye en una plataforma que entiende su naturaleza.
El test del nivel. “Si pongo un pod que pide nvidia.com/gpu: 1, ¿se programa en la GPU correcta, con el slice correcto, con métricas DCGM expuestas, con observabilidad GenAI lista para recibir spans?”. Si sí, estás en nivel 4. Si la respuesta requiere “depende de qué nodo y quién lo despliegue”, todavía no.
Piezas mínimas del nivel.
| Pieza | Decisión sugerida en 2026 | Por qué |
|---|---|---|
| GPU device plugin | NVIDIA GPU Operator | Despliega drivers, container toolkit, DCGM y MIG manager con un operator |
| Particionamiento HW | MIG (Multi-Instance GPU) en H100 cuando aplique | Aislamiento hardware real, no time-slicing |
| Métricas GPU | DCGM Exporter | SM utilization, VRAM, temperatura, throttling, NVLink bandwidth |
| Métricas LLM | vLLM Prometheus endpoint + scrape | TTFT, TPOT, KV cache, prefix hit rate |
| Autoscaling | KEDA con ScaledObject Prometheus | Escala por métricas LLM, no por CPU |
| Operadores LLM | vLLM Production Stack / OME (Operator Model Engine) | Manejo declarativo de modelos / adapters |
| Trazas | OpenTelemetry Collector con receivers OTLP + processors + exporters | Semantic conventions gen_ai.* (post) |
| LeaderWorkerSet | API LeaderWorkerSet (k8s 1.30+) | Topología tensor parallel coherente con NVLink |
| Topology Manager | habilitado con single-numa-node | Pin de pods GPU a NUMA correcta |
Decisión clave: MIG, time-slicing o pasthrough.
- MIG divide una H100 en 1g.10gb, 2g.20gb, 3g.40gb, 7g.80gb (slices con aislamiento HW real). Útil para servir varios modelos pequeños o reservar capacidad por tenant con garantía. Limitación: hasta 7 instancias por GPU, perfiles predefinidos.
- Time-slicing comparte una GPU entre varios pods sin aislamiento HW. Útil para dev/test, no para producción multi-tenant con SLA.
- Passthrough asigna la GPU entera a un pod. Útil para tensor parallel sobre múltiples GPUs del mismo nodo (LLM grande con TP=4).
Para una plataforma LLM productiva, la regla práctica: passthrough para los modelos grandes con TP, MIG para embeddings y modelos pequeños que cohabitan, nunca time-slicing en producción.
Antipatrones que te bajan a nivel 3.
- Instalar drivers NVIDIA a mano fuera del GPU Operator (rotura silenciosa al actualizar Kubernetes).
- Servir un LLM con
requests.gpu: 1sin haber decidido MIG / passthrough (terminas con GPUs idle por fragmentación o pods que se pisan). - KEDA autoscalando por CPU (
HorizontalPodAutoscalerclásico) en pods que están casi siempre al 10% de CPU pero al 95% de KV cache. - OpenTelemetry desplegado pero sin semantic conventions
gen_ai.*(las trazas no son LLM-aware).
Orden de despliegue dentro del nivel. NVIDIA GPU Operator instalado vía Helm/Flux con la versión de driver que case con el motor LLM elegido → DCGM Exporter habilitado y métricas visibles en Grafana (dashboards NVIDIA importados) → MIG manager configurado para los nodos donde tenga sentido (mezcla typical en cluster 4×H100 SXM: dos GPUs con passthrough completo para el LLM general TP=4, dos GPUs particionadas en 2×3g.40gb cada una para LLMs pequeños + embeddings) → OpenTelemetry Collector con processors attributes para enriquecer spans con etiquetas propias (tenant_id, priority_tier) + exporters a Langfuse y a Tempo → KEDA instalado con ScaledObject de ejemplo apuntando a vllm:num_requests_running → vLLM Production Stack o OME para declarar modelos como CRD → smoke test (un Deployment de vLLM declarado vía CRD arranca, sirve un token, expone métricas, la traza llega a Langfuse, KEDA escala bajo carga sintética).
Nivel 5 — Handoff: el cluster es plataforma LLM, las siete capas entran encima
Llegado al nivel 4, el cluster cumple el contrato que el post de las siete capas asumía como punto de partida. El nivel 5 no añade infraestructura: añade el stack LLM propiamente dicho. Por completitud, los siete componentes del nivel 5 son:
- Gateway (Envoy AI Gateway) — entra primero, dirige tráfico a inferencia LLM y embeddings.
- Inferencia LLM (vLLM Production Stack o OME con vLLM) — sobre las GPUs ya descubiertas por el GPU Operator del nivel 4.
- Embeddings + reranker (Infinity, TEI) — pod separado del LLM, ya cubierto en el post anterior.
- Vector store + datos relacionales (Qdrant, PostgreSQL CNPG, Ceph RGW para pesos y adapters, CephFS para datasets) — la mayoría ya existía en nivel 2 como datos; ahora se especializa para RAG.
- Observabilidad LLM-aware (Langfuse) — se enchufa a la cadena OTel del nivel 4.
- Control plane GitOps — el del nivel 2 sigue siendo la única autoridad legítima.
- Dependency tracking (Hubble flows + Otterize) — sobre Cilium que ya existía en nivel 1.
El criterio para promocionar de nivel 4 a nivel 5 no es técnico: es contractual. El cluster ya soporta LLMs; la decisión es cuándo abrir tráfico real de clientes. La promoción exige: golden eval del modelo verde, runbook de incidentes firmado, SLOs negociados, plan de continuidad, mapeo a ENS / NIS2 / 42001 si aplica.
Las matemáticas que importan: cuánto cuesta saltarse un nivel
Para cuantificar la tesis del post, una estimación con orden de magnitud del coste de subir cada nivel a tiempo versus subirlo después de tener producción. Las cifras son tiempo de ingeniería con un equipo de plataforma pequeño (2-3 personas), asumiendo plantillas y experiencia previa.
| Nivel | Tiempo a montar sobre cluster vacío | Tiempo a retrofit con producción rodando |
|---|---|---|
| 0 → 1 | 1-2 semanas | 1-2 semanas (poco refactor downstream) |
| 1 → 2 | 2-3 semanas | 4-8 semanas (migrar todo a git) |
| 2 → 3 | 2-4 semanas | 8-16 semanas (rebuild de imágenes, migración de secretos, RBAC retroactivo) |
| 3 → 4 | 1-2 semanas | 4-8 semanas (reconfigurar GPU, mover modelos a MIG, instrumentar gen_ai.*) |
| 4 → 5 | 1-2 semanas | 2-4 semanas |
| Total 0 → 5 | ~10-15 semanas | ~20-40 semanas si se hace en orden equivocado |
Multiplicador típico observable en la práctica: 2× a 3× el coste si se hace en orden equivocado. Y eso asumiendo que se llega a hacer — muchos proyectos no superan el nivel 2 nunca porque “lo de la identidad” siempre puede esperar a otro sprint. Cuando llega el incidente, ya es tarde para empezar.
Más allá del tiempo, el coste operativo (incidentes nocturnos, escapes de seguridad, deuda invisible) crece exponencialmente con el desfase entre el nivel real y el nivel necesario. Un cluster en nivel 2 sirviendo LLMs productivos en clientes regulados es una bomba de relojería: técnicamente funciona, organizativamente no.
Diagrama final: la escalera completa con piezas
La escalera no es decorativa: cada nivel enable el siguiente. No se puede tener observabilidad LLM-aware (nivel 4) sin OTel desplegado vía Flux (nivel 2). No se puede tener TLS interno automático (nivel 3) sin un PKI raíz que viva en algún sitio (registro y certificados gestionados desde el nivel 2). No se puede tener KEDA escalando por métricas vLLM (nivel 4) sin Prometheus / VictoriaMetrics scrapeando (nivel 2). Los niveles no son una jerarquía conceptual: son una jerarquía de dependencias de instalación.
Decisiones de diseño típicas que rompen el progreso
Errores que se ven repetidamente y que tiran el cluster atrás de nivel:
1. Saltar de nivel 1 a nivel 4 directamente. “Tenemos prisa por servir el LLM, lo de identidad y GitOps lo hacemos después”. Después es siempre dos órdenes de magnitud más caro y siempre llega después del primer incidente.
2. Confundir Helm con GitOps. Tener Helm charts no es nivel 2. Es nivel 1 con plantillas. Nivel 2 exige que un reconciliador (Flux/ArgoCD) aplique las charts desde un repo, detecte drift y avise.
3. cert-manager sin policy de uso. Tener certificados auto-renovados pero usar TLS sólo en el ingress, sin mTLS interno entre servicios, deja la promesa de TLS coja y baja el nivel 3 a un cosplay del 3.
4. NVIDIA drivers a mano. Funciona el día uno y se rompe el día del primer upgrade de kernel. La regla: drivers siempre vía GPU Operator, nunca paquetes del sistema operativo.
5. Métricas Prometheus pero retención de 7 días. Sin retención larga (≥ 90 días) no hay SLO honesto. VictoriaMetrics con 1 año de retención cuesta poco más que Prometheus con 7 días, y desbloquea cumplimiento y postmortems serios.
6. OIDC sólo para kube-apiserver. Si Forgejo, Grafana, Defguard y vLLM cada uno tiene su propio sistema de auth, no tienes SSO, tienes islas. Un nivel 3 honesto exige federación.
7. Kyverno en modo audit permanente. Las políticas que no rechazan no son políticas, son alertas. En algún momento hay que pasar a enforce. Mientras tanto, sigues en nivel 2 con cara de 3.
8. MIG sin decisión consciente del perfil. Configurar MIG con el perfil por defecto sin haber medido el tamaño de los modelos que van a cohabitar deja GPUs fragmentadas con slices que nadie usa. La regla: MIG sólo si has medido y has decidido los perfiles por adelantado.
Todos comparten una raíz: declarar el nivel sin pasar el test del nivel. Decir “ya hicimos GitOps” cuando todavía se aplican cosas con kubectl edit en prod. Decir “ya hicimos identidad” cuando hay un kubeconfig admin compartido. Decir “estamos listos para LLM” cuando no hay DCGM Exporter ni Langfuse enchufado.
Aplicado a hardware on-premise típico: cluster 4×H100 SXM
Sobre el cluster genérico de referencia (4×H100 SXM 80 GB, NVLink, 640 GB RAM), un setup razonable después de pasar los cinco niveles distribuye así los componentes:
control plane (3 nodos sin GPU, hostnames cp-01..03)
├── kube-apiserver, etcd, controller-manager, scheduler
├── Flux, Forgejo, cert-manager, External Secrets, Kyverno
└── Tetragon (DaemonSet también aquí)
worker plane (≥ 3 nodos sin GPU, hostnames worker-cpu-01..03)
├── Cilium agent (DaemonSet)
├── Rook-Ceph OSDs + MONs + MDS (CephFS) + RGW (S3)
├── VictoriaMetrics + Grafana + Loki
├── Defguard (StatefulSet)
└── Langfuse + OTel Collector
worker plane GPU (≥ 2 nodos con 4×H100 SXM, hostnames worker-gpu-01..02)
├── NVIDIA GPU Operator (driver + container toolkit)
├── DCGM Exporter (DaemonSet)
├── MIG manager (configurando el perfil decidido)
├── vLLM (Deployment) — LLM general TP=4 ocupa 4 GPUs (passthrough)
├── vLLM (Deployment) — LLM código TP=2 ocupa 2 GPUs
├── Infinity (embeddings) — 2 réplicas cohabitan en 2 slices MIG
└── KEDA scaler escuchando métricas vLLM
La regla operativa: el plano de control y el plano CPU se separan del plano GPU. Un incidente en el plano GPU no debe llevarse por delante el plano de control (que es lo que recupera el cluster). Y el plano CPU concentra todo lo que mueve estado relevante (Forgejo, Rook-Ceph, Postgres CNPG, Langfuse): es el corazón a proteger.
El hardware GPU se especializa al máximo: pods GPU solamente corren en nodos GPU, y los nodos GPU no corren nada CPU-bound aparte del overhead operativo (Cilium, GPU Operator, DCGM). Esto se enforza con nodeSelector + taints/tolerations + Kyverno policy que rechaza pods sin requests GPU programándose en nodos GPU.
Lo que no hemos cubierto (próximos posts)
Este post recorre el camino vertical hacia arriba. Quedan piezas horizontales y otras transversales que merecen su propio artículo:
- Multi-site activo/standby: cómo se federan dos clusters con Cilium Cluster Mesh y qué cambia en cada nivel cuando hay dos sites en lugar de uno.
- Migración entre niveles con tráfico real: cómo se retrofitea un cluster que ya está en producción al nivel siguiente sin downtime.
- La operación día a día: runbooks por nivel, qué dashboards mirar cada mañana, qué SLOs definir por componente.
- El plano de coste: cuánto cuesta cada nivel en hardware, energía, horas de ingeniería, licencias OSS opcionales (soporte comercial de Rancher, Cilium Enterprise, etc.) y cuándo cada gasto se justifica.
- Cumplimiento operacionalizado: cómo se mapean los niveles 3 y 4 a controles ENS Alto, NIS2 e ISO/IEC 42001 sin convertir el cluster en un ejercicio de paperwork.
Ver también
- Anatomía de un stack de inferencia LLM on-premise — lo que se monta encima de un cluster en nivel 4. Este post es su prequel arquitectónico.
- El catálogo OSS para LLMOps en seis etapas — fichas individuales de muchas de las piezas citadas aquí.
- Tracing LLM con OpenTelemetry GenAI — el OTel del nivel 4 con detalle de las semantic conventions
gen_ai.*. - Pipeline LLMOps de seis etapas — el marco operacional que vive sobre el cluster nivel 5.
Referencias
- RKE2 Documentation — docs.rke2.io
- Cilium documentation — docs.cilium.io
- Rook-Ceph — rook.io
- Flux GitOps toolkit — fluxcd.io
- Forgejo — forgejo.org
- cert-manager — cert-manager.io
- External Secrets Operator — external-secrets.io
- Kyverno — kyverno.io
- NVIDIA GPU Operator — docs.nvidia.com/datacenter/cloud-native/gpu-operator
- DCGM Exporter — github.com/NVIDIA/dcgm-exporter
- KEDA — keda.sh
- LeaderWorkerSet API — github.com/kubernetes-sigs/lws
- vLLM Production Stack — docs.vllm.ai/en/latest/serving/production_stack.html
- OpenTelemetry Semantic Conventions for GenAI — opentelemetry.io/docs/specs/semconv/gen-ai
- CIS Kubernetes Benchmark
- NIST SP 800-207 — Zero Trust Architecture