From 6a9c242f660a3e433298fef5f0035780c4e252e7 Mon Sep 17 00:00:00 2001 From: Yassin Kortam Date: Mon, 6 Jul 2026 19:53:47 +0300 Subject: [PATCH] feat(helm): support user-defined volumes and volumeMounts in microservices chart (#32233) The componentized chart at helm/litellm had no way to mount extra volumes into its deployments, so custom callback or SSO handler code could not be mounted the way the docs describe for the monolithic chart. Adds per-component volumes and volumeMounts values for gateway, backend, and ui, merged with the existing gateway-config volume, plus a helm-unittest suite for the chart wired into the helm unit test workflow Resolves LIT-4209 --- .github/workflows/helm_unit_test.yml | 4 +- .../litellm/templates/backend/deployment.yaml | 14 +- .../litellm/templates/gateway/deployment.yaml | 14 +- helm/litellm/templates/ui/deployment.yaml | 8 + .../tests/deployment_volumes_tests.yaml | 172 ++++++++++++++++++ helm/litellm/tests/values/required.yaml | 4 + helm/litellm/values.yaml | 13 ++ 7 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 helm/litellm/tests/deployment_volumes_tests.yaml create mode 100644 helm/litellm/tests/values/required.yaml diff --git a/.github/workflows/helm_unit_test.yml b/.github/workflows/helm_unit_test.yml index 06836b1d1cd..a280e5557bb 100644 --- a/.github/workflows/helm_unit_test.yml +++ b/.github/workflows/helm_unit_test.yml @@ -38,4 +38,6 @@ jobs: echo "Helm unittest plugin integrity verified: $ACTUAL_SHA" - name: Run unit tests - run: helm unittest -f 'tests/*.yaml' deploy/charts/litellm-helm + run: | + helm unittest -f 'tests/*.yaml' deploy/charts/litellm-helm + helm unittest -f 'tests/*.yaml' helm/litellm diff --git a/helm/litellm/templates/backend/deployment.yaml b/helm/litellm/templates/backend/deployment.yaml index b355db43540..8b4552bf302 100644 --- a/helm/litellm/templates/backend/deployment.yaml +++ b/helm/litellm/templates/backend/deployment.yaml @@ -45,11 +45,16 @@ spec: value: /app/config/config.yaml {{- end }} {{- include "litellm.envFrom" .Values.backend | nindent 10 }} - {{- if .Values.gateway.config.create }} + {{- if or .Values.gateway.config.create .Values.backend.volumeMounts }} volumeMounts: + {{- if .Values.gateway.config.create }} - name: gateway-config mountPath: /app/config/config.yaml subPath: config.yaml + {{- end }} + {{- with .Values.backend.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} {{- end }} {{- with .Values.backend.livenessProbe }} livenessProbe: @@ -61,11 +66,16 @@ spec: {{- end }} resources: {{- toYaml .Values.backend.resources | nindent 12 }} - {{- if .Values.gateway.config.create }} + {{- if or .Values.gateway.config.create .Values.backend.volumes }} volumes: + {{- if .Values.gateway.config.create }} - name: gateway-config configMap: name: {{ include "litellm.gateway.fullname" . }}-config + {{- end }} + {{- with .Values.backend.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.backend.nodeSelector }} nodeSelector: diff --git a/helm/litellm/templates/gateway/deployment.yaml b/helm/litellm/templates/gateway/deployment.yaml index 05ea4052159..bd491b69e0f 100644 --- a/helm/litellm/templates/gateway/deployment.yaml +++ b/helm/litellm/templates/gateway/deployment.yaml @@ -47,11 +47,16 @@ spec: value: {{ .Values.gateway.numWorkers | quote }} {{- end }} {{- include "litellm.envFrom" .Values.gateway | nindent 10 }} - {{- if .Values.gateway.config.create }} + {{- if or .Values.gateway.config.create .Values.gateway.volumeMounts }} volumeMounts: + {{- if .Values.gateway.config.create }} - name: gateway-config mountPath: /app/config/config.yaml subPath: config.yaml + {{- end }} + {{- with .Values.gateway.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} {{- end }} {{- with .Values.gateway.livenessProbe }} livenessProbe: @@ -63,11 +68,16 @@ spec: {{- end }} resources: {{- toYaml .Values.gateway.resources | nindent 12 }} - {{- if .Values.gateway.config.create }} + {{- if or .Values.gateway.config.create .Values.gateway.volumes }} volumes: + {{- if .Values.gateway.config.create }} - name: gateway-config configMap: name: {{ include "litellm.gateway.fullname" . }}-config + {{- end }} + {{- with .Values.gateway.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.gateway.nodeSelector }} nodeSelector: diff --git a/helm/litellm/templates/ui/deployment.yaml b/helm/litellm/templates/ui/deployment.yaml index b40b44cca53..79e9a3e43bb 100644 --- a/helm/litellm/templates/ui/deployment.yaml +++ b/helm/litellm/templates/ui/deployment.yaml @@ -46,6 +46,10 @@ spec: {{- toYaml . | nindent 12 }} {{- end }} {{- include "litellm.envFrom" .Values.ui | nindent 10 }} + {{- with .Values.ui.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} {{- with .Values.ui.livenessProbe }} livenessProbe: {{- toYaml . | nindent 12 }} @@ -56,6 +60,10 @@ spec: {{- end }} resources: {{- toYaml .Values.ui.resources | nindent 12 }} + {{- with .Values.ui.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.ui.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/helm/litellm/tests/deployment_volumes_tests.yaml b/helm/litellm/tests/deployment_volumes_tests.yaml new file mode 100644 index 00000000000..3a64300b86c --- /dev/null +++ b/helm/litellm/tests/deployment_volumes_tests.yaml @@ -0,0 +1,172 @@ +suite: test deployment volumes and volumeMounts +templates: + - gateway/deployment.yaml + - gateway/configmap.yaml + - backend/deployment.yaml + - ui/deployment.yaml +values: + - ./values/required.yaml +tests: + - it: gateway renders only the config volume by default + template: gateway/deployment.yaml + asserts: + - equal: + path: spec.template.spec.volumes + value: + - name: gateway-config + configMap: + name: RELEASE-NAME-litellm-gateway-config + - equal: + path: spec.template.spec.containers[0].volumeMounts + value: + - name: gateway-config + mountPath: /app/config/config.yaml + subPath: config.yaml + + - it: gateway merges user volumes and volumeMounts with the config volume + template: gateway/deployment.yaml + set: + gateway.volumes: + - name: custom-callbacks + configMap: + name: custom-callbacks + gateway.volumeMounts: + - name: custom-callbacks + mountPath: /app/custom_callbacks.py + subPath: custom_callbacks.py + asserts: + - equal: + path: spec.template.spec.volumes[0].name + value: gateway-config + - equal: + path: spec.template.spec.volumes[1] + value: + name: custom-callbacks + configMap: + name: custom-callbacks + - equal: + path: spec.template.spec.containers[0].volumeMounts[0].name + value: gateway-config + - equal: + path: spec.template.spec.containers[0].volumeMounts[1] + value: + name: custom-callbacks + mountPath: /app/custom_callbacks.py + subPath: custom_callbacks.py + + - it: gateway renders user volumes even when config creation is disabled + template: gateway/deployment.yaml + set: + gateway.config.create: false + gateway.volumes: + - name: certs + secret: + secretName: tls-certs + gateway.volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true + asserts: + - equal: + path: spec.template.spec.volumes + value: + - name: certs + secret: + secretName: tls-certs + - equal: + path: spec.template.spec.containers[0].volumeMounts + value: + - name: certs + mountPath: /etc/certs + readOnly: true + + - it: gateway omits volumes when config creation is disabled and no user volumes are set + template: gateway/deployment.yaml + set: + gateway.config.create: false + asserts: + - isNull: + path: spec.template.spec.volumes + - isNull: + path: spec.template.spec.containers[0].volumeMounts + + - it: backend merges user volumes and volumeMounts with the shared config volume + template: backend/deployment.yaml + set: + backend.volumes: + - name: sso-handler + configMap: + name: sso-handler + backend.volumeMounts: + - name: sso-handler + mountPath: /app/custom_sso.py + subPath: custom_sso.py + asserts: + - equal: + path: spec.template.spec.volumes[0].name + value: gateway-config + - equal: + path: spec.template.spec.volumes[1] + value: + name: sso-handler + configMap: + name: sso-handler + - equal: + path: spec.template.spec.containers[0].volumeMounts[1] + value: + name: sso-handler + mountPath: /app/custom_sso.py + subPath: custom_sso.py + + - it: backend renders user volumes even when config creation is disabled + template: backend/deployment.yaml + set: + gateway.config.create: false + backend.volumes: + - name: data + emptyDir: {} + backend.volumeMounts: + - name: data + mountPath: /data + asserts: + - equal: + path: spec.template.spec.volumes + value: + - name: data + emptyDir: {} + - equal: + path: spec.template.spec.containers[0].volumeMounts + value: + - name: data + mountPath: /data + + - it: ui renders no volumes by default + template: ui/deployment.yaml + asserts: + - isNull: + path: spec.template.spec.volumes + - isNull: + path: spec.template.spec.containers[0].volumeMounts + + - it: ui renders user volumes and volumeMounts + template: ui/deployment.yaml + set: + ui.volumes: + - name: nginx-config + configMap: + name: custom-nginx + ui.volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/conf.d + asserts: + - equal: + path: spec.template.spec.volumes + value: + - name: nginx-config + configMap: + name: custom-nginx + - equal: + path: spec.template.spec.containers[0].volumeMounts + value: + - name: nginx-config + mountPath: /etc/nginx/conf.d diff --git a/helm/litellm/tests/values/required.yaml b/helm/litellm/tests/values/required.yaml new file mode 100644 index 00000000000..21d3f7a5a6a --- /dev/null +++ b/helm/litellm/tests/values/required.yaml @@ -0,0 +1,4 @@ +database: + writer: + host: postgres.example.com + dbname: litellm diff --git a/helm/litellm/values.yaml b/helm/litellm/values.yaml index 934661643bd..6aa5dd39cd0 100644 --- a/helm/litellm/values.yaml +++ b/helm/litellm/values.yaml @@ -124,6 +124,11 @@ gateway: extraEnv: [] # Add extra environment variables to the gateway envConfigMaps: [] # Add extra environment variables to the gateway from config maps envSecrets: [] # Add extra environment variables to the gateway from secrets + # Additional volumes on the gateway Deployment (e.g. a ConfigMap holding + # custom callback / SSO handler code, mounted next to the proxy config). + volumes: [] + # Additional volumeMounts on the gateway container. + volumeMounts: [] config: create: true proxy_config: {} @@ -167,6 +172,10 @@ backend: extraEnv: [] envConfigMaps: [] envSecrets: [] + # Additional volumes on the backend Deployment. + volumes: [] + # Additional volumeMounts on the backend container. + volumeMounts: [] image: repository: ghcr.io/berriai/litellm-backend tag: "" @@ -206,6 +215,10 @@ ui: extraEnv: [] envConfigMaps: [] envSecrets: [] + # Additional volumes on the ui Deployment. + volumes: [] + # Additional volumeMounts on the ui container. + volumeMounts: [] image: repository: ghcr.io/berriai/litellm-ui tag: ""