Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion helm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.12
version: 0.1.13

maintainers:
- name: apostac
Expand Down
30 changes: 30 additions & 0 deletions helm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ This table documents all available configuration values for the Production Stack

### Table of Contents

- [Global Configuration](#global-configuration)
- [Serving Engine Configuration](#serving-engine-configuration)
- [Router Configuration](#router-configuration)
- [Cache Server Configuration](#cache-server-configuration)
Expand All @@ -43,6 +44,35 @@ This table documents all available configuration values for the Production Stack
- [Shared Storage Configuration](#shared-storage-configuration)
- [Other Configuration](#other-configuration)

### Global Configuration

Set `global.imageRegistry` to pull images from a shared registry:

```yaml
global:
imageRegistry: "registry.example.com:5000"
```

The override replaces an explicit registry (such as `ghcr.io`) or prefixes an
unqualified image. Repository paths, tags and digests are preserved. For example,
`lmcache/lmstack-router:latest` becomes
`registry.example.com:5000/lmcache/lmstack-router:latest`.
Mirror images at their corresponding repository paths before enabling this option.

This applies to the router, serving engines, cache server, LoRA controller and
sidecar, Ray head and worker containers, and their init containers. An empty
value (the default) leaves configured images unchanged. Continue to configure
`imagePullSecrets` per component when authentication is required.

Helm also passes global values to dependencies. The bundled
`kube-prometheus-stack` supports this setting. The bundled `prometheus-adapter`
requires its own `prometheus-adapter.image.repository` override. Images in
user-supplied `extraObjects` are not rewritten.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `global.imageRegistry` | string | `""` | Registry override for images managed by this chart |

### Serving Engine Configuration

| Field | Type | Default | Description |
Expand Down
20 changes: 20 additions & 0 deletions helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
{{/*
Override an image's registry while preserving its repository path, tag and digest.
Usage: include "chart.image" (dict "image" $image "global" $.Values.global)
*/}}
{{- define "chart.image" -}}
{{- $global := .global | default dict -}}
{{- $registry := $global.imageRegistry | default "" | trimSuffix "/" -}}
{{- $image := .image | default "" -}}
{{- if and $registry $image -}}
{{- $parts := splitList "/" $image -}}
{{- $first := first $parts -}}
{{- if and (gt (len $parts) 1) (or (contains "." $first) (contains ":" $first) (eq $first "localhost")) -}}
{{- $image = join "/" (rest $parts) -}}
{{- end -}}
{{- printf "%s/%s" $registry $image -}}
{{- else -}}
{{- $image -}}
{{- end -}}
{{- end -}}

{{/*
Define ports for the pods
*/}}
Expand Down
2 changes: 1 addition & 1 deletion helm/templates/deployment-cache-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ spec:
{{- end }}
containers:
- name: "lmcache-server"
image: "{{ .Values.cacheserverSpec.image.repository }}:{{ .Values.cacheserverSpec.image.tag }}"
image: {{ include "chart.image" (dict "image" (printf "%s:%s" .Values.cacheserverSpec.image.repository .Values.cacheserverSpec.image.tag) "global" $.Values.global) | quote }}
command:
- "/opt/venv/bin/lmcache_server"
- "0.0.0.0"
Expand Down
4 changes: 2 additions & 2 deletions helm/templates/deployment-lora-controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ spec:
{{- if $.Values.sharedPvcStorage.enabled }}
initContainers:
- name: fix-perms
image: "{{ $.Values.sharedPvcStorage.image.repository }}:{{ $.Values.sharedPvcStorage.image.tag }}"
image: {{ include "chart.image" (dict "image" (printf "%s:%s" $.Values.sharedPvcStorage.image.repository $.Values.sharedPvcStorage.image.tag) "global" $.Values.global) | quote }}
command: ["sh", "-c", "chown -R 65532:65532 /data/shared-pvc-storage"]
securityContext:
runAsUser: 0
Expand All @@ -56,7 +56,7 @@ spec:
{{- end }}
containers:
- name: manager
image: "{{ .Values.loraController.image.repository }}:{{ .Values.loraController.image.tag }}"
image: {{ include "chart.image" (dict "image" (printf "%s:%s" .Values.loraController.image.repository .Values.loraController.image.tag) "global" $.Values.global) | quote }}
imagePullPolicy: {{ .Values.loraController.image.pullPolicy }}
args:
- --leader-elect
Expand Down
2 changes: 1 addition & 1 deletion helm/templates/deployment-router.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ spec:
{{- end }}
containers:
- name: router-container
image: "{{ .Values.routerSpec.repository }}:{{ .Values.routerSpec.tag }}"
image: {{ include "chart.image" (dict "image" (printf "%s:%s" .Values.routerSpec.repository .Values.routerSpec.tag) "global" $.Values.global) | quote }}
imagePullPolicy: "{{ .Values.routerSpec.imagePullPolicy }}"
{{- if .Values.routerSpec.containerSecurityContext }}
securityContext:
Expand Down
6 changes: 3 additions & 3 deletions helm/templates/deployment-vllm-multi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ spec:
{{- $container := $modelSpec.initContainer }}
initContainers:
- name: {{ $container.name }}
image: {{ $container.image }}
image: {{ include "chart.image" (dict "image" $container.image "global" $.Values.global) | quote }}
{{- if $container.command }}
command: {{ toYaml $container.command | nindent 12 }}
{{- end }}
Expand Down Expand Up @@ -119,7 +119,7 @@ spec:
subdomain: "{{ $.Release.Name }}-{{ $modelSpec.name }}-engine-service"
containers:
- name: "vllm"
image: "{{ required "Required value 'modelSpec.repository' must be defined !" $modelSpec.repository }}:{{ required "Required value 'modelSpec.tag' must be defined !" $modelSpec.tag }}"
image: {{ include "chart.image" (dict "image" (printf "%s:%s" (required "Required value 'modelSpec.repository' must be defined !" $modelSpec.repository) (required "Required value 'modelSpec.tag' must be defined !" $modelSpec.tag)) "global" $.Values.global) | quote }}
{{- with .Values.servingEngineSpec.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
Expand Down Expand Up @@ -446,7 +446,7 @@ spec:
{{- end }}
{{- if and $modelSpec.enableLoRA (hasKey $modelSpec "pvcStorage") }}
- name: sidecar
image: {{ .Values.servingEngineSpec.sidecar.image }}
image: {{ include "chart.image" (dict "image" .Values.servingEngineSpec.sidecar.image "global" $.Values.global) | quote }}
imagePullPolicy: {{ .Values.servingEngineSpec.sidecar.imagePullPolicy }}
env:
- name: PORT
Expand Down
8 changes: 4 additions & 4 deletions helm/templates/ray-cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ spec:
{{- $container := $modelSpec.raySpec.headNode.initContainer }}
initContainers:
- name: {{ $container.name }}
image: {{ $container.image }}
image: {{ include "chart.image" (dict "image" $container.image "global" $.Values.global) | quote }}
{{- if $container.command }}
command: {{ toYaml $container.command | nindent 14 }}
{{- end }}
Expand Down Expand Up @@ -88,7 +88,7 @@ spec:
{{- end }}
containers:
- name: vllm-ray-head
image: "{{ required "Required value 'modelSpec.repository' must be defined !" $modelSpec.repository }}:{{ required "Required value 'modelSpec.tag' must be defined !" $modelSpec.tag }}"
image: {{ include "chart.image" (dict "image" (printf "%s:%s" (required "Required value 'modelSpec.repository' must be defined !" $modelSpec.repository) (required "Required value 'modelSpec.tag' must be defined !" $modelSpec.tag)) "global" $.Values.global) | quote }}
imagePullPolicy: "{{ .Values.servingEngineSpec.imagePullPolicy | default "Always" }}"
command:
- >-
Expand Down Expand Up @@ -355,7 +355,7 @@ spec:
{{- $container := $modelSpec.initContainer }}
initContainers:
- name: {{ $container.name }}
image: {{ $container.image }}
image: {{ include "chart.image" (dict "image" $container.image "global" $.Values.global) | quote }}
{{- if $container.command }}
command: {{ toYaml $container.command | nindent 16 }}
{{- end }}
Expand Down Expand Up @@ -398,7 +398,7 @@ spec:
{{- end }}
containers:
- name: vllm-ray-worker
image: "{{ required "Required value 'modelSpec.repository' must be defined !" $modelSpec.repository }}:{{ required "Required value 'modelSpec.tag' must be defined !" $modelSpec.tag }}"
image: {{ include "chart.image" (dict "image" (printf "%s:%s" (required "Required value 'modelSpec.repository' must be defined !" $modelSpec.repository) (required "Required value 'modelSpec.tag' must be defined !" $modelSpec.tag)) "global" $.Values.global) | quote }}
imagePullPolicy: "{{ .Values.servingEngineSpec.imagePullPolicy | default "Always" }}"
env:
- name: VLLM_HOST_IP
Expand Down
150 changes: 150 additions & 0 deletions helm/tests/imageRegistry_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
suite: global image registry
templates:
- deployment-router.yaml
- deployment-cache-server.yaml
- deployment-lora-controller.yaml
- deployment-vllm-multi.yaml
- ray-cluster.yaml
values:
- values/image-registry.yaml
tests:
- it: preserves configured images when the override is empty
set:
global.imageRegistry: ""
asserts:
- template: deployment-router.yaml
equal:
path: spec.template.spec.containers[0].image
value: "ghcr.io/lmcache/lmstack-router:v1"
- template: deployment-cache-server.yaml
equal:
path: spec.template.spec.containers[0].image
value: "registry.example.org:5000/lmcache/cache:v2"
- template: deployment-lora-controller.yaml
equal:
path: spec.template.spec.containers[0].image
value: "lmcache/lmstack-lora-controller:latest"
- template: deployment-lora-controller.yaml
equal:
path: spec.template.spec.initContainers[0].image
value: "busybox:1.37"
- template: deployment-vllm-multi.yaml
equal:
path: spec.template.spec.containers[0].image
value: "vllm/vllm-openai:v3"
- template: deployment-vllm-multi.yaml
equal:
path: spec.template.spec.containers[1].image
value: "lmcache/lmstack-sidecar:latest"
- template: deployment-vllm-multi.yaml
equal:
path: spec.template.spec.initContainers[0].image
value: "busybox:1.36"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.headGroupSpec.template.spec.containers[0].image
value: "localhost:5000/team/ray-vllm:v4"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.workerGroupSpecs[0].template.spec.containers[0].image
value: "localhost:5000/team/ray-vllm:v4"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.headGroupSpec.template.spec.initContainers[0].image
value: "localhost/tools/init@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.workerGroupSpecs[0].template.spec.initContainers[0].image
value: "docker.io/library/busybox:1.36"
- it: overrides images for all chart-managed containers
set:
global.imageRegistry: "mirror.example.com:5000"
asserts:
- template: deployment-router.yaml
equal:
path: spec.template.spec.containers[0].image
value: "mirror.example.com:5000/lmcache/lmstack-router:v1"
- template: deployment-cache-server.yaml
equal:
path: spec.template.spec.containers[0].image
value: "mirror.example.com:5000/lmcache/cache:v2"
- template: deployment-lora-controller.yaml
equal:
path: spec.template.spec.containers[0].image
value: "mirror.example.com:5000/lmcache/lmstack-lora-controller:latest"
- template: deployment-lora-controller.yaml
equal:
path: spec.template.spec.initContainers[0].image
value: "mirror.example.com:5000/busybox:1.37"
- template: deployment-vllm-multi.yaml
equal:
path: spec.template.spec.containers[0].image
value: "mirror.example.com:5000/vllm/vllm-openai:v3"
- template: deployment-vllm-multi.yaml
equal:
path: spec.template.spec.containers[1].image
value: "mirror.example.com:5000/lmcache/lmstack-sidecar:latest"
- template: deployment-vllm-multi.yaml
equal:
path: spec.template.spec.initContainers[0].image
value: "mirror.example.com:5000/busybox:1.36"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.headGroupSpec.template.spec.containers[0].image
value: "mirror.example.com:5000/team/ray-vllm:v4"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.workerGroupSpecs[0].template.spec.containers[0].image
value: "mirror.example.com:5000/team/ray-vllm:v4"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.headGroupSpec.template.spec.initContainers[0].image
value: "mirror.example.com:5000/tools/init@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- template: ray-cluster.yaml
documentIndex: 0
equal:
path: spec.workerGroupSpecs[0].template.spec.initContainers[0].image
value: "mirror.example.com:5000/library/busybox:1.36"
- it: keeps nested namespaces
set:
global.imageRegistry: "mirror.example.com"
routerSpec.repository: "team/subteam/router"
asserts:
- template: deployment-router.yaml
equal:
path: spec.template.spec.containers[0].image
value: "mirror.example.com/team/subteam/router:v1"
- it: does not duplicate an already matching registry
set:
global.imageRegistry: "mirror.example.com"
routerSpec.repository: "mirror.example.com/team/router"
asserts:
- template: deployment-router.yaml
equal:
path: spec.template.spec.containers[0].image
value: "mirror.example.com/team/router:v1"
- it: allows a registry path prefix and trailing slash
set:
global.imageRegistry: "mirror.example.com/cache/"
routerSpec.repository: "ghcr.io/team/router"
asserts:
- template: deployment-router.yaml
equal:
path: spec.template.spec.containers[0].image
value: "mirror.example.com/cache/team/router:v1"
- it: does not manufacture a registry-only reference for an empty image
set:
global.imageRegistry: "mirror.example.com"
servingEngineSpec.sidecar.image: ""
asserts:
- template: deployment-vllm-multi.yaml
equal:
path: spec.template.spec.containers[1].image
value: ""
47 changes: 47 additions & 0 deletions helm/tests/values/image-registry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
routerSpec:
repository: ghcr.io/lmcache/lmstack-router
tag: v1
cacheserverSpec:
enabled: true
image:
repository: registry.example.org:5000/lmcache/cache
tag: v2
loraController:
enableLoraController: true
sharedPvcStorage:
enabled: true
servingEngineSpec:
modelSpec:
- name: engine
repository: vllm/vllm-openai
tag: v3
modelURL: example/model
replicaCount: 1
requestCPU: 1
requestMemory: 1Gi
requestGPU: 0
pvcStorage: 1Gi
enableLoRA: true
initContainer:
name: init
image: busybox:1.36
- name: ray
repository: localhost:5000/team/ray-vllm
tag: v4
modelURL: example/model
replicaCount: 1
requestCPU: 1
requestMemory: 1Gi
requestGPU: 0
initContainer:
name: worker-init
image: docker.io/library/busybox:1.36
raySpec:
enabled: true
headNode:
requestCPU: 1
requestMemory: 1Gi
requestGPU: 0
initContainer:
name: head-init
image: localhost/tools/init@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
10 changes: 10 additions & 0 deletions helm/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@
"description": "Array of extra Kubernetes objects to deploy. Each object should be a valid Kubernetes manifest in YAML format. This can be used to deploy additional resources such as ConfigMaps, Secrets, or custom resources that are not directly supported by the chart's built-in configuration. Supports use of custom Helm templates.",
"type": "array"
},
"global": {
"description": "Global configuration",
"type": "object",
"properties": {
"imageRegistry": {
"description": "Override the registry of images managed by this chart. Leave empty to use each configured image unchanged.",
"type": "string"
}
}
},
"grafanaDashboards": {
"description": "Set to true do deploy dashboards stored in the \"dashboards\" directory as configmaps. This requires the kube-prometheus-stack to be deployed with Grafana enabled and properly configured to pick up dashboards from configmaps.",
"type": "object",
Expand Down
Loading