LLM inference on Kubernetes and observability Coroot ran five Kubernetes LLM-serving frameworks — KServe, NVIDIA Dynamo, Ray Serve, Kthena and llm-d — on a single cluster and extended its observability tool to cover them, after finding that each framework maps a model deployment onto Kubernetes objects differently and that standard latency SLOs flag every model server as violating from startup because requests can legitimately take four seconds. The frameworks each invent their own custom resource: KServe's InferenceService becomes Deployments or Knative Services, NVIDIA Dynamo expands a DynamoGraphDeployment into per-component Deployments with a TCP request plane and NIXL GPU-to-GPU KV cache transfer, Ray Serve manages pods directly with blue-green upgrades, and llm-d ships only recipes for vLLM plus a Gateway API Inference Extension router producing an InferencePool. Coroot said its first fix went wrong and describes what the tool now does to attribute the generated Deployments and pods to their originating model deployments. ← All posts https://coroot.com/blog Engineering LLM inference on Kubernetes and observability Running an LLM on Kubernetes is rarely just a Deployment with vLLM in it anymore. A whole layer of frameworks and operators has grown up for it: KServe, NVIDIA Dynamo, Ray Serve, Kthena, llm-d. Each one adds its own custom resource that describes a model deployment, with routing, autoscaling and the split of a model across pods built in, and each one turns that resource into ordinary Kubernetes objects in its own way. None of those resources is an object a monitoring tool knows about. What it sees is what the frameworks create: Deployments named llama-disagg-prefill-6f8d9c and friends, a new set after every rollout. And every model server sits in SLO violation from the moment it starts, because a latency objective made for web services doesn't survive a request that takes four seconds on purpose. So we ran all of them on one cluster and fixed both in Coroot. Here is what the frameworks actually build, where our first fix went wrong, and what Coroot does now. The frameworks the-frameworks KServe is the old guard. It started in Kubeflow, and one InferenceService can run any model on any runtime, with canary rollouts and scale-to-zero through Knative. Red Hat ships it in OpenShift AI. NVIDIA's NIM Operator can hand its prepackaged NIM containers to KServe to run. NVIDIA Dynamo is for one big model spread across many GPUs and nodes. You pick the engine, vLLM, SGLang or TensorRT-LLM. Dynamo adds everything around it: a frontend that sends each request to the worker that already has its KV cache, separate prefill and decode pools, and a planner that resizes them. Ray Serve is the serving part of Ray. A model is a Python class that runs as Ray actors, and classes can be chained into a pipeline. KubeRay runs the Ray cluster on Kubernetes. It is the natural pick when serving is more than one engine call and the glue is Python. Kthena is the newest one, from the Volcano community, and built only for LLMs. It has prefill and decode roles, multi-node instances that are scheduled as a unit, and a router that works with models and versions instead of Services. llm-d comes from Red Hat, Google and IBM, and it is the only one without a resource of its own. It is a set of recipes for vLLM plus a router from the Gateway API Inference Extension. The router picks a server by prefix-cache hits and load, and can split a request into a prefill pass and a decode pass on different pods. What lands on the cluster is stock Kubernetes: an InferencePool and either Deployments or a DisaggregatedSet from the LeaderWorkerSet project. Five ways to turn a model into pods five-ways-to-turn-a-model-into-pods A model deployment is more than one container: the engine, maybe a preprocessing step, a router, and in disaggregated setups several kinds of workers that only make sense together. Kubernetes has no object for that, so each framework invents one and maps it onto the objects Kubernetes does have. They map it differently: - KServe turns each component of an InferenceService into a Deployment, or in serverless mode into a Knative Service that gets a fresh Deployment per revision,