feat: migrate to llm-d-router-gateway chart v0.9.0 and enable KV cache-aware routing - #2144
feat: migrate to llm-d-router-gateway chart v0.9.0 and enable KV cache-aware routing#2144andyzhangx wants to merge 10 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Migrates KAITO’s InferencePool Helm chart integration from the Gateway API Inference Extension (GWIE) inferencepool chart to the llm-d-router-gateway chart, updating constants and Helm values to the new schema while keeping the existing InferencePool/EPP behavior aligned with llm-d-router.
Changes:
- Update chart source (OCI URL) and version constants, along with the EPP image constants, to llm-d-router-gateway v0.9.1.
- Update generated Helm values from the old
inferenceExtension/inferencePoolschema to the newrouter.epp/router.modelServersschema. - Update manifest unit tests to assert the new values structure.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| pkg/utils/consts/consts.go | Switch InferencePool chart URL/version and EPP image constants to llm-d-router-gateway + new image fields (registry/repository). |
| pkg/workspace/manifests/manifests.go | Update generated Flux OCIRepository comment + HelmRelease values to router.epp.image and router.modelServers shape. |
| pkg/controllers/multiroleinference/controller.go | Update MRI controller’s HelmRelease values to the new llm-d-router schema (router.epp, router.modelServers). |
| pkg/workspace/manifests/manifests_test.go | Adjust expected Helm values in tests to match the new router.* schema and targetPorts nesting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dcf1e78 to
6eee0c5
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (2)
pkg/controllers/multiroleinference/controller.go:666
- These EPP resource defaults are duplicated with the InferenceSet manifests path (pkg/workspace/manifests/manifests.go). Keeping two separate copies increases the chance they diverge over time and makes sizing changes harder to reason about. Consider consolidating them into a shared helper/const so both controllers use the same source of truth.
eppValues["resources"] = map[string]any{
"requests": map[string]string{
"cpu": "1",
"memory": "2Gi",
},
"limits": map[string]string{
"memory": "16Gi",
},
}
pkg/workspace/manifests/manifests.go:451
- The EPP resource requests/limits are hard-coded here and the same defaults are also duplicated in the MultiRoleInference controller. This duplication makes it easy for the two code paths to drift (InferenceSet vs MRI) and makes future tuning harder. Consider factoring these defaults into a shared helper/const (e.g., in pkg/utils/consts or a manifests helper) and referencing it from both places, or wiring them from API/config if they should be user-tunable.
"resources": map[string]any{
"requests": map[string]string{
"cpu": "1",
"memory": "2Gi",
},
"limits": map[string]string{
"memory": "16Gi",
},
},
…hart Migrate the InferencePool Helm chart dependency from the Gateway API Inference Extension inferencepool chart to the llm-d-router-gateway chart. The llm-d-router chart provides: - Same InferencePool deployment with advanced routing capabilities - Correct --flag=value rendering for boolean flags (fixes issue llm-d/llm-d-router#924) - Better alignment with the llm-d project which KAITO already uses for EPP Changes: - Chart URL: oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool → oci://ghcr.io/llm-d/charts/llm-d-router-gateway - Chart version: v1.3.1 → v0.9.1 - EPP image: mcr.microsoft.com/oss/v2/llm-d/llm-d-inference-scheduler:v0.8.0 → ghcr.io/llm-d/llm-d-router-endpoint-picker:v0.9.1 - Values schema: inferenceExtension.image.{hub,name} → router.epp.image.{registry,repository} inferencePool.{targetPorts,modelServers} → router.modelServers.{targetPorts,matchLabels} Signed-off-by: Andy Zhang <andyzhangx@live.com>
The llm-d-router EPP defaults to secure-serving=true (self-signed TLS). We need to explicitly set it to false so that the Istio Gateway can reach EPP over plaintext gRPC with a DestinationRule mode: DISABLE, which is simpler than managing TLS certificate trust. Signed-off-by: Andy Zhang <andyzhangx@live.com>
Remove the explicit secure-serving=false flag from EPP configuration. The EPP will use its default secure-serving=true (self-signed TLS), which works with the existing DestinationRule (mode: SIMPLE + insecureSkipVerify: true) documented in the KAITO quickstart. This provides transport encryption between the Istio Gateway and EPP. Signed-off-by: Andy Zhang <andyzhangx@live.com>
The chart defaults (cpu: 8, memory: 8Gi requests) are excessive for the EPP which is a lightweight routing/scheduling component. Reduce to cpu: 1, memory: 2Gi requests with memory limit 16Gi. Signed-off-by: Andy Zhang <andyzhangx@live.com>
…r-endpoint-picker:v0.9.0
mcr.microsoft.com/oss/v2/llm-d/llm-d-router-endpoint-picker only ships
v0.9.1{,-1,-2,-3}. Pinning to v0.9.0 leaves the EPP Deployment stuck in
ImagePullBackOff, which prevents the Flux HelmRelease for
llm-d-router-gateway from going Ready in e2e (preset_vllm_test.go:1138).
…nfig Add kv-cache-utilization-scorer plugin to the default P/D disaggregated serving EndpointPickerConfig. This scorer reads vLLM KV cache utilization metrics (enabled by default since PR kaito-project#1890) and scores endpoints by available KV cache capacity (score = 1 - kvCacheUsagePercent), spreading traffic away from pods with high KV cache pressure. Changes to defaultPDPluginsConfigTemplate: - Add kv-cache-utilization-scorer plugin declaration - Wire it into both prefill and decode scheduling profiles with weight 5 (half of load-aware-scorer's weight 10, so queue depth remains the primary signal while KV cache pressure provides a secondary signal) The scorer consumes metrics.KVCacheUsagePercentKey which vLLM publishes via /metrics. No additional sidecar or ZMQ subscription is required for the scorer itself — it reads from the same metrics endpoint the EPP already scrapes. Signed-off-by: Andy Zhang <andyzhangx@live.com> Signed-off-by: andyzhangx <xiazhang@microsoft.com>
cc682e4 to
a158514
Compare
Add validateMultiRoleInferenceEPPKVCacheScorer to the MRI P/D e2e test flow. This validates two things: 1. EPP plugins ConfigMap contains 'kv-cache-utilization-scorer' — proves the operator's defaultPDPluginsConfigTemplate is correctly rendered into the HelmRelease values and materialized as a ConfigMap by Flux. 2. EPP pod logs contain 'kv-cache-utilization-scorer' — proves the EPP binary actually loaded and registered the scorer plugin at startup, not just that the config was mounted. The validation runs after validateMultiRoleInferenceEPPReady (which already checks for disagg-profile-handler) and before the DestinationRule / chat-completions / KV-events / P/D-disaggregation checks, ensuring the scorer is wired up before traffic tests begin. Signed-off-by: Andy Zhang <andyzhangx@live.com> Signed-off-by: andyzhangx <xiazhang@microsoft.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (4)
pkg/controllers/multiroleinference/controller.go:522
- The comment says
kv-cache-utilization-scorerleverages vLLM KV cache events, but this scorer is intended to use vLLM metrics (KV cache utilization) as its signal. Keeping the comment accurate matters because KV events are a separate integration path (ZMQ/indexer) and can mislead future readers.
// kv-cache-utilization-scorer leverages vLLM KV cache events (enabled by default on vLLM pods)
// to score endpoints by available KV cache capacity, spreading traffic away from high-pressure pods.
pkg/controllers/multiroleinference/controller.go:664
- This change drops the explicit
secure-serving=falseflag for EPP. The repo docs indicate EPP defaults to--secure-serving=true(self-signed cert), which requires an Istio DestinationRule TLS bypass; removing the flag may unintentionally revert to secure serving and change Gateway→EPP connectivity expectations. If the goal is still to disable secure serving, set the flag here explicitly.
eppValues["flags"] = map[string]string{
"model-server-metrics-port": fmt.Sprintf("%d", consts.PortInferenceServer),
}
test/e2e/preset_vllm_test.go:1482
- The fallback path scans all ConfigMaps in the namespace and only checks whether any value contains the substring
kv-cache-utilization-scorer. This can produce false positives (unrelated ConfigMaps) and makes the test more expensive/flaky in busy namespaces. Restrict the fallback scan to ConfigMaps whose name is clearly associated with this InferencePool (e.g., prefixed bypoolName).
for _, cm := range cmList.Items {
for _, v := range cm.Data {
if strings.Contains(v, "kv-cache-utilization-scorer") {
GinkgoWriter.Printf("ConfigMap %s contains kv-cache-utilization-scorer\n", cm.Name)
found = true
pkg/workspace/manifests/manifests.go:447
- The EPP resource requests/limits are hard-coded here and the exact same values are also hard-coded in the MultiRoleInference controller. Duplicating these defaults in multiple places risks configuration drift when one side is updated. Consider centralizing these defaults (e.g., helper in a shared package or consts) so both code paths stay in sync.
"resources": map[string]any{
"requests": map[string]string{
"cpu": "1",
"memory": "2Gi",
},
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (3)
pkg/controllers/multiroleinference/controller.go:522
- The comment says
kv-cache-utilization-scorerleverages vLLM KV cache events, but this scorer is described elsewhere in this PR as using vLLM/metricsKV cache utilization. Updating the comment will avoid misleading readers about ZMQ/KV-events dependencies.
// kv-cache-utilization-scorer leverages vLLM KV cache events (enabled by default on vLLM pods)
// to score endpoints by available KV cache capacity, spreading traffic away from high-pressure pods.
test/e2e/preset_vllm_test.go:1460
Get()errors for candidate ConfigMaps are currently ignored unconditionally. This can mask real failures (e.g., RBAC/connection issues) and makes the test harder to debug. Only ignore NotFound and surface other errors.
cm, err := coreClient.CoreV1().ConfigMaps(mriObj.Namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
continue
}
test/e2e/preset_vllm_test.go:1479
- The fallback path scans every ConfigMap in the namespace, which can be slow and can match unrelated resources (especially if previous e2e runs left artifacts). Narrow the scan to ConfigMaps whose names include this MRI's pool name.
for _, cm := range cmList.Items {
for _, v := range cm.Data {
What type of PR is this?
/kind feature
What this PR does / why we need it
Migrates the InferencePool Helm chart dependency from the Gateway API Inference Extension (GWIE)
inferencepoolchart to thellm-d-router-gatewaychart at v0.9.0, and enables KV cache-aware routing in the default EPP EndpointPickerConfig.Why migrate?
--key"value"), which breaks Go pflag parsing (see llm-d/llm-d-router#924, kubernetes-sigs/gateway-api-inference-extension#2871). The llm-d-router chart already has this fix.KV cache-aware routing
With #1890 enabling KV cache events on vLLM pods by default, this PR adds the
kv-cache-utilization-scorerplugin to the default P/D EndpointPickerConfig. The scorer reads each endpoint's KV cache utilization from vLLM metrics (/metrics) and computesscore = 1 - kvCacheUsagePercent, spreading traffic away from pods with high KV cache pressure.load-aware-scorer's weight 10)load-aware-scorer) remains the primary routing signal; KV cache pressure acts as a secondary signalWhy
kv-cache-utilization-scorerand notprefix-cache-scorerwithprecise-prefix-cache-producer?The llm-d Router provides two levels of prefix-cache-aware routing:
approx-prefix-cache-producerprecise-prefix-cache-producer+token-producerThis PR stays with the approximate approach because:
No tokenizer sidecar — The
precise-prefix-cache-producerrequires atoken-producerplugin that sends prompts to vLLM's/v1/completions/renderendpoint (typically avllm launch rendersidecar in the EPP pod). KAITO does not currently deploy this sidecar, and adding one would cost ~500m CPU / 1Gi memory per MRI with no benefit for the approximate pipeline.KV-Cache Indexer not configured — While #1890 enables the ZMQ publisher on vLLM pods (port 5557), the EPP side's KV-Cache Indexer is not yet configured to subscribe to these events. The
precise-prefix-cache-producerdepends on this indexer to maintain the global block-to-pod mapping.kv-cache-utilization-scoreris complementary, not overlapping — It reads thekvCacheUsagePercentmetric from vLLM's/metricsendpoint (which EPP already scrapes forload-aware-scorer), requiring zero additional infrastructure. It provides a different signal: how full is each pod's KV cache (distribution/load-balancing), vs. how much of this specific request's prefix is cached on each pod (affinity). Both are valuable.The approximate producer is already in the config —
approx-prefix-cache-producer+prefix-based-pd-deciderhandles prefix-aware P/D routing without any external dependencies. Adding aprefix-cache-scoreron top would partially overlap with the decider's routing decisions in the P/D context.Next steps: Upgrade to precise prefix-cache routing (follow-up PRs)
Upgrading from the current approximate approach to precise prefix-cache routing will bring significant improvements, especially under high load and in P/D disaggregation scenarios:
What precise routing improves
BlockStored/BlockRemoved/AllBlocksClearedevents via ZMQ, EPP maintains a globally consistent indexBlockRemovedevents immediately → never routes to a pod that already evicted the prefixConcrete example
A user sends multiple prompts sharing a long system prompt (e.g., 4K tokens of instructions):
BlockRemovedfrom pod-3, knows pod-1 still has 90% of the blocks cached. Routes to pod-1. Result: cache hit, near-zero prefill latency.Implementation roadmap
vllm launch rendersidecar to EPP deployment, gated by feature flag or MRI spec field. Enablestoken-producerplugin for exact tokenization.precise-prefix-cache-producer+ updateprefix-cache-scorerwithprefixMatchInfoProducerName: precise-prefix-cache-producer. Achieves 100% accurate prefix-cache-aware routing.precise-prefix-cache-producer's speculative indexing to proactively update the index after routing decisions, closing the gap between routing and KV event arrival.Trade-offs
Changes
oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepooloci://ghcr.io/llm-d/charts/llm-d-router-gatewayv1.3.1v0.9.0mcr.microsoft.com/oss/v2/llm-d/llm-d-inference-scheduler:v0.8.0mcr.microsoft.com/oss/v2/llm-d/llm-d-router-endpoint-picker:v0.9.1inferenceExtension.image.{hub,name}router.epp.image.{registry,repository}inferencePool.{targetPorts,modelServers}router.modelServers.{targetPorts,matchLabels}load-aware-scoreronlyload-aware-scorer+kv-cache-utilization-scorerFiles changed
pkg/utils/consts/consts.gopkg/workspace/manifests/manifests.gopkg/controllers/multiroleinference/controller.gokv-cache-utilization-scorerto default EndpointPickerConfigpkg/workspace/manifests/manifests_test.gotest/e2e/preset_vllm_test.gokv-cache-utilization-scorerin EPP ConfigMap and pod logsWhich issue(s) this PR fixes
Resolves llm-d/llm-d-router#924 (for KAITO users)
Related PRs