<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Dynamo on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/dynamo/</link><description>Recent content in Dynamo on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Mon, 18 May 2026 17:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/dynamo/index.xml" rel="self" type="application/rss+xml"/><item><title>Operators de inferencia LLM en Kubernetes: OME, vLLM Production Stack, NVIDIA Dynamo y llm-d</title><link>https://blog.lo0.es/posts/operators-llm-kubernetes/</link><pubDate>Mon, 18 May 2026 17:00:00 +0200</pubDate><guid>https://blog.lo0.es/posts/operators-llm-kubernetes/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Servir un LLM en producción no es ejecutar un binario: es coordinar &lt;strong>un modelo&lt;/strong> (decenas de gigabytes que tardan minutos en cargar), &lt;strong>un runtime&lt;/strong> (vLLM, SGLang, TensorRT-LLM con cien flags), &lt;strong>GPUs heterogéneas&lt;/strong> (NVLink, MIG, PCIe), &lt;strong>prefill y decode&lt;/strong> que viven mejor separados, &lt;strong>un cache de KV&lt;/strong> que quiere offloading a tiers más fríos, &lt;strong>routing inteligente&lt;/strong> que aproveche prefix caching, y &lt;strong>autoscaling&lt;/strong> que reaccione a métricas que no son CPU%. Un &lt;code>Deployment&lt;/code> plano de Kubernetes solo cubre el primer 20% de esto. El otro 80% lo cubren los &lt;strong>operators de inferencia LLM&lt;/strong>, que en 2026 son cuatro relevantes: &lt;strong>OME&lt;/strong> (LMSYS, julio 2025, multi-engine con foco en SGLang), &lt;strong>vLLM Production Stack&lt;/strong> (Helm chart curado del propio vLLM con LMCache para tiered KV), &lt;strong>NVIDIA Dynamo&lt;/strong> (sucesor oficial de Triton, multi-engine, scheduler propio Grove) y &lt;strong>llm-d&lt;/strong> (donación CNCF de marzo 2026 por Red Hat + Google + IBM + CoreWeave + NVIDIA, sobre vLLM, foco en escala distribuida). Detrás de los cuatro está &lt;strong>KServe&lt;/strong>, el operator madre del CNCF que normalizó el concepto de &lt;code>InferenceService&lt;/code> y sobre el que varios se apoyan. Este artículo recorre la jerarquía completa, da un mapa de decisión y enseña a no perderse cuando alguien suelte siete siglas en la primera reunión.&lt;/p>
&lt;blockquote>
&lt;p>Este artículo cierra la serie de inferencia LLM. Los anteriores fueron &lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">KV cache: la memoria de trabajo que sostiene la inferencia LLM&lt;/a>, &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes: la pieza de inferencia LLM que sí escala&lt;/a> y &lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention por dentro y el estado del arte del KV cache en 2026&lt;/a>. Allí explicamos qué pasa &lt;strong>dentro de un proceso de inferencia&lt;/strong>. Aquí explicamos cómo se coordinan &lt;strong>muchos procesos de inferencia&lt;/strong> a través de Kubernetes.&lt;/p>
&lt;/blockquote>
&lt;h2 id="la-analogía-de-initd-a-systemd-a-operators">La analogía: de &lt;code>init.d&lt;/code> a systemd a operators&lt;/h2>
&lt;p>El que lleva 20 años en sysadmin reconocerá el patrón. Hace décadas, arrancar un servicio en Linux era un script shell en &lt;code>/etc/init.d/&lt;/code>: start, stop, status, recargado a mano. Cuando los servicios se hicieron más complejos —dependencias entre ellos, monitorización, restart on failure, slots por usuario— se hizo evidente que un script no bastaba. Llegó &lt;strong>systemd&lt;/strong>, que convirtió &amp;ldquo;un servicio&amp;rdquo; en una &lt;strong>unidad declarativa&lt;/strong> con dependencias, recursos, restart policy, sockets, timers. El script no desapareció; se subió un nivel de abstracción.&lt;/p>
&lt;p>Kubernetes hizo el mismo movimiento para servicios distribuidos. Un &lt;code>Deployment&lt;/code> declara &amp;ldquo;quiero N réplicas de este contenedor&amp;rdquo;; un &lt;code>Service&lt;/code> declara &amp;ldquo;estas réplicas se exponen así&amp;rdquo;; un &lt;code>Ingress&lt;/code> declara &amp;ldquo;este tráfico HTTP entra aquí&amp;rdquo;. El controller traduce la declaración en estado real y mantiene el sistema convergente.&lt;/p>
&lt;p>Servir LLMs en 2024 era el equivalente al &lt;code>/etc/init.d/&lt;/code>: cada equipo escribía sus &lt;code>Deployment&lt;/code>/&lt;code>Service&lt;/code>/&lt;code>HPA&lt;/code> con scripts customizados de carga de modelo, drenaje de sesiones, manejo de GPU. Lo cubrimos en el &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">artículo de vLLM en Kubernetes&lt;/a>: se puede hacer, y de hecho funciona, pero &lt;strong>es repetitivo, frágil y nadie está extrayendo las abstracciones correctas&lt;/strong>. Servir LLMs en 2026 ha vivido la misma transición que los servicios: ha aparecido el equivalente a systemd —los &lt;strong>operators de inferencia&lt;/strong>— que normalizan las abstracciones y dejan al ingeniero declarar lo importante: &amp;ldquo;este modelo, con este runtime, así de escalable, con esta política de routing&amp;rdquo;.&lt;/p>
&lt;p>Hay cuatro operators relevantes en 2026 y un quinto antecesor común. Vamos por orden.&lt;/p>
&lt;h2 id="por-qué-un-operator-y-no-solo-un-deployment">Por qué un operator, y no solo un Deployment&lt;/h2>
&lt;p>Listar lo que un operator de inferencia aporta sobre un Deployment plano es la mejor manera de entender qué problema resuelve:&lt;/p>
&lt;p>&lt;strong>Modelo como ciudadano de primera clase.&lt;/strong> En un Deployment, el modelo es &amp;ldquo;lo que descargas en un initContainer y montas como volumen&amp;rdquo;. En un operator, el modelo es una &lt;code>CustomResource&lt;/code> con metadatos (origen, fingerprint, licencia, GPU requirements). Pueden compartirse entre InferenceServices, versionarse, replicarse a múltiples nodos. Es la diferencia entre &amp;ldquo;un fichero&amp;rdquo; y &amp;ldquo;un artifact gestionado&amp;rdquo;.&lt;/p>
&lt;p>&lt;strong>Runtime como ciudadano de primera clase.&lt;/strong> Idem para el runtime (vLLM/SGLang/TRT-LLM): no es &amp;ldquo;una imagen Docker con flags&amp;rdquo;; es una &lt;code>ServingRuntime&lt;/code> que declara qué args acepta, qué métricas exporta, qué tipos de despliegue soporta (single-node, multi-node TP, PD-disag). Cambiar de runtime es cambiar una referencia, no reescribir todos los manifests.&lt;/p>
&lt;p>&lt;strong>Composición declarativa.&lt;/strong> Una &lt;code>InferenceService&lt;/code> (CRD nuclear de KServe y descendientes) &lt;strong>referencia&lt;/strong> un modelo y un runtime, &lt;strong>declara&lt;/strong> la política de escalado, &lt;strong>enlaza&lt;/strong> observabilidad, &lt;strong>configura&lt;/strong> routing. El controller compone todas las piezas: Deployment(s), Service, HPA, eventualmente LeaderWorkerSet, ScaledObject de KEDA, HTTPRoute de Gateway API. Tú declaras intención; el operator emite los 8 recursos derivados.&lt;/p>
&lt;p>&lt;strong>Prefill–decode disaggregation operacional.&lt;/strong> Como vimos en el artículo de PagedAttention, separar prefill y decode en pools distintos puede dar 7× goodput. Modelar eso con Deployments planos es viable, pero requiere coordinar dos sets de pods, un transport para mover KV cache, routing condicional. Un operator lo modela como una sola &lt;code>InferenceService&lt;/code> con dos sub-pools.&lt;/p>
&lt;p>&lt;strong>Autoscaling con métricas LLM.&lt;/strong> El HPA estándar no entiende &lt;code>vllm:num_requests_waiting&lt;/code>. Un operator integra KEDA o Prometheus Adapter automáticamente y expone las métricas correctas como knobs del CRD.&lt;/p>
&lt;p>&lt;strong>Multi-tenancy.&lt;/strong> Múltiples modelos en el mismo cluster, con cuotas, prioridades y fairness. Un Deployment por modelo escalando independientemente está bien hasta el quinto modelo; a partir de ahí, la coordinación de GPUs entre tenants se vuelve operationally hostil.&lt;/p>
&lt;p>&lt;strong>Lifecycle del modelo.&lt;/strong> Pesos en PVC compartido, calentamiento del primer pod, rolling updates con &lt;code>maxUnavailable: 0&lt;/code>, drenaje de sesiones activas, observabilidad integrada. Cosas que en Deployment plano hay que reinventar en cada equipo.&lt;/p>
&lt;p>Si tu carga es &lt;strong>un modelo, un nodo, hasta tres réplicas&lt;/strong>, un Deployment plano basta y un operator es overkill. Si tu carga es &lt;strong>dos o más modelos, escalado serio, disaggregation o multi-tenancy&lt;/strong>, un operator deja de ser opcional.&lt;/p>
&lt;h2 id="kserve-el-antecesor-común">KServe: el antecesor común&lt;/h2>
&lt;p>Antes de los cuatro nuevos, hay que mencionar a &lt;a href="https://kserve.github.io/website/">KServe&lt;/a>, que es el operator madre del que descienden conceptualmente todos los demás. Nació como &lt;strong>KFServing&lt;/strong> dentro del proyecto Kubeflow en 2019, pasó a llamarse KServe al independizarse en 2021, y en 2025 fue &lt;a href="https://thenewstack.io/kserve-joins-cncf-to-standardize-ai-model-serving-on-kubernetes/">aceptado en la CNCF&lt;/a> como proyecto incubando hacia graduado.&lt;/p>
&lt;p>La contribución conceptual de KServe es &lt;strong>el CRD &lt;code>InferenceService&lt;/code>&lt;/strong>, que se ha convertido en el vocabulario común del campo: un objeto K8s declarativo que une un &lt;code>model&lt;/code> (origen + metadata) con un &lt;code>predictor&lt;/code> (runtime + recursos) y produce un servicio HTTP listo. Bajo el capó, el controller emite Deployments, Services, HorizontalPodAutoscalers, Knative Services si haces serverless, Istio VirtualServices si haces traffic splitting.&lt;/p>
&lt;p>KServe fue diseñado en una era pre-LLM: sus primeros casos de uso eran modelos scikit-learn, TensorFlow y PyTorch tradicionales servidos como REST APIs simples. Eso le da fortalezas (es maduro, lleva 6 años en producción en Bloomberg, JPMorgan y otros) y debilidades (no fue diseñado para gestionar tensor parallel multi-nodo, prefill–decode disaggregation, ni los patrones específicos de LLMs).&lt;/p>
&lt;p>La forma en la que el ecosistema ha reaccionado es elegante: &lt;strong>los nuevos operators de LLM heredan o se inspiran en &lt;code>InferenceService&lt;/code> pero extienden la API con primitivos específicos de LLM&lt;/strong>. OME es el ejemplo más claro: usa el nombre &lt;code>InferenceService&lt;/code> y la idea de &amp;ldquo;modelo + runtime → servicio&amp;rdquo;, pero añade &lt;code>BaseModel&lt;/code>, &lt;code>ServingRuntime&lt;/code> con flags LLM-aware, y modos de despliegue (PD-disag, multi-node) que KServe no contempla nativamente.&lt;/p>
&lt;h2 id="ome-open-model-engine">OME (Open Model Engine)&lt;/h2>
&lt;p>&lt;a href="https://github.com/ome-projects/ome">OME&lt;/a> lo publicó el equipo de LMSYS en julio 2025 (anunciado en &lt;a href="https://www.lmsys.org/blog/2025-07-08-ome/">su blog&lt;/a>). Es un operator que entiende SGLang en profundidad (es su runtime de primera clase) pero también soporta vLLM, TensorRT-LLM y Triton.&lt;/p>
&lt;h3 id="la-jerarquía-de-crds">La jerarquía de CRDs&lt;/h3>
&lt;p>OME modela el dominio con cuatro CRDs principales:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>BaseModel&lt;/code>&lt;/strong> y &lt;strong>&lt;code>ClusterBaseModel&lt;/code>&lt;/strong>: el modelo en sí. Define origen (Hugging Face, S3, URL), fingerprint, metadatos. La versión &lt;code>Cluster*&lt;/code> es global; la &lt;code>BaseModel&lt;/code> es namespaced. Permite que múltiples &lt;code>InferenceService&lt;/code> referencien el mismo modelo sin duplicar la descarga.&lt;/li>
&lt;li>&lt;strong>&lt;code>FineTunedWeight&lt;/code>&lt;/strong>: adapters LoRA o pesos finetuneados que se sirven encima de un &lt;code>BaseModel&lt;/code>. Crítico para multi-tenant donde cada cliente tiene su finetune.&lt;/li>
&lt;li>&lt;strong>&lt;code>ServingRuntime&lt;/code>&lt;/strong> y &lt;strong>&lt;code>ClusterServingRuntime&lt;/code>&lt;/strong>: el runtime (vLLM, SGLang, etc.) con su configuración. Declara qué args acepta, qué métricas exporta, qué modos de despliegue soporta.&lt;/li>
&lt;li>&lt;strong>&lt;code>InferenceService&lt;/code>&lt;/strong>: la pieza central, declarativa, que une &lt;code>BaseModel&lt;/code> + &lt;code>ServingRuntime&lt;/code> + infraestructura.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ome.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">InferenceService&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llama3-70b-prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">inference&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">model&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">meta-llama-3-70b-instruct &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># referencia a un BaseModel&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runtime&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">sglang-h100 &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># referencia a un ServingRuntime&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deploymentMode&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PrefillDecodeDisaggregated &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># standard | PD | MultiNode | Serverless&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">prefill&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minReplicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">maxReplicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">requests&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">decode&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">minReplicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">maxReplicas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">16&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">requests&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">nvidia.com/gpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">router&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cache-aware &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># SGLang router con cache awareness&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">autoscaling&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">metricSource&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">keda&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">metrics&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">prometheus&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">metricName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">vllm_requests_waiting&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">threshold&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;10&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Esto es lo que el operador toma como entrada. La salida son aproximadamente &lt;strong>8 recursos derivados&lt;/strong> que serían un horror declarar a mano: dos LeaderWorkerSets (uno por pool prefill/decode), dos Services, un Deployment para el router, ScaledObjects de KEDA por cada pool, HTTPRoute de Gateway API, y un PriorityClass que conecta con Kueue para gang scheduling.&lt;/p>
&lt;h3 id="los-cuatro-modos-de-despliegue">Los cuatro modos de despliegue&lt;/h3>
&lt;p>OME materializa la &lt;code>InferenceService&lt;/code> de forma distinta según &lt;code>deploymentMode&lt;/code>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Standard&lt;/strong>: un Deployment con N réplicas; clásico. Para modelos pequeños o single-GPU.&lt;/li>
&lt;li>&lt;strong>PrefillDecodeDisaggregated&lt;/strong>: dos pools coordinados; el router de SGLang los enruta.&lt;/li>
&lt;li>&lt;strong>MultiNode&lt;/strong>: tensor parallel sobre múltiples nodos vía LeaderWorkerSet, con NCCL/InfiniBand. Para modelos &amp;gt;70B donde un solo nodo no llega.&lt;/li>
&lt;li>&lt;strong>Serverless&lt;/strong>: Knative-style scale-to-zero. Para cargas esporádicas donde el coste de mantener GPUs encendidas no compensa. Trade-off: el primer request paga el coste de cold start del modelo (minutos).&lt;/li>
&lt;/ul>
&lt;h3 id="integración-con-el-ecosistema-k8s">Integración con el ecosistema K8s&lt;/h3>
&lt;p>OME no inventa primitivos donde ya existen. Se apoya en:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://kueue.sigs.k8s.io/">Kueue&lt;/a>&lt;/strong> para gang scheduling: todos los pods de un tensor parallel deben arrancar a la vez o ninguno; Kueue lo garantiza.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://lws.sigs.k8s.io/">LeaderWorkerSet (LWS)&lt;/a>&lt;/strong> para multi-nodo: workers se unen al cluster Ray del leader, ciclo de vida atómico (caída de uno reinicia el grupo).&lt;/li>
&lt;li>&lt;strong>KEDA&lt;/strong> para autoscaling por métricas Prometheus específicas de LLM (queue depth, GPU cache usage, TTFT p95).&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://gateway-api.sigs.k8s.io/">Gateway API&lt;/a>&lt;/strong> y su &lt;strong>Inference Extension&lt;/strong> para routing avanzado (model-aware, prefix-aware, weighted canary).&lt;/li>
&lt;/ul>
&lt;p>La consecuencia: OME se siente &amp;ldquo;idiomáticamente Kubernetes&amp;rdquo;. No introduce conceptos nuevos donde no hace falta; usa primitivos estándar y se concentra en lo específico del dominio LLM.&lt;/p>
&lt;h3 id="cuándo-elegirlo">Cuándo elegirlo&lt;/h3>
&lt;p>OME es la opción natural si &lt;strong>SGLang es tu runtime principal&lt;/strong> y/o si vienes del ecosistema KServe y quieres una evolución idiomática. Es maduro pero relativamente joven (un año en el momento de este artículo); espera bordes ásperos en features avanzadas.&lt;/p>
&lt;h2 id="vllm-production-stack">vLLM Production Stack&lt;/h2>
&lt;p>&lt;a href="https://github.com/vllm-project/production-stack">vLLM Production Stack&lt;/a> es el proyecto &lt;strong>oficial del propio vLLM&lt;/strong> para producción en Kubernetes. Su filosofía es opuesta a la de OME: en lugar de un operator con CRDs nuevos, es &lt;strong>un Helm chart curado&lt;/strong> que despliega un conjunto coherente de piezas.&lt;/p>
&lt;h3 id="las-tres-piezas">Las tres piezas&lt;/h3>
&lt;p>El stack tiene tres componentes:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Serving engines&lt;/strong>: pods de vLLM, configurados con los flags que llevamos viendo en toda la serie (&lt;code>--enable-prefix-caching&lt;/code>, &lt;code>--kv-cache-dtype fp8&lt;/code>, etc.). El Helm chart te deja declararlos como una lista; despliega los Deployments y Services subyacentes.&lt;/li>
&lt;li>&lt;strong>Request router&lt;/strong>: un proxy delante de los engines que decide a cuál enviar cada petición. Soporta varias políticas:
&lt;ul>
&lt;li>&lt;strong>Round-robin&lt;/strong>: trivial, para baseline.&lt;/li>
&lt;li>&lt;strong>Session-based&lt;/strong>: clava cada sesión a una réplica para mantener su KV cache.&lt;/li>
&lt;li>&lt;strong>Prefix-aware&lt;/strong>: detecta prefijos compartidos entre peticiones y las enruta a la réplica que ya los tenga cacheados.&lt;/li>
&lt;li>&lt;strong>KV-aware&lt;/strong>: ve el &lt;code>gpu_cache_usage_perc&lt;/code> de cada réplica y evita las saturadas.&lt;/li>
&lt;li>&lt;strong>Disaggregated-prefill&lt;/strong> con &lt;strong>LMCache&lt;/strong> nativo: separa prefill y decode con LMCache como transport del KV cache entre ambos.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Observability stack&lt;/strong>: Prometheus + Grafana con dashboards listos. Mide TTFT, TBT (Time-Between-Tokens), throughput, queue depth, GPU memory.&lt;/li>
&lt;/ol>
&lt;h3 id="lmcache-y-el-tiered-kv">LMCache y el tiered KV&lt;/h3>
&lt;p>Una de las piezas más interesantes que mete el stack es &lt;a href="https://github.com/LMCache/LMCache">&lt;strong>LMCache&lt;/strong>&lt;/a>, que añade un caché de KV con &lt;strong>múltiples tiers&lt;/strong>: GPU HBM como L1, CPU RAM como L2, disco local como L3, y opcionalmente storage remoto como L4. Cuando un bloque de KV cache no cabe en HBM, en lugar de evictarlo y recalcularlo, LMCache lo baja a un tier inferior. Para cargas con prefijos compartidos y multi-turn, el ahorro es brutal.&lt;/p>
&lt;p>LMCache se integra como sidecar de los engines y como parte del transport en disaggregated-prefill. El Production Stack lo trae habilitado por defecto en su Helm chart.&lt;/p>
&lt;h3 id="manifest-típico-valuesyaml">Manifest típico (values.yaml)&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">servingEngineSpec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">modelSpec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llama3-8b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repository&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">vllm/vllm-openai&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tag&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">v0.6.3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">modelURL&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">meta-llama/Meta-Llama-3-8B-Instruct&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">replicaCount&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">requestCPU&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">requestMemory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">16Gi&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">requestGPU&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">vllmConfig&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enablePrefixCaching&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">kvCacheDtype&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">fp8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">maxModelLen&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">32768&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enableChunkedPrefill&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">routerSpec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">routingLogic&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">prefix-aware &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># round-robin | session | prefix-aware | kv-aware&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">sessionKey&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">x-user-id &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># cuando routingLogic=session&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">cacheserverSpec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># LMCache para tiered KV&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">storageBackends&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">cpu&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">disk &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># offload a disco local&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">observabilitySpec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">prometheus&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">grafana&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">dashboards&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">vllm-engine-metrics&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">lmcache-metrics&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Esto es declarativo pero &lt;strong>no son CRDs&lt;/strong>: son valores de un Helm chart. La diferencia con OME no es semántica (ambos parten de declaración) sino operacional: con Helm, los cambios pasan por &lt;code>helm upgrade&lt;/code>; con CRDs, pasan por &lt;code>kubectl apply&lt;/code>. Para equipos que ya viven en GitOps con Argo CD o Flux, ambos enfoques se integran limpiamente, pero los flujos son distintos.&lt;/p>
&lt;h3 id="cuándo-elegirlo-1">Cuándo elegirlo&lt;/h3>
&lt;p>Si &lt;strong>tu único runtime es vLLM&lt;/strong> y quieres lo más cercano a &amp;ldquo;el camino feliz que recomienda el proyecto&amp;rdquo;, esto. Es la versión productivizada y mantenida por la misma gente que escribe el motor. Las desventajas: ata a vLLM (no es genérico) y no resuelve algunos casos avanzados como multi-tenancy con cuotas estrictas o gang scheduling, donde OME u operators full-fledged son superiores.&lt;/p>
&lt;h2 id="nvidia-dynamo">NVIDIA Dynamo&lt;/h2>
&lt;p>&lt;a href="https://developer.nvidia.com/dynamo">NVIDIA Dynamo&lt;/a> es el &lt;strong>sucesor oficial de Triton Inference Server&lt;/strong>, anunciado en GTC 2025 y fusionado con la marca como &lt;strong>Dynamo-Triton&lt;/strong> en marzo de ese año. Triton llevaba años siendo el motor de inferencia más usado en infraestructuras NVIDIA &amp;ldquo;serias&amp;rdquo;; Dynamo es lo que NVIDIA cree que la nueva generación necesita.&lt;/p>
&lt;h3 id="qué-es-exactamente">Qué es exactamente&lt;/h3>
&lt;p>Dynamo es &lt;strong>un framework de inferencia distribuida&lt;/strong>, no exactamente un operator de Kubernetes. Tiene runtime propio (puede correr engines), scheduler (Grove), routing inteligente, gestión de KV cache multi-tier y disaggregation. Soporta como engines a &lt;strong>SGLang, TensorRT-LLM y vLLM&lt;/strong>, pero los engines son ejecutados por Dynamo, no a la inversa: el modelo es &amp;ldquo;Dynamo gestiona, el engine ejecuta&amp;rdquo;.&lt;/p>
&lt;p>En Kubernetes, Dynamo se despliega vía operator + CRDs propios, normalizados con la integración K8s que NVIDIA formalizó a finales de 2025 (la cubre &lt;a href="https://www.infoq.com/news/2025/12/nvidia-dynamo-kubernetes/">esta nota de InfoQ&lt;/a>). Los CRDs son específicos del producto: definen un &lt;code>DynamoCluster&lt;/code>, una topología de prefill/decode workers, una política de routing.&lt;/p>
&lt;h3 id="las-cuatro-contribuciones">Las cuatro contribuciones&lt;/h3>
&lt;p>Dynamo se vende sobre cuatro pilares, con números reportados por NVIDIA:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Disaggregated serving&lt;/strong> built-in con scheduler propio.&lt;/li>
&lt;li>&lt;strong>Smart routing&lt;/strong> basado en estado de cache: si un worker ya tiene cacheada la mayoría de un prompt, la petición va ahí.&lt;/li>
&lt;li>&lt;strong>Multi-tier KV cache&lt;/strong>: análogo a LMCache, con HBM/RAM/SSD/NVMe.&lt;/li>
&lt;li>&lt;strong>Autoscaling&lt;/strong> integrado con el scheduler de Dynamo.&lt;/li>
&lt;/ol>
&lt;p>El número marketing: &lt;strong>hasta 30× más throughput&lt;/strong> que Triton legacy en el mismo hardware. Con todas las precauciones que merece un benchmark de vendor.&lt;/p>
&lt;h3 id="grove-scheduler-propio">Grove: scheduler propio&lt;/h3>
&lt;p>Una decisión polémica de Dynamo es no apoyarse al 100% en el scheduler de Kubernetes y, en su lugar, traer un scheduler propio llamado &lt;strong>Grove&lt;/strong> que entiende topologías de GPU. Grove decide qué worker corre en qué GPU física, qué interconexiones (NVLink/InfiniBand) son relevantes, y cómo distribuir tensor parallel entre nodos. Esto le da más control que kube-scheduler estándar.&lt;/p>
&lt;p>Operacionalmente: si tu cluster es &amp;ldquo;puro Kubernetes&amp;rdquo; con kube-scheduler y workloads heterogéneos (no solo LLMs), Grove añade un componente adicional a operar. Si tu cluster es &lt;strong>dedicado a inferencia LLM&lt;/strong> y ya hay equipo dedicado a operarlo, Grove te da más palancas.&lt;/p>
&lt;h3 id="cuándo-elegirlo-2">Cuándo elegirlo&lt;/h3>
&lt;p>Dynamo tiene sentido si:&lt;/p>
&lt;ul>
&lt;li>Tu infraestructura es &lt;strong>NVIDIA-heavy&lt;/strong> (Hopper, Blackwell, GB200) y quieres aprovechar lo más reciente de TensorRT-LLM con la integración de Triton-de-toda-la-vida pero modernizado.&lt;/li>
&lt;li>Ya eras usuario de Triton para inferencia legacy (visión, recomendación) y quieres mantener el ecosistema.&lt;/li>
&lt;li>Tienes equipo SRE dedicado a inferencia y la complejidad operacional adicional de Grove no es un problema.&lt;/li>
&lt;/ul>
&lt;p>Es la opción &lt;strong>vendor-specific&lt;/strong> del cuarteto. A cambio te da el soporte de NVIDIA y la integración de primera con su hardware. Si tu organización ya pelea con NVIDIA por GPUs, igual te llaman para ofrecer asistencia con Dynamo.&lt;/p>
&lt;h2 id="llm-d">llm-d&lt;/h2>
&lt;p>&lt;a href="https://github.com/llm-d/llm-d">llm-d&lt;/a> es el más joven y el más &amp;ldquo;político&amp;rdquo; de los cuatro. En marzo de 2026, en &lt;a href="https://siliconangle.com/2026/03/24/red-hat-bets-big-kubernetes-inference-llm-d-kubeconeu/">KubeCon Europe Amsterdam&lt;/a>, &lt;strong>Red Hat, Google Cloud, IBM Research, CoreWeave y NVIDIA&lt;/strong> anunciaron la donación conjunta del proyecto a la CNCF como Sandbox, con soporte de AMD, Cisco, Hugging Face, Intel, Lambda, Mistral AI, UC Berkeley y University of Chicago. Una coalición de vendor-neutralidad explícita.&lt;/p>
&lt;h3 id="filosofía">Filosofía&lt;/h3>
&lt;p>llm-d se posiciona como &lt;strong>el &amp;ldquo;Kubernetes blueprint&amp;rdquo; vendor-neutral para inferencia distribuida&lt;/strong>. No es un runtime; es un sistema que se monta encima de vLLM (motor por defecto) y orquesta el plano de control.&lt;/p>
&lt;p>Las primitivas que el proyecto pone sobre la mesa:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Routing inteligente&lt;/strong> con prefix-cache awareness y load-aware balancing.&lt;/li>
&lt;li>&lt;strong>Tiered KV cache&lt;/strong> con offload a CPU y disco para multi-turn.&lt;/li>
&lt;li>&lt;strong>Prefill/decode disaggregation&lt;/strong> sobre interconnects rápidos.&lt;/li>
&lt;li>&lt;strong>Wide expert-parallelism&lt;/strong> para servir Mixture-of-Experts (MoE) muy grandes —un patrón crítico que DeepSeek-V3 y Mixtral popularizaron— donde los expertos viven en distintas GPUs y hay que enrutar tokens al experto correcto.&lt;/li>
&lt;/ul>
&lt;h3 id="números">Números&lt;/h3>
&lt;p>El &lt;a href="https://github.com/llm-d/llm-d/releases">release v0.5&lt;/a> valida ~3.1k tok/s por GPU de decode B200, y hasta 50k output tok/s en una topología 16×16 B200 prefill/decode. El benchmark más interesante: &lt;strong>orden de magnitud de reducción de TTFT&lt;/strong> vs una baseline round-robin. Es decir, el routing inteligente vale lo que se dice.&lt;/p>
&lt;h3 id="cncf-y-futuro">CNCF y futuro&lt;/h3>
&lt;p>Donar a la CNCF como Sandbox significa &lt;strong>gobernanza neutral&lt;/strong>: ningún vendor manda. Para una organización que recela de quedar atado a un único proveedor, llm-d es probablemente la apuesta más segura a medio plazo. El precio: como cualquier proyecto Sandbox, todavía no es &amp;ldquo;boring&amp;rdquo; en el sentido en que vLLM lo es. Hay churn de API, features que se mueven, documentación que va por detrás del código.&lt;/p>
&lt;h3 id="cuándo-elegirlo-3">Cuándo elegirlo&lt;/h3>
&lt;p>llm-d tiene sentido si:&lt;/p>
&lt;ul>
&lt;li>Quieres &lt;strong>portabilidad multi-vendor&lt;/strong> sin ataduras a NVIDIA, Red Hat o Google.&lt;/li>
&lt;li>Tu carga incluye &lt;strong>MoE grandes&lt;/strong> (DeepSeek-V3, Mixtral 8x22B, Llama 4 Behemoth si confirma tamaño), donde wide expert parallelism es decisivo.&lt;/li>
&lt;li>Tu organización ya está cómoda con CNCF Sandbox (proyectos en evolución activa, no aún 1.0 estable).&lt;/li>
&lt;li>Quieres apostar por el proyecto que probablemente sea el estándar de facto en 2-3 años.&lt;/li>
&lt;/ul>
&lt;h2 id="el-antecesor-común-sigue-ahí-kserve">El antecesor común sigue ahí: KServe&lt;/h2>
&lt;p>Vale la pena reconectar antes de la comparativa: &lt;strong>KServe sigue vivo y muy usado&lt;/strong> en organizaciones que sirven tanto LLMs como modelos tradicionales (scikit-learn, XGBoost, PyTorch CV). Su &lt;code>InferenceService&lt;/code> es lo bastante genérico como para servir cualquier modelo, incluyendo vLLM o SGLang como &lt;code>ServingRuntime&lt;/code>. Lo que no hace bien es lo específico de LLM: disaggregation, tensor parallel multi-nodo, routing con awareness de KV cache. Si tu organización ya tiene KServe en producción para otros modelos, &lt;strong>añadir un operator específico de LLM al lado&lt;/strong> (OME, vLLM Stack o llm-d) es razonable. Pelearlo todo desde KServe puro no.&lt;/p>
&lt;h2 id="mapa-de-decisión">Mapa de decisión&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Dimensión&lt;/th>
&lt;th>OME&lt;/th>
&lt;th>vLLM Prod Stack&lt;/th>
&lt;th>NVIDIA Dynamo&lt;/th>
&lt;th>llm-d&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Filosofía&lt;/strong>&lt;/td>
&lt;td>Operator clásico K8s-idiomático&lt;/td>
&lt;td>Helm chart curado&lt;/td>
&lt;td>Framework con scheduler propio&lt;/td>
&lt;td>Blueprint CNCF vendor-neutral&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>CRDs propios&lt;/strong>&lt;/td>
&lt;td>Sí (BaseModel, ServingRuntime, InferenceService&amp;hellip;)&lt;/td>
&lt;td>No (Helm values)&lt;/td>
&lt;td>Sí (DynamoCluster)&lt;/td>
&lt;td>Sí (KServe-derived + extensions)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Runtime primario&lt;/strong>&lt;/td>
&lt;td>SGLang (primera clase), también vLLM/TRT-LLM/Triton&lt;/td>
&lt;td>vLLM exclusivamente&lt;/td>
&lt;td>TensorRT-LLM (primera clase), también SGLang/vLLM&lt;/td>
&lt;td>vLLM (primera clase)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>PD-disaggregation&lt;/strong>&lt;/td>
&lt;td>Sí, declarativo&lt;/td>
&lt;td>Sí, con LMCache&lt;/td>
&lt;td>Sí, scheduler propio&lt;/td>
&lt;td>Sí, nativo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-nodo TP&lt;/strong>&lt;/td>
&lt;td>Sí, via LWS&lt;/td>
&lt;td>Limitado&lt;/td>
&lt;td>Sí, via Grove&lt;/td>
&lt;td>Sí, via LWS y MoE EP&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-modelo en cluster&lt;/strong>&lt;/td>
&lt;td>Sí, multi-tenant maduro&lt;/td>
&lt;td>Sí (lista de modelos en values)&lt;/td>
&lt;td>Sí&lt;/td>
&lt;td>Sí&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-LoRA&lt;/strong>&lt;/td>
&lt;td>Sí, primera clase (FineTunedWeight CRD)&lt;/td>
&lt;td>Limitado&lt;/td>
&lt;td>Sí&lt;/td>
&lt;td>En roadmap&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Tiered KV cache&lt;/strong>&lt;/td>
&lt;td>Vía LMCache (integración externa)&lt;/td>
&lt;td>LMCache nativo&lt;/td>
&lt;td>Multi-tier propio&lt;/td>
&lt;td>Sí, nativo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Routing inteligente&lt;/strong>&lt;/td>
&lt;td>Cache-aware via SGLang router&lt;/td>
&lt;td>Prefix-aware / KV-aware / session-based&lt;/td>
&lt;td>Smart routing propio&lt;/td>
&lt;td>Prefix-cache + load-aware&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Scheduler GPU&lt;/strong>&lt;/td>
&lt;td>kube-scheduler + Kueue&lt;/td>
&lt;td>kube-scheduler&lt;/td>
&lt;td>Grove (propio)&lt;/td>
&lt;td>kube-scheduler + Kueue&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Hardware&lt;/strong>&lt;/td>
&lt;td>NVIDIA, AMD ROCm, Intel&lt;/td>
&lt;td>NVIDIA, AMD ROCm&lt;/td>
&lt;td>NVIDIA exclusivo (con énfasis)&lt;/td>
&lt;td>NVIDIA, AMD, Intel — neutral&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Madurez (mid-2026)&lt;/strong>&lt;/td>
&lt;td>Joven, en evolución&lt;/td>
&lt;td>Estable&lt;/td>
&lt;td>Estable, vendor-driven&lt;/td>
&lt;td>CNCF Sandbox, evolución rápida&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Gobernanza&lt;/strong>&lt;/td>
&lt;td>LMSYS (académico-industrial)&lt;/td>
&lt;td>vLLM project (académico)&lt;/td>
&lt;td>NVIDIA (vendor)&lt;/td>
&lt;td>CNCF (neutral)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Curva de aprendizaje&lt;/strong>&lt;/td>
&lt;td>Media (4 CRDs nuevos)&lt;/td>
&lt;td>Baja (Helm values familiar)&lt;/td>
&lt;td>Media-alta (Grove + CRDs propios)&lt;/td>
&lt;td>Media (similar a KServe extendido)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="cuándo-elegir-cada-uno">Cuándo elegir cada uno&lt;/h3>
&lt;p>&lt;strong>Elige OME&lt;/strong> si:&lt;/p>
&lt;ul>
&lt;li>SGLang es tu motor principal.&lt;/li>
&lt;li>Necesitas multi-LoRA serving en producción.&lt;/li>
&lt;li>Te encaja la abstracción jerárquica (BaseModel → ServingRuntime → InferenceService) y vienes de o convives con KServe.&lt;/li>
&lt;li>Tienes appetito por un proyecto joven y muy activo.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Elige vLLM Production Stack&lt;/strong> si:&lt;/p>
&lt;ul>
&lt;li>vLLM es tu único motor y quieres alinearte con lo que el proyecto recomienda.&lt;/li>
&lt;li>Tu equipo ya vive en Helm y no quiere aprender CRDs nuevos.&lt;/li>
&lt;li>LMCache + routing avanzado dentro de un solo Helm chart es exactamente lo que necesitas.&lt;/li>
&lt;li>Tu escala es media (decenas de réplicas), no extrema.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Elige NVIDIA Dynamo&lt;/strong> si:&lt;/p>
&lt;ul>
&lt;li>Tu infraestructura es NVIDIA-heavy y quieres el path más optimizado para Hopper/Blackwell.&lt;/li>
&lt;li>Ya operabas Triton para inferencia legacy y la transición es natural.&lt;/li>
&lt;li>Aceptas vendor lock-in a cambio de soporte directo NVIDIA.&lt;/li>
&lt;li>Tu organización tiene equipo SRE dedicado a inferencia.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Elige llm-d&lt;/strong> si:&lt;/p>
&lt;ul>
&lt;li>Quieres apostar por el estándar CNCF futuro, neutro entre vendors.&lt;/li>
&lt;li>Tu carga incluye MoE grandes con wide expert parallelism.&lt;/li>
&lt;li>Operas en multi-cloud o multi-hardware y la portabilidad es valiosa.&lt;/li>
&lt;li>Aceptas la inmadurez de un proyecto Sandbox a cambio de la apuesta a futuro.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Elige KServe puro&lt;/strong> si:&lt;/p>
&lt;ul>
&lt;li>Ya sirves modelos no-LLM y quieres unificar; los LLMs son una minoría de tu carga.&lt;/li>
&lt;li>Necesitas el caso de uso más conservador y maduro.&lt;/li>
&lt;li>Aceptas que features avanzadas de LLM (disaggregation, MoE EP, smart routing) te tocará añadirlas con piezas externas.&lt;/li>
&lt;/ul>
&lt;h3 id="escenarios-concretos">Escenarios concretos&lt;/h3>
&lt;p>&lt;strong>Escenario A — Startup pequeña, 1-2 modelos, 1-3 nodos GPU.&lt;/strong> Probablemente no necesitas operator. Deployment + Service + HPA con métricas de KEDA, como en el artículo de vLLM en Kubernetes. Cuando crezcas a 5+ modelos, evalúa.&lt;/p>
&lt;p>&lt;strong>Escenario B — Empresa media, 5-15 modelos, multi-tenant interno.&lt;/strong> vLLM Production Stack o OME son las opciones razonables. Production Stack si vLLM es todo lo que vas a usar; OME si quieres flexibilidad de runtime y CRDs idiomáticos.&lt;/p>
&lt;p>&lt;strong>Escenario C — Plataforma interna corporativa o servicio externo a clientes finales.&lt;/strong> llm-d o Dynamo. llm-d si valoras vendor-neutralidad; Dynamo si vives en infraestructura NVIDIA y quieres el camino que ellos recomiendan.&lt;/p>
&lt;p>&lt;strong>Escenario D — Cluster mixto LLM + modelos tradicionales.&lt;/strong> KServe como base, operator de LLM al lado (OME es lo más natural por su parentesco conceptual).&lt;/p>
&lt;h2 id="trampas-comunes">Trampas comunes&lt;/h2>
&lt;p>&lt;strong>&amp;ldquo;Voy a empezar con KServe puro porque es maduro&amp;rdquo;.&lt;/strong> Para LLMs medianos en adelante, KServe puro deja muchas optimizaciones sobre la mesa. Lo razonable es KServe como base si convives con otros modelos, pero operator LLM-específico al lado.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;Voy a montar todo a mano para entenderlo&amp;rdquo;.&lt;/strong> Razonable en PoC, suicida en producción. Hay 8 recursos derivados por modelo. Multiplica por 10 modelos. Estás escribiendo 80 YAMLs y manteniéndolos. Usa un operator.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;Voy a elegir el que más me gusta y luego pivoto si me equivoco&amp;rdquo;.&lt;/strong> Pivotar entre operators no es gratis: aunque la abstracción &lt;code>InferenceService&lt;/code> se está homogeneizando, los detalles (cómo se modela LoRA, cómo se configura routing, cómo se exponen métricas) varían. Migrar de OME a Dynamo es un proyecto de semanas, no de días.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;Voy a poner Dynamo porque es de NVIDIA y mejor&amp;rdquo;.&lt;/strong> Solo si tu organización ya está alineada con su filosofía operacional (scheduler propio, vendor lock-in aceptable). Para muchos casos, vLLM Production Stack o llm-d dan 95% del valor con menos fricción.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;Helm chart vs operator es una decisión técnica&amp;rdquo;.&lt;/strong> Es una decisión cultural/operacional. Si tu equipo entrega vía Argo CD con Helm values en Git, Production Stack encaja sin fricción. Si tu equipo vive en &lt;code>kubectl apply -f&lt;/code> directo y la idea de operators te resulta natural, OME o llm-d.&lt;/p>
&lt;h2 id="lo-que-no-hemos-cubierto">Lo que no hemos cubierto&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://github.com/kvcache-ai/Mooncake">Mooncake&lt;/a>&lt;/strong>: el sistema de cache de KV compartido entre instancias que Kimi/Moonshot lleva en producción a cientos de millones de queries. Es un primitivo (no un operator completo), pero se integra como tier de cache con varios de los anteriores.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://docs.ray.io/en/latest/serve/llm/serving-llms.html">Ray Serve LLM&lt;/a>&lt;/strong>: la oferta de Anyscale, en Kubernetes a través de KubeRay. Más vinculado al ecosistema Ray que a los CRDs nativos K8s. Útil si Ray ya es parte de tu infraestructura.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://fireworks.ai/">Fireworks AI&lt;/a>, &lt;a href="https://www.modular.com/">Modular MAX&lt;/a>&lt;/strong>: plataformas comerciales con primitivos similares, pero hospedadas. No son operators K8s; son competidores en otra capa.&lt;/li>
&lt;li>&lt;strong>Gateway API Inference Extension&lt;/strong>: la propuesta sigwg para extender Gateway API con primitivos LLM (model-aware routing, sticky sessions, fairness). En 2026 está en alpha; los operators de arriba ya empiezan a soportarla. Cuando madure, el routing dejará de ser problema de cada operator y será parte del estándar de Kubernetes.&lt;/li>
&lt;li>&lt;strong>Inference observability stack genérico&lt;/strong>: Prometheus + Grafana se está estandarizando en torno a las métricas &lt;code>vllm:*&lt;/code> que cubrimos en el artículo de vLLM. Hay esfuerzo de OpenTelemetry para LLMs (&lt;code>gen-ai&lt;/code> semantic conventions) que probablemente sea el siguiente eslabón.&lt;/li>
&lt;/ul>
&lt;h2 id="cerrando-la-serie">Cerrando la serie&lt;/h2>
&lt;p>Esta serie de cuatro artículos ha recorrido la inferencia LLM en producción de abajo arriba:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">KV cache: la memoria de trabajo que sostiene la inferencia LLM&lt;/a> — por qué cada token consume VRAM y cuánto.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes: la pieza de inferencia LLM que sí escala&lt;/a> — cómo se sirve un modelo en producción con un Deployment serio.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention por dentro y el estado del arte del KV cache en 2026&lt;/a> — qué pasa dentro del motor a nivel del bloque, y qué ha llegado después.&lt;/li>
&lt;li>&lt;strong>Este&lt;/strong> — cómo se orquestan muchos modelos en cluster.&lt;/li>
&lt;/ol>
&lt;p>Si has llegado aquí, tienes el vocabulario y el mapa para sentarte en una reunión donde cinco personas tiren siglas y reconocer cada una en su sitio. Y, lo más importante, para empezar a tomar decisiones razonadas sobre por dónde empezar.&lt;/p>
&lt;h2 id="referencias">Referencias&lt;/h2>
&lt;p>Operators y proyectos cubiertos:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/ome-projects/ome">OME — Open Model Engine (GitHub)&lt;/a> — operator de LMSYS para LLM serving con SGLang/vLLM/TRT-LLM/Triton.&lt;/li>
&lt;li>&lt;a href="https://www.lmsys.org/blog/2025-07-08-ome/">Introducing OME (LMSYS Blog, jul 2025)&lt;/a> — anuncio y arquitectura.&lt;/li>
&lt;li>&lt;a href="https://github.com/vllm-project/production-stack">vLLM Production Stack (GitHub)&lt;/a> — Helm chart oficial de vLLM para K8s.&lt;/li>
&lt;li>&lt;a href="https://docs.vllm.ai/projects/production-stack/en/latest/deployment/">vLLM Production Stack docs&lt;/a> — instalación y configuración.&lt;/li>
&lt;li>&lt;a href="https://github.com/LMCache/LMCache">LMCache (GitHub)&lt;/a> — caché de KV con tiers.&lt;/li>
&lt;li>&lt;a href="https://developer.nvidia.com/dynamo">NVIDIA Dynamo&lt;/a> — sucesor de Triton.&lt;/li>
&lt;li>&lt;a href="https://www.infoq.com/news/2025/12/nvidia-dynamo-kubernetes/">NVIDIA Dynamo Addresses Multi-Node LLM Inference Challenges (InfoQ, dic 2025)&lt;/a> — integración K8s.&lt;/li>
&lt;li>&lt;a href="https://github.com/llm-d/llm-d">llm-d (GitHub)&lt;/a> — proyecto CNCF Sandbox.&lt;/li>
&lt;li>&lt;a href="https://thenewstack.io/llm-d-cncf-kubernetes-inference/">IBM, Red Hat, and Google donated llm-d to CNCF (The New Stack)&lt;/a> — anuncio KubeCon EU 2026.&lt;/li>
&lt;li>&lt;a href="https://siliconangle.com/2026/03/24/red-hat-bets-big-kubernetes-inference-llm-d-kubeconeu/">Red Hat bets big on Kubernetes inference with llm-d (SiliconANGLE, mar 2026)&lt;/a> — cobertura del anuncio.&lt;/li>
&lt;/ul>
&lt;p>Antecesores y primitivos:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://kserve.github.io/website/">KServe (sitio)&lt;/a> y &lt;a href="https://thenewstack.io/kserve-joins-cncf-to-standardize-ai-model-serving-on-kubernetes/">KServe joins CNCF (The New Stack)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://kueue.sigs.k8s.io/">Kueue&lt;/a> — gang scheduling.&lt;/li>
&lt;li>&lt;a href="https://lws.sigs.k8s.io/">LeaderWorkerSet&lt;/a> — workloads coordinados como tensor parallel multi-pod.&lt;/li>
&lt;li>&lt;a href="https://keda.sh/">KEDA&lt;/a> — autoscaling por métricas externas.&lt;/li>
&lt;li>&lt;a href="https://gateway-api.sigs.k8s.io/">Gateway API&lt;/a> — sucesor del Ingress.&lt;/li>
&lt;/ul>
&lt;p>Análisis y perspectivas:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://jimmysong.io/blog/cloud-native-llm-inference-stack/">Building Efficient LLM Inference with the Cloud Native Quartet: KServe, vLLM, llm-d, and WG Serving (Jimmy Song)&lt;/a> — visión integradora.&lt;/li>
&lt;li>&lt;a href="https://dev.to/x4nent/complete-guide-to-llm-d-cncf-sandbox-kubernetes-native-distributed-llm-inference-1imj">Complete Guide to llm-d CNCF Sandbox (DEV Community)&lt;/a> — walkthrough operacional.&lt;/li>
&lt;li>Artículos previos en este blog: &lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">KV cache&lt;/a>, &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes&lt;/a>, &lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention deep dive&lt;/a>.&lt;/li>
&lt;/ul></description></item></channel></rss>