<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Despliegue on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/despliegue/</link><description>Recent content in Despliegue on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Sun, 31 May 2026 08:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/despliegue/index.xml" rel="self" type="application/rss+xml"/><item><title>Siete fases de despliegue greenfield de una plataforma LLM on-premise: del hardware en la sala al primer token productivo</title><link>https://blog.lo0.es/posts/siete-fases-despliegue-plataforma-llm-on-premise/</link><pubDate>Sun, 31 May 2026 08:00:00 +0200</pubDate><guid>https://blog.lo0.es/posts/siete-fases-despliegue-plataforma-llm-on-premise/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Los dos posts anteriores de esta trilogía arquitectónica fijaron las piezas: &lt;a href="https://blog.lo0.es/posts/siete-capas-stack-inferencia-llm-on-premise/">las siete capas del stack de inferencia LLM&lt;/a> describen los componentes encima del cluster, y &lt;a href="https://blog.lo0.es/posts/cinco-niveles-madurez-plataforma-llm-on-premise/">los cinco niveles de madurez de la plataforma&lt;/a> describen los estratos por debajo. Este post fija el &lt;strong>cuándo&lt;/strong>: en qué orden se despliega cada cosa cuando se parte de cero —hardware comprado, racks instalados, cableado físico hecho— y se quiere llegar a un cluster sirviendo el primer token productivo a un cliente. Siete fases nominales &lt;strong>F0 a F6&lt;/strong> sin compromisos de calendario, organizadas por &lt;strong>dependencias técnicas&lt;/strong> (no se entra en F3 sin gate de F2) y con un &lt;strong>camino crítico&lt;/strong> identificable. F0 inventario hardware y conectividad eléctrica/red. F1 OS bare metal + drivers + container runtime. F2 cluster Kubernetes con CNI y storage Ceph operativos. F3 GitOps y observabilidad de infraestructura. F4 identidad, TLS, secretos y políticas. F5 plataforma GPU con observabilidad LLM-aware. F6 stack LLM operativo y abierto a tráfico productivo. Para cada fase: qué se monta, qué tiene que estar listo antes (dependencias entre fases), &lt;strong>gate&lt;/strong> que valida el cierre, y la trampa típica que retrasa el camino crítico. La tesis: una plataforma LLM on-premise se hunde mucho más a menudo por &lt;strong>secuenciar mal&lt;/strong> que por &lt;strong>elegir mal&lt;/strong>. Las herramientas están todas inventadas; el orden es lo único que cada equipo redescubre.&lt;/p>
&lt;h2 id="estás-aquí-las-siete-fases-y-sus-dependencias">Estás aquí: las siete fases y sus dependencias&lt;/h2>
&lt;p>Las fases no se ejecutan en serie pura. F2 y F3 pueden empezarse a la vez para acelerar (instalar Kubernetes y preparar el repo GitOps en paralelo). F4 puede solaparse con la parte final de F3. F5 espera a que F4 cierre porque los pods GPU exigen NetworkPolicy y RBAC desde el primer día. F6 es &lt;strong>un único paso atómico&lt;/strong>: el cluster entra en producción o no.&lt;/p>
&lt;div class="diagram" style="max-width:820px;margin:1rem auto;">
&lt;svg viewBox="0 0 820 340" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="dag de fases F0 a F6 con dependencias y camino crítico">
&lt;style>.b{stroke:#333;stroke-width:1.4;rx:6}.f0{fill:#f6e2e2;stroke:#a33}.f1{fill:#f4e3cf;stroke:#a63}.f2{fill:#eef0d0;stroke:#7a3}.f3{fill:#dfe9f5;stroke:#356}.f4{fill:#d8eecf;stroke:#373}.f5{fill:#f5e3d8;stroke:#763}.f6{fill:#ead8f5;stroke:#634}.lbl{font:600 12px sans-serif;fill:#222}.sm{font:11px sans-serif;fill:#222}.tiny{font:600 10px sans-serif;fill:#222}.note{font:italic 10px sans-serif;fill:#555}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#a)}.crit{stroke:#c33;stroke-width:2.4;fill:none;marker-end:url(#ac)}&lt;/style>
&lt;defs>&lt;marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#666"/>&lt;/marker>&lt;marker id="ac" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#c33"/>&lt;/marker>&lt;/defs>
&lt;text x="410" y="22" text-anchor="middle" class="lbl">DAG de fases · camino crítico marcado en rojo&lt;/text>
&lt;rect x="40" y="50" width="110" height="48" class="b f0"/>&lt;text x="95" y="68" text-anchor="middle" class="tiny">F0&lt;/text>&lt;text x="95" y="84" text-anchor="middle" class="sm">Hardware&lt;/text>&lt;text x="95" y="98" text-anchor="middle" class="note">Inventario · red&lt;/text>
&lt;rect x="180" y="50" width="110" height="48" class="b f1"/>&lt;text x="235" y="68" text-anchor="middle" class="tiny">F1&lt;/text>&lt;text x="235" y="84" text-anchor="middle" class="sm">Bare metal&lt;/text>&lt;text x="235" y="98" text-anchor="middle" class="note">OS · drivers&lt;/text>
&lt;rect x="320" y="50" width="110" height="48" class="b f2"/>&lt;text x="375" y="68" text-anchor="middle" class="tiny">F2&lt;/text>&lt;text x="375" y="84" text-anchor="middle" class="sm">Cluster k8s&lt;/text>&lt;text x="375" y="98" text-anchor="middle" class="note">Cilium · Ceph&lt;/text>
&lt;rect x="460" y="50" width="110" height="48" class="b f3"/>&lt;text x="515" y="68" text-anchor="middle" class="tiny">F3&lt;/text>&lt;text x="515" y="84" text-anchor="middle" class="sm">GitOps + obs&lt;/text>&lt;text x="515" y="98" text-anchor="middle" class="note">Flux · VM/Loki&lt;/text>
&lt;rect x="600" y="50" width="110" height="48" class="b f4"/>&lt;text x="655" y="68" text-anchor="middle" class="tiny">F4&lt;/text>&lt;text x="655" y="84" text-anchor="middle" class="sm">Identidad&lt;/text>&lt;text x="655" y="98" text-anchor="middle" class="note">OIDC · Kyverno&lt;/text>
&lt;rect x="320" y="170" width="110" height="48" class="b f5"/>&lt;text x="375" y="188" text-anchor="middle" class="tiny">F5&lt;/text>&lt;text x="375" y="204" text-anchor="middle" class="sm">GPU plane&lt;/text>&lt;text x="375" y="218" text-anchor="middle" class="note">NVIDIA op · DCGM&lt;/text>
&lt;rect x="600" y="170" width="110" height="48" class="b f6"/>&lt;text x="655" y="188" text-anchor="middle" class="tiny">F6&lt;/text>&lt;text x="655" y="204" text-anchor="middle" class="sm">Stack LLM live&lt;/text>&lt;text x="655" y="218" text-anchor="middle" class="note">7 capas activas&lt;/text>
&lt;path class="crit" d="M150,74 L180,74"/>
&lt;path class="crit" d="M290,74 L320,74"/>
&lt;path class="crit" d="M430,74 L460,74"/>
&lt;path class="crit" d="M570,74 L600,74"/>
&lt;path class="arr" d="M655,98 L655,170"/>
&lt;path class="arr" d="M375,98 L375,170"/>
&lt;path class="crit" d="M430,194 L600,194"/>
&lt;text x="410" y="262" text-anchor="middle" class="sm" fill="#c33">Camino crítico: F0 → F1 → F2 → F3 → F4 → F5 → F6&lt;/text>
&lt;text x="410" y="282" text-anchor="middle" class="note">Solapes posibles: F2 ↔ F3 (preparar repo mientras se monta cluster) · F3 ↔ F4 (políticas en audit antes de enforce)&lt;/text>
&lt;text x="410" y="304" text-anchor="middle" class="note">No solapables: F4 antes de F5 (GPU sin RBAC = bomba) · F5 antes de F6 (stack LLM sin GPU plane no arranca)&lt;/text>
&lt;/svg>
&lt;/div>
&lt;p>Las flechas rojas son el &lt;strong>camino crítico&lt;/strong>: el cuello de botella secuencial que ningún paralelismo puede acortar. Las flechas grises son dependencias que admiten solape parcial. Reconocer dónde solapar y dónde no es la diferencia entre un despliegue de tres meses y uno de seis para el mismo perímetro.&lt;/p>
&lt;h2 id="la-analogía-la-expedición-a-una-cumbre-de-ocho-mil">La analogía: la expedición a una cumbre de ocho mil&lt;/h2>
&lt;p>Una expedición a una cumbre alpina alta no es un trekking largo. Es una serie de &lt;strong>campamentos&lt;/strong> que se montan en orden, cada uno con su altura, su función y su gate de validación: si no se aclimata bien en el campo base, no se puede subir al C1 sin riesgo; si el C2 no tiene su cocina y su radio en marcha, no se puede mandar gente arriba; si el ataque a cumbre se intenta sin los porteadores en los campamentos altos, no hay descenso seguro.&lt;/p>
&lt;p>El despliegue greenfield de una plataforma LLM funciona idéntico. &lt;strong>F0&lt;/strong> es la llegada del material al campamento base — cajas, sponsors, permisos, primera revisión. &lt;strong>F1&lt;/strong> es montar el campo base operativo: cocina, tiendas, generador. &lt;strong>F2&lt;/strong> es la subida al C1: ya hay altitud real (cluster k8s en marcha) y se respira distinto. &lt;strong>F3&lt;/strong> es C2: añade comunicaciones, planificación y aclimatación operativa. &lt;strong>F4&lt;/strong> es C3, la última noche antes del ataque: equipo cordado, oxígeno listo, todos los protocolos verificados. &lt;strong>F5&lt;/strong> es el día del ataque a cumbre — esfuerzo intenso, márgenes finos. &lt;strong>F6&lt;/strong> es la cumbre y el inicio del descenso seguro: a partir de aquí la expedición está en operación día a día, ya no en construcción.&lt;/p>
&lt;p>La analogía aguanta dos lecciones útiles: &lt;strong>no se salta un campo&lt;/strong> (subir directo del campo base a la cumbre mata al equipo), y &lt;strong>los gates son técnicos, no anímicos&lt;/strong> (si el barómetro pone tormenta, no se sale, aunque haya entusiasmo). El equipo de plataforma que sigue esas dos reglas llega a la cumbre. El que las negocia, no.&lt;/p>
&lt;h2 id="f0--hardware-en-la-sala-el-campamento-base">F0 — Hardware en la sala: el campamento base&lt;/h2>
&lt;p>&lt;strong>Lo que se monta en esta fase.&lt;/strong> Inventario del hardware recibido (servidores, switches, PDUs, BMC), racks montados, cableado eléctrico y de datos terminado, etiquetado físico de cada equipo (rack/U/función), conectividad a la red corporativa, IPs de gestión asignadas, BMC accesible vía VPN con MFA, primer ping de cada nodo desde el bastion.&lt;/p>
&lt;p>&lt;strong>Dependencias.&lt;/strong> Cero técnicas — esta es la fase &lt;strong>previa al software&lt;/strong>. Sí dependencias de procurement (servidores comprados, switches comprados), de obra civil (sala con climatización suficiente, suelo técnico) y administrativas (acceso al CPD para los técnicos).&lt;/p>
&lt;p>&lt;strong>Gate de validación que cierra F0.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Cada nodo aparece en el inventario con &lt;code>(hostname, MAC, IP gestión, IP datos, rack, U, función, owner)&lt;/code>.&lt;/li>
&lt;li>BMC de cada nodo responde a &lt;code>ipmitool power status&lt;/code> y a la UI HTTPS desde la VPN de gestión.&lt;/li>
&lt;li>El switch de top-of-rack tiene su configuración versionada en git (incluso si todavía no hay GitOps de cluster, los configs de switch sí).&lt;/li>
&lt;li>Un comando &lt;code>for h in $(cat hosts); do ping -c1 -W1 $h.mgmt; done&lt;/code> devuelve 100% de éxito.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Trampa típica.&lt;/strong> Cablear &amp;ldquo;como salga&amp;rdquo; sin etiquetado físico ni esquema. Cuando llega F4 y hay que troubleshootear una NetworkPolicy, no saber qué interfaz física lleva qué VLAN duplica el tiempo de diagnóstico de cada incidente para siempre.&lt;/p>
&lt;p>&lt;strong>Por qué F0 no se solapa con F1.&lt;/strong> Hasta que cada servidor tiene IP de gestión y BMC vivo, no se puede automatizar el bootstrap del OS. Toda hora invertida en F0 ahorra horas en cada fase posterior — es la fase con mejor ROI del proyecto y la única que no admite atajos.&lt;/p>
&lt;h2 id="f1--bare-metal-el-campamento-base-operativo">F1 — Bare metal: el campamento base operativo&lt;/h2>
&lt;p>&lt;strong>Lo que se monta.&lt;/strong> Imagen del sistema operativo (Debian estable o Ubuntu LTS) provisionada vía PXE o cloud-init con el &lt;code>cloud-config&lt;/code> versionado en git. Cada nodo tiene: hostname coherente, particiones LVM, kernel ≥ 6.6, container runtime &lt;code>containerd&lt;/code>, drivers NVIDIA para los nodos GPU, &lt;code>chrony&lt;/code> sincronizando contra servidores propios, SSH key del operador como única vía de acceso, &lt;code>nvidia-smi&lt;/code> pasando smoke test en los nodos GPU.&lt;/p>
&lt;p>&lt;strong>Dependencias.&lt;/strong> F0 cerrada. Necesita la red de gestión funcionando para que el PXE responda y para que el bastion alcance cada nodo.&lt;/p>
&lt;p>&lt;strong>Gate de validación que cierra F1.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>ansible -i inventory all -m ping&lt;/code> devuelve 100% de éxito (o equivalente con Salt / Pulumi / etc).&lt;/li>
&lt;li>Cada nodo GPU pasa &lt;code>nvidia-smi&lt;/code> mostrando las GPUs esperadas con driver consistente entre nodos.&lt;/li>
&lt;li>Reloj de cada nodo desviado &amp;lt; 50 ms del NTP de referencia.&lt;/li>
&lt;li>Reinicio físico de un nodo lo deja exactamente en el mismo estado tras boot (idempotencia).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Trampa típica.&lt;/strong> Drivers NVIDIA instalados manualmente con &lt;code>apt install&lt;/code> o con el script &lt;code>.run&lt;/code> de NVIDIA. Funciona el día uno y se rompe el día de la primera actualización de kernel. La regla operativa que ya quedó establecida en &lt;a href="https://blog.lo0.es/posts/cinco-niveles-madurez-plataforma-llm-on-premise/">el post de los cinco niveles&lt;/a>: los drivers acaban siendo gestionados por el GPU Operator en F5; lo que se haga ahora es solo para que &lt;code>nvidia-smi&lt;/code> pase el smoke test, no para producción.&lt;/p>
&lt;p>&lt;strong>Solape posible.&lt;/strong> F1 puede empezar para algunos nodos mientras todavía se finaliza F0 en otros (greenfield real raramente entrega todos los servidores el mismo día). El gate de F1 es por cluster, no por nodo individual.&lt;/p>
&lt;h2 id="f2--cluster-kubernetes-operativo">F2 — Cluster Kubernetes operativo&lt;/h2>
&lt;p>&lt;strong>Lo que se monta.&lt;/strong> RKE2 instalado con tres nodos de control plane HA, joining de todos los workers (CPU y GPU), Cilium como CNI con &lt;code>kubeProxyReplacement&lt;/code> habilitado y BGP control plane apuntando a los switches ToR del F0, Rook-Ceph desplegado en los nodos de storage para cubrir block (RBD), filesystem (CephFS) y object (RGW S3-compatible), &lt;code>kubectl get nodes&lt;/code> devolviendo todos los nodos &lt;code>Ready&lt;/code>, primer pod de prueba con PVC montando y datos persistiendo tras restart del pod.&lt;/p>
&lt;p>&lt;strong>Dependencias.&lt;/strong> F1 cerrada (drivers + container runtime). Switches con BGP configurado (lo cerrado en F0). Discos NVMe particionados o disponibles raw para Ceph OSDs.&lt;/p>
&lt;p>&lt;strong>Gate de validación que cierra F2.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>kubectl get nodes -o wide&lt;/code> muestra todos los nodos &lt;code>Ready&lt;/code> con la versión esperada de Kubernetes.&lt;/li>
&lt;li>Un Deployment con replicas=3 y antiAffinity por nodo arranca y los pods caen en nodos distintos.&lt;/li>
&lt;li>Una PVC RWO (RBD) crea un volumen, el pod escribe datos, el pod se borra, otro pod la monta y lee los datos.&lt;/li>
&lt;li>Una PVC RWX (CephFS) hace lo mismo con dos pods escribiendo simultáneamente.&lt;/li>
&lt;li>Un bucket RGW vía &lt;code>s3cmd&lt;/code> o &lt;code>mc&lt;/code> acepta &lt;code>put&lt;/code> y &lt;code>get&lt;/code> con TLS.&lt;/li>
&lt;li>Hubble (lado lectura del CNI) muestra flow logs entre dos pods de namespaces distintos.&lt;/li>
&lt;li>Test de chaos: drain de un nodo worker no GPU; las cargas se reschedulean automáticamente.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Trampa típica.&lt;/strong> Empezar a &lt;code>kubectl apply&lt;/code> cargas reales en F2 sin GitOps. El backlog de cosas-aplicadas-a-mano crece más rápido que la capacidad de migrarlo a git después. La regla: en F2 sólo se aplican los &lt;strong>prerrequisitos&lt;/strong> del cluster (CNI, CSI, storage class por defecto). Cualquier carga de aplicación espera a F3.&lt;/p>
&lt;p>&lt;strong>Solape posible.&lt;/strong> F2 ↔ F3. Mientras se monta el cluster, se prepara en paralelo el repo GitOps (estructura de directorios, primeras Helm releases). Cuando F2 cierra, Flux se enchufa al repo y todo lo que iba a ser &lt;code>kubectl apply&lt;/code> ya está como manifest reconciliado.&lt;/p>
&lt;h2 id="f3--gitops-y-observabilidad-de-infraestructura">F3 — GitOps y observabilidad de infraestructura&lt;/h2>
&lt;p>&lt;strong>Lo que se monta.&lt;/strong> Forgejo desplegado primero (es prerrequisito de todo lo que viene). Repo &lt;code>gitops-infra&lt;/code> con la estructura inicial (&lt;code>apps/&lt;/code>, &lt;code>infrastructure/&lt;/code>, &lt;code>tenants/&lt;/code>, &lt;code>clusters/&lt;/code>). Flux instalado y reconciliando ese repo. Las cargas de prerequisito que se aplicaron a mano en F2 se mueven al repo y se reconcilian (deja de haber &lt;code>kubectl apply&lt;/code> operativo). VictoriaMetrics + vmagent scrapeando métricas. Grafana con dashboards iniciales (USE/RED + cluster + Ceph + Cilium). Loki recibiendo logs vía vector/fluent-bit. Alertmanager + Keep enrutando alertas a un canal de chat. Backups Barman Cloud para Postgres (futuro CNPG) y snapshots Ceph programados.&lt;/p>
&lt;p>&lt;strong>Dependencias.&lt;/strong> F2 cerrada. Bucket RGW para almacenar backups (lo cubre Ceph del F2).&lt;/p>
&lt;p>&lt;strong>Gate de validación que cierra F3.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Cambio aplicado al repo se refleja en el cluster en &amp;lt; 5 minutos sin intervención manual.&lt;/li>
&lt;li>Un cambio aplicado con &lt;code>kubectl edit&lt;/code> directamente al cluster es detectado por Flux y revertido (drift detection vinculante, no sólo observacional).&lt;/li>
&lt;li>Grafana muestra dashboards de cluster, Ceph, Cilium y nodos GPU (DCGM no llega hasta F5, pero las métricas básicas del nodo sí).&lt;/li>
&lt;li>Un alert de prueba enviado a Alertmanager llega al canal de chat en &amp;lt; 1 minuto.&lt;/li>
&lt;li>Restore de un backup Postgres en un cluster temporal devuelve datos coherentes (la prueba define el RPO real).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Trampa típica.&lt;/strong> Tener Helm charts en git pero seguir aplicando con &lt;code>helm install&lt;/code> desde la terminal. Eso es nivel 1 con disfraz de nivel 2. F3 sólo se cierra cuando Flux es &lt;strong>la única autoridad&lt;/strong> que aplica cambios y los humanos editan repo, no cluster.&lt;/p>
&lt;p>&lt;strong>Solape posible.&lt;/strong> F3 ↔ F4. Mientras se cierra F3, se puede preparar el manifest de Defguard y cert-manager en el repo. Cuando se reconcilien tienen donde aterrizar.&lt;/p>
&lt;h2 id="f4--identidad-certificados-secretos-políticas">F4 — Identidad, certificados, secretos, políticas&lt;/h2>
&lt;p>&lt;strong>Lo que se monta.&lt;/strong> Defguard desplegado con su Postgres dedicado (CNPG). Realm inicial con los operadores de plataforma enrolados con MFA y WireGuard. OIDC integrado en kube-apiserver (&lt;code>--oidc-issuer-url&lt;/code>, &lt;code>--oidc-client-id&lt;/code>, &lt;code>--oidc-username-claim&lt;/code>), en Forgejo, en Grafana, en Alertmanager — un solo SSO. cert-manager instalado con CA interna emitiendo certs internos para mTLS y con Let&amp;rsquo;s Encrypt ACME para certs de borde. SOPS configurado con KMS (puede ser un HSM físico, una clave age en un cofre, o un Vault externo) y External Secrets Operator sincronizando secretos al cluster. Kyverno desplegado con políticas iniciales en modo &lt;code>audit&lt;/code> durante una semana, después promovidas a &lt;code>enforce&lt;/code>. NetworkPolicy default-deny aplicada a cada namespace existente. Tetragon habilitado para runtime security. Audit log de kube-apiserver enviado a Loki con retención larga.&lt;/p>
&lt;p>&lt;strong>Dependencias.&lt;/strong> F3 cerrada (Flux aplica los manifests, VM/Loki ingieren métricas y logs).&lt;/p>
&lt;p>&lt;strong>Gate de validación que cierra F4.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>kubectl&lt;/code> con &lt;code>kubeconfig&lt;/code> admin compartido &lt;strong>deja de funcionar&lt;/strong>; cada operador usa su propio token OIDC con MFA.&lt;/li>
&lt;li>Un secret en &lt;code>data:&lt;/code> plano en un commit es rechazado por el pre-commit hook (o por Kyverno admission).&lt;/li>
&lt;li>Un pod sin &lt;code>securityContext.runAsNonRoot=true&lt;/code> es rechazado por Kyverno en admission.&lt;/li>
&lt;li>Una NetworkPolicy intencionalmente errónea (allow-all) en un namespace de tenant es rechazada.&lt;/li>
&lt;li>Un audit del último día devuelve la lista completa de actores y cambios (huella regulatoria mínima).&lt;/li>
&lt;li>Pen-test interno básico: un atacante con &lt;code>kubeconfig&lt;/code> falsificado falla en MFA y queda registrado.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Trampa típica.&lt;/strong> Kyverno en modo &lt;code>audit&lt;/code> permanente porque &amp;ldquo;no queremos romper cargas en producción&amp;rdquo;. F4 se cierra cuando las políticas están en &lt;code>enforce&lt;/code>. Hasta entonces, sigues en F3 con cara de F4.&lt;/p>
&lt;p>&lt;strong>Por qué F4 no se solapa con F5.&lt;/strong> F5 introduce pods GPU que mueven mucha VRAM y mucho cómputo. Sin NetworkPolicy default-deny, sin RBAC OIDC, sin Kyverno bloqueando configuraciones inseguras, los pods GPU son la superficie de ataque más jugosa del cluster. Cualquier compromiso en F5 sin F4 cerrada es un acceso casi-total al hardware caro.&lt;/p>
&lt;h2 id="f5--plataforma-gpu-con-observabilidad-llm-aware">F5 — Plataforma GPU con observabilidad LLM-aware&lt;/h2>
&lt;p>&lt;strong>Lo que se monta.&lt;/strong> NVIDIA GPU Operator vía Flux con la versión de driver decidida en F1 (ahora ya no se manipula a mano). DCGM Exporter expone métricas GPU a VictoriaMetrics. MIG manager configurado para los nodos donde tenga sentido (por ejemplo, en un 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 y embeddings). Topology Manager con política &lt;code>single-numa-node&lt;/code>. KEDA con Prometheus scaler instalado y un ScaledObject de ejemplo apuntando a una métrica vLLM (&lt;code>vllm:num_requests_running&lt;/code>). OpenTelemetry Collector con receivers OTLP, processors &lt;code>attributes&lt;/code> (enriquecen spans con &lt;code>tenant_id&lt;/code>, &lt;code>priority_tier&lt;/code>), exporters a Langfuse y a Tempo. LeaderWorkerSet API habilitada para topologías tensor parallel. OME (Operator Model Engine) o vLLM Production Stack desplegado como controller — todavía sin modelos cargados.&lt;/p>
&lt;p>&lt;strong>Dependencias.&lt;/strong> F4 cerrada (los pods GPU heredan NetworkPolicy default-deny, RBAC OIDC y políticas Kyverno).&lt;/p>
&lt;p>&lt;strong>Gate de validación que cierra F5.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Un pod de prueba pidiendo &lt;code>nvidia.com/gpu: 1&lt;/code> se programa en el nodo correcto y &lt;code>nvidia-smi&lt;/code> desde dentro del contenedor ve la GPU correcta (entera o un slice MIG).&lt;/li>
&lt;li>DCGM Exporter expone métricas en Grafana (utilization, VRAM, temperatura, NVLink bandwidth) para cada GPU.&lt;/li>
&lt;li>Un Deployment de vLLM de prueba arranca con un modelo pequeño (por ejemplo, un 7B FP16) cargado desde Ceph RGW.&lt;/li>
&lt;li>Un span OpenTelemetry generado por ese vLLM llega a Langfuse con atributos &lt;code>gen_ai.*&lt;/code> correctos.&lt;/li>
&lt;li>KEDA escala el Deployment de prueba de 1 a N réplicas bajo carga sintética y vuelve a 1 cuando cesa.&lt;/li>
&lt;li>Un upgrade del GPU Operator a una nueva versión drena y reprograma los pods GPU sin pérdida de servicio.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Trampa típica.&lt;/strong> Cargar el modelo grande &amp;ldquo;para probar&amp;rdquo; antes de que DCGM y OTel estén verdes. Cuando algo falle, no habrá métricas que distingan entre OOM, throttling térmico, mismatch de driver o problema de red — se diagnostica a ciegas. La regla: &lt;strong>modelo pequeño primero&lt;/strong>, golden path verde, &lt;strong>después&lt;/strong> modelo grande.&lt;/p>
&lt;p>&lt;strong>Solape posible.&lt;/strong> Ninguno con F6. F6 es atómico.&lt;/p>
&lt;h2 id="f6--stack-llm-en-producción">F6 — Stack LLM en producción&lt;/h2>
&lt;p>&lt;strong>Lo que se monta.&lt;/strong> Las &lt;strong>siete capas del stack de inferencia&lt;/strong> descritas en el &lt;a href="https://blog.lo0.es/posts/siete-capas-stack-inferencia-llm-on-premise/">post correspondiente&lt;/a>, desplegadas en este orden:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vector store + datos relacionales&lt;/strong> (Qdrant, PostgreSQL CNPG, Ceph RGW para pesos y adapters, CephFS para datasets). Algunos componentes ya existían de F3 como datos; aquí se especializan para RAG con sus colecciones y schemas iniciales.&lt;/li>
&lt;li>&lt;strong>Embeddings + reranker&lt;/strong> (Infinity con &lt;code>multilingual-e5-large&lt;/code>, TEI con &lt;code>bge-reranker-v2-m3&lt;/code>). Es la capa que debe estar verde antes de cualquier modelo grande, porque el RAG depende de ella.&lt;/li>
&lt;li>&lt;strong>Inferencia LLM&lt;/strong> (vLLM Production Stack con el LLM general y el LLM código). Carga modelos desde Ceph RGW. Multi-LoRA pool inicial vacío.&lt;/li>
&lt;li>&lt;strong>Gateway&lt;/strong> (Envoy AI Gateway) con OAuth Defguard, routing por &lt;code>body.model&lt;/code>, rate-limit por tenant. Este es el punto que &lt;strong>abre tráfico al exterior&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Observabilidad LLM-aware&lt;/strong> (Langfuse enchufado al OTel del F5).&lt;/li>
&lt;li>&lt;strong>Control plane GitOps&lt;/strong> y &lt;strong>dependency tracking&lt;/strong> ya estaban activos desde F3 y F4 respectivamente; aquí simplemente se les añade el catálogo de los nuevos servicios LLM.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Dependencias.&lt;/strong> Todas las anteriores cerradas.&lt;/p>
&lt;p>&lt;strong>Gate de validación que cierra F6.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Curl al endpoint público con bearer token Defguard recibe respuesta de chat completion en castellano técnico correcta, con &lt;code>trace_id&lt;/code> propagado.&lt;/li>
&lt;li>La traza aparece en Langfuse con atributos &lt;code>gen_ai.*&lt;/code> completos, latencia desglosada y &lt;code>tenant_id&lt;/code> propio.&lt;/li>
&lt;li>Un canary 5% de tráfico al nuevo modelo durante 24 h no degrada métricas de calidad ni de latencia.&lt;/li>
&lt;li>Un golpe de tráfico controlado dispara KEDA, las réplicas escalan, la latencia P95 se mantiene dentro de presupuesto.&lt;/li>
&lt;li>Un fallo intencional de un pod vLLM no afecta a la disponibilidad del endpoint (réplicas + reschedule).&lt;/li>
&lt;li>El operador interno demuestra el camino completo de revocación de acceso a un tenant en &amp;lt; 5 minutos (Defguard → Kyverno → cierre de NetworkPolicy).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Trampa típica.&lt;/strong> Abrir tráfico de cliente real antes de tener el runbook de incidentes firmado, el SLO negociado y el plan de continuidad probado. F6 técnicamente está cerrada; operativamente, la plataforma sigue siendo experimento hasta que el primer postmortem real demuestre que el equipo sabe responder.&lt;/p>
&lt;h2 id="las-matemáticas-que-importan-peso-relativo-del-esfuerzo-por-fase">Las matemáticas que importan: peso relativo del esfuerzo por fase&lt;/h2>
&lt;p>Sin comprometernos con semanas calendario, sí podemos cuantificar el &lt;strong>peso relativo&lt;/strong> del esfuerzo de ingeniería por fase en un greenfield típico. La curva no es uniforme:&lt;/p>
&lt;p>$$
\text{esfuerzo}_{F_i} \approx \text{base}_i \cdot (1 + \epsilon_i)
$$&lt;/p>
&lt;p>donde $\text{base}_i$ es el esfuerzo nominal y $\epsilon_i$ es el factor de &lt;strong>sorpresas&lt;/strong> (cabling errado, drivers incompatibles, certificados mal emitidos, conflictos de versiones). La tabla siguiente da el peso relativo nominal y el factor típico de sorpresa observado:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Fase&lt;/th>
&lt;th>Peso nominal&lt;/th>
&lt;th>Factor sorpresa típico ε&lt;/th>
&lt;th>Peso efectivo medio&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>F0 — Hardware&lt;/td>
&lt;td>8 %&lt;/td>
&lt;td>0.5 (1× a 2×)&lt;/td>
&lt;td>&lt;strong>12 %&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>F1 — Bare metal&lt;/td>
&lt;td>6 %&lt;/td>
&lt;td>0.3&lt;/td>
&lt;td>8 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>F2 — Cluster k8s&lt;/td>
&lt;td>12 %&lt;/td>
&lt;td>0.4&lt;/td>
&lt;td>17 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>F3 — GitOps + obs&lt;/td>
&lt;td>14 %&lt;/td>
&lt;td>0.5&lt;/td>
&lt;td>21 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>F4 — Identidad + políticas&lt;/td>
&lt;td>18 %&lt;/td>
&lt;td>0.7&lt;/td>
&lt;td>&lt;strong>31 %&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>F5 — GPU plane&lt;/td>
&lt;td>10 %&lt;/td>
&lt;td>0.4&lt;/td>
&lt;td>14 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>F6 — Stack LLM live&lt;/td>
&lt;td>8 %&lt;/td>
&lt;td>0.3&lt;/td>
&lt;td>10 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Buffer / integración&lt;/td>
&lt;td>24 %&lt;/td>
&lt;td>—&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Dos observaciones operativas. &lt;strong>F4 concentra más sorpresas que ninguna otra&lt;/strong> (federación OIDC entre cuatro o cinco apps con configuraciones distintas, políticas Kyverno que tumban cargas legítimas, secretos rotos por encriptación mal probada). &lt;strong>F0 tiene un coeficiente de sorpresa alto en relación a su tamaño&lt;/strong> porque cualquier error de cableado o etiquetado se descubre tarde y se paga caro. Las dos consecuencias prácticas: planificar &lt;strong>F4 con margen generoso&lt;/strong> y no escatimar tiempo en &lt;strong>F0&lt;/strong> porque cada hora ahorrada ahí cuesta cinco después.&lt;/p>
&lt;p>&lt;strong>Camino crítico y holguras.&lt;/strong> El camino crítico es lineal F0 → F1 → F2 → F3 → F4 → F5 → F6. Las únicas holguras reales son los solapes ya identificados:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>F2 ↔ F3 (holgura ~30 %)&lt;/strong>: preparar repo y dashboards iniciales mientras se monta cluster.&lt;/li>
&lt;li>&lt;strong>F3 ↔ F4 (holgura ~20 %)&lt;/strong>: manifests de identidad listos al cerrar F3, aplicación inmediata.&lt;/li>
&lt;li>&lt;strong>Dentro de F4&lt;/strong>: políticas en modo &lt;code>audit&lt;/code> corriendo en paralelo con setup de Defguard.&lt;/li>
&lt;/ul>
&lt;p>Nada acorta el camino crítico más de un ~15 % del total. Quien promete un greenfield productivo en la mitad del tiempo razonable está vendiendo otra cosa: probablemente saltarse F4 o cargar F6 con F5 verde-pero-no-validado.&lt;/p>
&lt;h2 id="diagrama-final-el-cronograma-de-despliegue-completo">Diagrama final: el cronograma de despliegue completo&lt;/h2>
&lt;div class="diagram" style="max-width:820px;margin:1rem auto;">
&lt;svg viewBox="0 0 820 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="cronograma completo del despliegue por fases con piezas y gates">
&lt;style>.b{stroke:#333;stroke-width:1.4;rx:6}.bg{fill:#fafafa;stroke:#bbb;rx:8}.f0{fill:#f6e2e2;stroke:#a33}.f1{fill:#f4e3cf;stroke:#a63}.f2{fill:#eef0d0;stroke:#7a3}.f3{fill:#dfe9f5;stroke:#356}.f4{fill:#d8eecf;stroke:#373}.f5{fill:#f5e3d8;stroke:#763}.f6{fill:#ead8f5;stroke:#634}.gate{fill:#fffbe0;stroke:#a90}.lbl{font:600 12px sans-serif;fill:#222}.sm{font:11px sans-serif;fill:#222}.tiny{font:600 10px sans-serif;fill:#222}.note{font:italic 10px sans-serif;fill:#555}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#a)}&lt;/style>
&lt;defs>&lt;marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#666"/>&lt;/marker>&lt;/defs>
&lt;text x="410" y="22" text-anchor="middle" class="lbl">Cronograma completo: piezas por fase y gates de validación&lt;/text>
&lt;rect x="40" y="40" width="740" height="68" class="b f0"/>&lt;text x="60" y="58" class="tiny">F0 · HARDWARE EN LA SALA&lt;/text>
&lt;text x="60" y="76" class="sm">Inventario · cableado · BMC TLS+MFA · IPs gestión · switches BGP versionados&lt;/text>
&lt;text x="60" y="92" class="note">Gate: `for h in hosts; ping $h.mgmt` 100% éxito · inventario completo&lt;/text>
&lt;rect x="40" y="116" width="740" height="68" class="b f1"/>&lt;text x="60" y="134" class="tiny">F1 · BARE METAL&lt;/text>
&lt;text x="60" y="152" class="sm">PXE/cloud-init · OS LTS · kernel ≥6.6 · containerd · drivers NVIDIA · chrony · LVM&lt;/text>
&lt;text x="60" y="168" class="note">Gate: `ansible all -m ping` 100% · `nvidia-smi` smoke OK · reboot idempotente&lt;/text>
&lt;rect x="40" y="192" width="740" height="68" class="b f2"/>&lt;text x="60" y="210" class="tiny">F2 · CLUSTER KUBERNETES&lt;/text>
&lt;text x="60" y="228" class="sm">RKE2 HA · Cilium (kube-proxy replacement + BGP) · Rook-Ceph (RBD + CephFS + RGW)&lt;/text>
&lt;text x="60" y="244" class="note">Gate: PVCs RWO/RWX OK · bucket RGW OK · drain node sin downtime&lt;/text>
&lt;rect x="40" y="268" width="740" height="68" class="b f3"/>&lt;text x="60" y="286" class="tiny">F3 · GITOPS + OBSERVABILIDAD INFRA&lt;/text>
&lt;text x="60" y="304" class="sm">Forgejo · Flux · VictoriaMetrics + Grafana + Loki · Alertmanager + Keep · backups&lt;/text>
&lt;text x="60" y="320" class="note">Gate: cambio en repo → cluster en &amp;lt;5min · drift revertido · restore backup OK&lt;/text>
&lt;rect x="40" y="344" width="740" height="68" class="b f4"/>&lt;text x="60" y="362" class="tiny">F4 · IDENTIDAD + POLÍTICAS&lt;/text>
&lt;text x="60" y="380" class="sm">Defguard OIDC+MFA+WG · cert-manager · SOPS+ESO · Kyverno enforce · NP default deny · Tetragon&lt;/text>
&lt;text x="60" y="396" class="note">Gate: kubeconfig admin compartido no funciona · políticas en enforce · audit log completo&lt;/text>
&lt;rect x="40" y="420" width="740" height="68" class="b f5"/>&lt;text x="60" y="438" class="tiny">F5 · PLATAFORMA GPU + OBSERVABILIDAD LLM-AWARE&lt;/text>
&lt;text x="60" y="456" class="sm">NVIDIA GPU Operator · DCGM · MIG manager · KEDA con métricas vLLM · OTel gen_ai.* · OME&lt;/text>
&lt;text x="60" y="472" class="note">Gate: pod GPU programado · DCGM verde · vLLM smoke con modelo pequeño · KEDA escala&lt;/text>
&lt;rect x="40" y="496" width="740" height="38" class="b f6"/>&lt;text x="60" y="514" class="tiny">F6 · STACK LLM LIVE&lt;/text>
&lt;text x="60" y="528" class="sm">7 capas activas · primer modelo verde · canary OK · runbook firmado · primer cliente con SLA&lt;/text>
&lt;/svg>
&lt;/div>
&lt;p>El cronograma no es decorativo: cada fila define lo que se monta en su fase &lt;strong>y el gate que la cierra&lt;/strong>. Una fase no se da por terminada hasta que su gate está verde. Una fase con gate amarillo arrastra todas las posteriores; intentar saltar a la siguiente con un gate parcialmente cumplido es lo que produce, varias semanas después, el incidente que obliga a &amp;ldquo;volver a F4 con producción rodando&amp;rdquo; — la situación más cara de toda la matriz de costes del &lt;a href="https://blog.lo0.es/posts/cinco-niveles-madurez-plataforma-llm-on-premise/">post de los cinco niveles&lt;/a>.&lt;/p>
&lt;h2 id="errores-típicos-de-planificación">Errores típicos de planificación&lt;/h2>
&lt;p>Patrones que retrasan o hunden el despliegue greenfield, independientemente de las herramientas elegidas:&lt;/p>
&lt;p>&lt;strong>1. Comprar el LLM antes que el cluster.&lt;/strong> Empezar el proyecto por &amp;ldquo;qué modelo vamos a servir&amp;rdquo; en vez de por &amp;ldquo;qué plataforma puede sostener cualquier modelo razonable&amp;rdquo;. El modelo es un parámetro intercambiable; la plataforma no.&lt;/p>
&lt;p>&lt;strong>2. Subestimar F0.&lt;/strong> &amp;ldquo;Eso lo hace el equipo de redes&amp;rdquo;. Sí, pero el resultado de F0 lo consumen todas las fases posteriores. Si el equipo de redes entrega tarde, el proyecto entero llega tarde — y nadie lo había marcado como camino crítico.&lt;/p>
&lt;p>&lt;strong>3. Solapar F4 con F5 &amp;ldquo;para ganar tiempo&amp;rdquo;.&lt;/strong> Es la única dependencia donde no hay holgura. Si se intenta solapar, F5 acaba operando con políticas en &lt;code>audit&lt;/code> permanente (no estás en F4) o sin OIDC integrado (operadores con kubeconfig compartido tocando GPU). Ambos antipatrones se quedan en producción.&lt;/p>
&lt;p>&lt;strong>4. Saltar el smoke test del modelo pequeño en F5.&lt;/strong> &amp;ldquo;Vamos a por el 70B directamente&amp;rdquo;. Cuando algo falle (y algo fallará), no habrá baseline contra el que diagnosticar.&lt;/p>
&lt;p>&lt;strong>5. Tratar F6 como &amp;ldquo;encender vLLM&amp;rdquo;.&lt;/strong> F6 incluye gateway, observabilidad LLM-aware, runbook, SLO, plan de continuidad. Encender vLLM es cinco minutos; cerrar F6 es semanas de validación y firma.&lt;/p>
&lt;p>&lt;strong>6. No definir gates por escrito.&lt;/strong> Si los gates no están escritos, son negociables a posteriori. &amp;ldquo;Esto ya cuenta como F4&amp;rdquo; es la frase que precede a los seis meses siguientes de retrofit.&lt;/p>
&lt;p>&lt;strong>7. Asignar la fase a un único responsable.&lt;/strong> Cada fase necesita al menos dos personas que la entiendan. La rotación de personal en proyectos largos destruye el conocimiento; los gates por escrito + revisión cruzada lo preservan.&lt;/p>
&lt;p>&lt;strong>8. Olvidar el camino de descenso.&lt;/strong> El post se centra en subir. La operación día a día (descenso, en la analogía) es otra historia que también merece planificación — runbooks, on-call, capacidad de upgrade, plan de fin de vida. Los equipos que sólo planifican la subida llegan a la cumbre y se quedan ahí sin oxígeno.&lt;/p>
&lt;h2 id="aplicado-a-hardware-on-premise-típico-4h100-sxm">Aplicado a hardware on-premise típico: 4×H100 SXM&lt;/h2>
&lt;p>Sobre el cluster genérico de referencia (4×H100 SXM 80 GB, NVLink, 640 GB RAM por nodo GPU, 3 nodos control plane, 3-5 nodos worker CPU, 2 nodos worker GPU), el reparto &lt;strong>temporal&lt;/strong> del trabajo se distribuye así:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">F0 (hardware)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─ 8 servidores físicos racks + switches + BMC + IPs gestión
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├─ 3 nodos cp-01..03 — control plane (sin GPU)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├─ 3 nodos worker-cpu-01..03 — CPU plane (Forgejo, Ceph, observabilidad)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └─ 2 nodos worker-gpu-01..02 — GPU plane (4×H100 SXM cada uno)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">F1 (bare metal)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─ OS + drivers + containerd en los 8 nodos por igual
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> (los drivers NVIDIA solo en los 2 nodos GPU, smoke `nvidia-smi`)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">F2 (cluster k8s)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─ RKE2 control plane en cp-01..03 (HA con etcd embebido)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> workers joining: 3 CPU + 2 GPU
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Ceph OSDs en los 3 nodos worker CPU
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> pools por defecto: RBD-replicated-3, CephFS-replicated-3, RGW
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">F3 (GitOps + obs)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─ Forgejo + Flux + VM/Grafana/Loki + Keep en CPU plane
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> primer repo `gitops-infra` reconcilia lo de F2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">F4 (identidad)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─ Defguard en CPU plane (StatefulSet con Postgres CNPG)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> OIDC en kube-apiserver, Forgejo, Grafana, Alertmanager
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Kyverno como Deployment en control plane
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">F5 (GPU plane)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─ NVIDIA GPU Operator targetea workers GPU
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> MIG manager: 1ª GPU MIG 7g.80gb (= passthrough), 2ª 2×3g.40gb
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> OTel Collector como DaemonSet en GPU plane + CPU plane
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> primer vLLM con modelo 7B FP16 verde
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">F6 (stack LLM)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─ Las 7 capas se reconcilian vía Flux desde un segundo repo `gitops-llm`
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> primer endpoint público con OAuth Defguard
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> primer cliente productivo enrolado bajo SLA
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>La distribución física del cluster aprovecha el aislamiento entre planos definido en F0: el plano de control no toca GPU, el plano CPU concentra estado relevante (Forgejo, Ceph, Postgres CNPG, Langfuse, Defguard) y el plano GPU se especializa al máximo. Esa separación, decidida en F0 antes de instalar el primer servidor, condiciona el éxito del resto de fases — es otro recordatorio de por qué F0 importa más de lo que parece.&lt;/p>
&lt;h2 id="lo-que-no-hemos-cubierto-próximos-posts">Lo que no hemos cubierto (próximos posts)&lt;/h2>
&lt;p>Este post recorre el &lt;strong>camino de subida&lt;/strong> a la cumbre. Quedan piezas que merecen su propio artículo:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>El descenso seguro&lt;/strong>: operación día a día, runbooks por componente, on-call, capacity planning continuo, ciclo de upgrades del cluster sin downtime.&lt;/li>
&lt;li>&lt;strong>Multi-site (segunda cumbre)&lt;/strong>: cómo se federan dos clusters con Cilium Cluster Mesh y qué fases extra introduce. F3.5 (Cluster Mesh) y F4.5 (replicación cross-site) son las fases que faltan.&lt;/li>
&lt;li>&lt;strong>El camino brownfield&lt;/strong>: lo que cambia cuando ya hay un cluster con cargas. Las fases siguen siendo las mismas, pero los gates se aplican retroactivamente y cada paso requiere planning de migración.&lt;/li>
&lt;li>&lt;strong>El coste calendario real&lt;/strong>: rangos típicos en semanas para un equipo de plataforma de 2-3 personas, separado por fase, con bandas de incertidumbre.&lt;/li>
&lt;li>&lt;strong>El handoff a operación&lt;/strong>: cómo se entrega la plataforma del equipo de despliegue al equipo de operación, qué documentos firman, qué se hereda y qué se renegocia.&lt;/li>
&lt;/ul>
&lt;h2 id="ver-también">Ver también&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/posts/siete-capas-stack-inferencia-llm-on-premise/">Anatomía de un stack de inferencia LLM on-premise&lt;/a> — las siete capas que se montan en F6. Los componentes, no el cronograma.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/cinco-niveles-madurez-plataforma-llm-on-premise/">Cinco niveles de madurez de la plataforma debajo del LLM&lt;/a> — los niveles correspondientes a las fases F1→F5. Los estratos, no la secuencia.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/catalogo-herramientas-oss-llmops/">El catálogo OSS para LLMOps en seis etapas&lt;/a> — fichas individuales de las piezas citadas aquí.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/tracing-llm-otel-genai/">Tracing LLM con OpenTelemetry GenAI&lt;/a> — el OTel del F5 con detalle de las semantic conventions &lt;code>gen_ai.*&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h2 id="referencias">Referencias&lt;/h2>
&lt;ul>
&lt;li>RKE2 Documentation — &lt;a href="https://docs.rke2.io/">docs.rke2.io&lt;/a>&lt;/li>
&lt;li>Cilium documentation — &lt;a href="https://docs.cilium.io/">docs.cilium.io&lt;/a>&lt;/li>
&lt;li>Rook documentation — &lt;a href="https://rook.io/">rook.io/docs&lt;/a>&lt;/li>
&lt;li>Flux GitOps toolkit — &lt;a href="https://fluxcd.io/">fluxcd.io&lt;/a>&lt;/li>
&lt;li>Forgejo — &lt;a href="https://forgejo.org/">forgejo.org&lt;/a>&lt;/li>
&lt;li>cert-manager — &lt;a href="https://cert-manager.io/">cert-manager.io&lt;/a>&lt;/li>
&lt;li>External Secrets Operator — &lt;a href="https://external-secrets.io/">external-secrets.io&lt;/a>&lt;/li>
&lt;li>Kyverno — &lt;a href="https://kyverno.io/">kyverno.io&lt;/a>&lt;/li>
&lt;li>NVIDIA GPU Operator — &lt;a href="https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/">docs.nvidia.com/datacenter/cloud-native/gpu-operator&lt;/a>&lt;/li>
&lt;li>DCGM Exporter — &lt;a href="https://github.com/NVIDIA/dcgm-exporter">github.com/NVIDIA/dcgm-exporter&lt;/a>&lt;/li>
&lt;li>KEDA — &lt;a href="https://keda.sh/">keda.sh&lt;/a>&lt;/li>
&lt;li>LeaderWorkerSet API — &lt;a href="https://github.com/kubernetes-sigs/lws">github.com/kubernetes-sigs/lws&lt;/a>&lt;/li>
&lt;li>OpenTelemetry Semantic Conventions for GenAI — &lt;a href="https://opentelemetry.io/docs/specs/semconv/gen-ai/">opentelemetry.io/docs/specs/semconv/gen-ai&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>