CRDs

InferenceWorkerSet

An InferenceWorkerSet represents a set of local inference workers (e.g. vLLM pods) that serve one model. An InferenceWorkerSet wraps a standard Kubernetes Service with inference-specific routing information including model and KV cache information.

  • Version: kinference.buoyant.io/v1alpha1
  • Short name: iws

InferenceWorkerSets are typically used as part of an InferencePool.

InferenceWorkerSets can also specify aliases for model names.

Example #

This InferenceWorkerSet wraps a Service named qwen-3-6-35b-a3b-vllm; specifies that it has a KV cache block size 16 and emits KV cache events on the port named “kv-pub”, and adds “qwen3.6” as an alias to the “Qwen/Qwen3.6-35B-A3B” model served.

apiVersion: kinference.buoyant.io/v1alpha1
kind: InferenceWorkerSet
metadata:
  name: qwen-3-6-35b-a3b
  namespace: default
spec:
  profile: default
  kvBlockSize: 16
  serviceRef:
    name: qwen-3-6-35b-a3b-vllm
    port: http
  kvEvents:
    port: kv-pub
  models:
    - name: Qwen/Qwen3.6-35B-A3B
      aliases: [qwen3.6]

Specification #

FieldTypeRequiredDefault
profilestringyes—
kvBlockSizeintegeryes—
serviceRefobjectyes—
serviceRef.namestringyes—
serviceRef.portstring or integeryes—
kvEvents.portstring or integeryes, if kvEvents is set—
kvEvents.replayPortstring or integernoport named kv-replay, else replay disabled
metricsPortstring or integernoport named metrics, else serviceRef.port
modelDiscovery.modeEndpoint | StaticnoEndpoint
modelDiscovery.intervaldurationno30s
modelslistno—
models[].namestringyes—
models[].aliaseslistno—

profile field #

Which routing profile to use. Determines the latency-model parameters and tokenization mode.

kvBlockSize field #

Tokens per block in the KV-cache events these engines publish, e.g. 16, 256.

Note: This value is Not necessarily the same as the --block-size parameter passed in to vLLM, or supplied in cache_config_info metrics. For example, Gemma 4 reports block_size=64 in cache_config_info but publishes 256-token blocks.

kvEvents field #

The socket on which the workers publish KV cache events (BlockStored / BlockRemoved and equivalents).

If unset, KV cache information will not be used. This may result in degraded routing quality.

models field #

Model information is auto-discovered from /v1/models. This optional field is used to provide model aliases. For example:

models:
  - name: Qwen/Qwen2.5-32B-Instruct-AWQ # what the engine reports
    aliases: [qwen-2.5, qwen-simple] # and two shorter ways to ask for it

In this example, users may call the Qwen2.5-32B-Instruct-AWQ model by passing the full model name or either of the two aliases (“qwen-2.5” or “qwen-simple”).

Status fields #

FieldMeaning
models[].upstreamNameModel name from the worker itself
models[].aliasesAny aliases provided
models[].readyEndpointsReady endpoints serving this model
models[].contextWindowEffective window (vLLM max_model_len) across ready endpoints, as {min, max}
endpoints.readyCandidate endpoints
endpoints.terminatingDraining: still serving in-flight requests, no longer candidates
kvEvents.configuredFalse when spec.kvEvents is unset
kvEvents.subscribedEndpointsEndpoints the router is currently receiving events from
referencedByPools listing this set in spec.destinations, sorted
conditionsAccepted, Ready, Referenced
ConditionQuestion
AcceptedIs the object valid and materialized as a routable pool?
ReadyDoes it have ready endpoints?
ReferencedDoes any InferencePool route to it — i.e. does pool-scoped policy apply?

Printer columns and state #

Example:

$ kubectl get iws
NAME               READY   STATE                            AGE
qwen-3-6-35b-a3b   3       Accepted                         7d
gemma-4-12b        0       Accepted,NotReady                7d
orphan             0       Accepted,NotReady,Unreferenced   19s
no-such-profile    0       UnknownProfile                   2m

READY is the number of ready endpoints; STATE is a comma-separated list of states:

StatesPositionMeans
AcceptedprimaryValid and materialized as a routable pool
NotReadyqualifierNo ready endpoints
UnreferencedqualifierNo pool references this InferenceWorkerSet
<a rejection reason>primaryRefused

Possible rejection reasons include:

Reasonspec is
MissingProfilemissing profile
UnknownProfilenaming a profile the router does not define
MissingKvBlockSize / InvalidKvBlockSizemissing kvBlockSize, or giving one that is zero
MissingServiceRefmissing serviceRef.name, so there is nothing to watch
KvEventsMissingPortdeclaring kvEvents with no port
ModelMissingNamecarrying a models row with no name

Diagnoses #

SymptomCause
Accepted=False, UnknownProfilespec.profile names an unknown profile not in Kinference’s configuration
Accepted=False, KvEventsMissingPortspec.kvEvents is present with no port. Omit the block, or name the port
Accepted=False, ModelMissingNameA spec.models row has no name.
Accepted=False, MissingProfile / MissingServiceRefThe field is absent. Only reachable by an object that bypassed admission
STATE blank in kubectl get iwsNo status written at all–the InferenceWorkerSet is not in a namespace that Kinference is watching
STATE has UnreferencedNo pool references this InferenceWorkerSet. (Not an error.)
Ready=False, NoReadyEndpointsThe Service has no ready endpoints
status.endpoints.ready: 0serviceRef.name matches no Service, or it has none ready. Check kubectl get endpointslices -l kubernetes.io/service-name=<name>
Events arrive, index.blocks stays 0kvBlockSize mismatch, stage 1. Grep the logs for the published size
Set drains after a few BlockStoredkvBlockSize mismatch, stage 2
Endpoints added but unresponsivePod IPs unreachable from the router pod. Check NetworkPolicies
A written alias never resolvesCheck it against status.models[].aliases, and confirm the request named a pool