Giant Swarm build of the KServe controllers. Produces:
- Container images (multi-arch: amd64 + arm64):
gsoci.azurecr.io/giantswarm/kserve-controller-- the classic KServe controller (cmd/manager)gsoci.azurecr.io/giantswarm/llmisvc-controller-- the LLMInferenceService controller (cmd/llmisvc)
- Helm charts (OCI,
gsoci.azurecr.io/charts/giantswarm/<chart>):kserve-resources,kserve-crd,kserve-runtime-configs,kserve-llmisvc-crd, andkserve-llmisvc-resources
Currently pinned to v0.21.0. The version is set in:
DockerfileandDockerfile.llmisvc(KSERVE_VERSIONbuild arg -- tracked by Renovate)helm/*/Chart.yamlandhelm/*/values.yaml(appVersion/kserve.version, vendored from upstream)
Upstream's v0.21.0 charts still carry v0.21.0-rc1 as their version and kserve.version; here
both say v0.21.0, the tag the images are built and mirrored at.
Renovate opens PRs when a new KServe release appears on GitHub (bumping the
KSERVE_VERSION build args). After merging:
- Re-vendor the Helm charts by hand from the upstream tag's
charts/tree (the charts are byte-copies of upstream plus a small set of deliberate Giant Swarm overlays -- Chart.yaml metadata, team label in_helpers.tpl, the gsoci image defaults in the resources charts'values.yaml, the image-less classic runtimes, and the generated schema files; the full list is under Giant Swarm overlays). - Verify the Go version in the Dockerfiles matches upstream's
go.mod. - Run
pre-commit run -auntil clean (regenerates schemas and chart READMEs) andmake check-image-registry(every image default is a gsoci reference). - Commit, push, and tag.
Dockerfile.llmisvc applies every patch under patches/llmisvc/ to the upstream
source before it builds the llmisvc controller. Each is one upstream-ready
commit (git format-patch output) that goes upstream and is dropped here once
a release carries it. A patch that no longer applies fails the image build.
| Patch | What it fixes |
|---|---|
0001-llmisvc-ready-needs-an-available-replica.patch |
With spec.rolloutStrategy.maxUnavailable at or above the replica count (maxSurge: 0, maxUnavailable: 1 on one replica), the Deployment is Available with no pod serving, and the LLMInferenceService turned Ready before its model served. A workload that desires replicas is now ready only with one available. |
Starting with v0.17.0, upstream split the single kserve chart; since v0.20.0
the LLMInferenceService (llmisvc) control plane ships as its own pair of charts:
| Chart | Purpose |
|---|---|
kserve-resources |
Classic controller deployment, RBAC, webhooks, inferenceservice-config |
kserve-crd |
CRDs for the classic control plane (InferenceService etc.) |
kserve-runtime-configs |
ClusterServingRuntimes and llmisvc config presets |
kserve-llmisvc-crd |
LLMInferenceService / LLMInferenceServiceConfig CRDs |
kserve-llmisvc-resources |
llmisvc controller deployment, RBAC, webhooks, GIE CRDs |
Consumers that previously used kserve need to reference kserve-resources instead.
The llmisvc control plane is independent of the classic controller. Install:
- Gateway API CRDs (standard channel) -- prerequisite, not shipped here:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml(KServe v0.21.0 builds against Gateway API v1.5.1) kserve-llmisvc-crd-- theLLMInferenceService/LLMInferenceServiceConfigCRDs.kserve-llmisvc-resources-- the llmisvc controller. By default this also installs the Gateway API Inference Extension CRDs (InferencePooletc.) embedded in the chart; setkserve.llmisvc.createGIECRDs: falseif those CRDs are managed elsewhere. Likekserve-resources, the chart also creates the shared resources (inferenceservice-configConfigMap, self-signed cert-manager Issuer, default ClusterStorageContainer); when installing it alongsidekserve-resourcesin the same namespace, setkserve.createSharedResources: falseon one of the two releases.kserve-runtime-configswithkserve.llmisvcConfigs.enabled: true-- the well-knownLLMInferenceServiceConfigpresets, rendered into the release namespace. Theirghcr.io/llm-d/images are rewritten at render time tokserve.llmisvcConfigs.imageRegistry, by default the digest-identical mirror set giantswarm/llm-d keeps ongsoci.azurecr.io/giantswarm/at the same tags;ghcr.io/llm-d/renders upstream's images.kserve.llmisvcConfigs.images.<preset>.<container>then replaces the image of one container of one preset (mainfor the runtime,llm-d-routing-sidecarfor the decode presets' sidecar) -- for GPU nodes that need another build of the same runtime, such as an arm64 vLLM on unified-memory Blackwell nodes; the chart README has the precedence and the entrypoint an override image must serve. The agent-platform chart consumes exactly this as itskserve-runtime-configscomponent (llmisvcConfigson,servingruntimeoff, no registry value).
The controller images default to gsoci.azurecr.io/giantswarm/kserve-controller
and gsoci.azurecr.io/giantswarm/llmisvc-controller at the pinned
kserve.version tag, which the release pipeline publishes alongside the
repo-versioned tags.
Every image the charts reference by default is a gsoci.azurecr.io/giantswarm/
reference; nothing is pulled from Docker Hub, quay.io or ghcr.io, so an
installation that pulls from one registry overrides nothing and a Kyverno
signature policy that trusts one Giant Swarm identity admits them all:
kserve-controllerandllmisvc-controllerare built here (multi-arch, signed by the release pipeline).- The KServe images the controllers inject or run --
agent,router,storage-initializer,art-explainer,kserve-localmodel-controller,kserve-localmodelnode-agent-- and the controller'skube-rbac-proxysidecar are mirrored and signed by giantswarm/retagger under their upstream tags. - The llm-d images the
LLMInferenceServiceConfigpresets pin are mirrored by giantswarm/llm-d (kserve.llmisvcConfigs.imageRegistry, see above). - The classic
ClusterServingRuntimes ofkserve-runtime-configsship no image: the Giant Swarm serving path is llm-d only. Withkserve.servingruntime.enabled: truea runtime renders only when itsimageis set; rendering fails when none is.
make check-image-registry (hack/check-image-registry.py, also the
check-image-registry CircleCI job every chart publish requires) renders every
chart with its defaults and its feature switches on and fails on any image
reference outside gsoci.azurecr.io -- in the manifests, in the JSON blocks of
the inferenceservice-config ConfigMap, and in values.yaml.
The charts are byte copies of upstream charts/<name> except for these
deliberate changes. Re-apply them after a re-vendor:
Chart.yamlof every chart: Giant Swarm annotations, icon,version: "[[ .Version ]]"._helpers.tpl: theapplication.giantswarm.io/teamlabel (the whole file inkserve-crdandkserve-llmisvc-crd).kserve-crd,kserve-llmisvc-crd:crd.keep(defaulttrue) addshelm.sh/resource-policy: keepto every CRD (theClusterStorageContainerCRD gets it injected into the document loaded fromfiles/).kserve-llmisvc-crd: the conversion-webhook service namespace and thecert-manager.io/inject-ca-fromannotation render.Release.Namespaceinstead of the hardcodedkserve; inkserve-crdtheInferenceServiceCRD'scert-manager.io/inject-ca-fromannotation does the same.kserve-runtime-configs: the llmisvc presets'ghcr.io/llm-d/images are rewritten tokserve.llmisvcConfigs.imageRegistry(defaultgsoci.azurecr.io/giantswarm/), a container named inkserve.llmisvcConfigs.images.<preset>.<container>gets that image, and thedocker.io/vllm/image of the tokenizer preset is rewritten to its gsoci copy (digest kept),kserve.llmisvcConfigs.rolloutStrategysets the single-node workload presets'rolloutStrategy, the tracing preset takeskserve.llmisvcConfigs.tracing, and their hardcodednamespace: kservefollows.Release.Namespace(kserve-common.replaceNamespace); the file underfiles/stays upstream's verbatim, a preset without an override renders byte for byte. The helm-unittest suites underhelm/*/tests/run withmake helm-test(thechart-testCircleCI job).kserve-resources,kserve-llmisvc-resources: every image default invalues.yamlis agsoci.azurecr.io/giantswarm/reference (see Images), the Renovate-pinnedrbacProxyImageincluded.kserve-runtime-configs: the classic runtimes'imagevalues are empty andtemplates/runtimes/resources.yamlrenders only runtimes that have one (failing when none has).- Giant Swarm-only files:
.schema.yaml,values.schema.json,zz_generated.app-platform.values.yaml,.kube-linter.yaml.
make build