feat: support open-webui charts

This commit is contained in:
Ivan087
2025-11-21 10:45:23 +08:00
parent 30dd26120a
commit fc2a155ded
84 changed files with 13039 additions and 2 deletions

View File

@ -0,0 +1,77 @@
{{- `
🎉 Welcome to Open WebUI!!
██████╗ ██████╗ ███████╗███╗ ██╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██╗
██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██║ ██║██╔════╝██╔══██╗██║ ██║██║
██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██║ █╗ ██║█████╗ ██████╔╝██║ ██║██║
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║███╗██║██╔══╝ ██╔══██╗██║ ██║██║
╚██████╔╝██║ ███████╗██║ ╚████║ ╚███╔███╔╝███████╗██████╔╝╚██████╔╝██║
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚══╝╚══╝ ╚══════╝╚═════╝ ╚═════╝ ╚═╝
` }}
v{{ .Chart.AppVersion }} - building the best open-source AI user interface.
- Chart Version: v{{ .Chart.Version }}
- Project URL 1: {{ .Chart.Home }}
- Project URL 2: https://github.com/open-webui/open-webui
- Documentation: https://docs.openwebui.com/
- Chart URL: https://github.com/open-webui/helm-charts
Open WebUI is a web-based user interface that works with Ollama, OpenAI, Claude 3, Gemini and more.
This interface allows you to easily interact with local AI models.
1. Deployment Information:
- Chart Name: {{ .Chart.Name }}
- Release Name: {{ .Release.Name }}
- Namespace: {{ .Release.Namespace }}
2. Access the Application:
{{- if contains "ClusterIP" .Values.service.type }}
Access via ClusterIP service:
export LOCAL_PORT=8080
export POD_NAME=$(kubectl get pods -n {{ .Release.Namespace }} -l "app.kubernetes.io/component={{ include "open-webui.name" . }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod -n {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
kubectl -n {{ .Release.Namespace }} port-forward $POD_NAME $LOCAL_PORT:$CONTAINER_PORT
echo "Visit http://127.0.0.1:$LOCAL_PORT to use your application"
Then, access the application at: http://127.0.0.1:$LOCAL_PORT or http://localhost:8080
{{- else if contains "NodePort" .Values.service.type }}
Access via NodePort service:
export NODE_PORT=$(kubectl get -n {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "open-webui.name" . }})
export NODE_IP=$(kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
Access via LoadBalancer service:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
NOTE: The external address format depends on your cloud provider:
- AWS: Will return a hostname (e.g., xxx.elb.amazonaws.com)
- GCP/Azure: Will return an IP address
You can watch the status by running:
kubectl get -n {{ .Release.Namespace }} svc {{ include "open-webui.name" . }} --watch
export EXTERNAL_IP=$(kubectl get -n {{ .Release.Namespace }} svc {{ include "open-webui.name" . }} -o jsonpath="{.status.loadBalancer.ingress[0].hostname:-.status.loadBalancer.ingress[0].ip}")
echo http://$EXTERNAL_IP:{{ .Values.service.port }}
{{- end }}
{{- if .Values.ingress.enabled }}
Ingress is enabled. Access the application at: http{{ if .Values.ingress.tls }}s{{ end }}://{{ .Values.ingress.host }}
{{- end }}
3. Useful Commands:
- Check deployment status:
helm status {{ .Release.Name }} -n {{ .Release.Namespace }}
- Get detailed information:
helm get all {{ .Release.Name }} -n {{ .Release.Namespace }}
- View logs:
{{- if .Values.persistence.enabled }}
kubectl logs -f statefulset/{{ include "open-webui.name" . }} -n {{ .Release.Namespace }}
{{- else }}
kubectl logs -f deployment/{{ include "open-webui.name" . }} -n {{ .Release.Namespace }}
{{- end }}
4. Cleanup:
- Uninstall the deployment:
helm uninstall {{ .Release.Name }} -n {{ .Release.Namespace }}

View File

@ -0,0 +1,256 @@
{{/*
Allow the release namespace to be overridden for multi-namespace deployments in combined charts
*/}}
{{- define "open-webui.namespace" -}}
{{- if .Values.namespaceOverride -}}
{{- .Values.namespaceOverride -}}
{{- else -}}
{{- .Release.Namespace -}}
{{- end -}}
{{- end -}}
{{/*
Set the name of the Open WebUI resources
*/}}
{{- define "open-webui.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end -}}
{{/*
Set the name of the integrated Ollama resources
*/}}
{{- define "ollama.name" -}}
open-webui-ollama
{{- end -}}
{{/*
Set the name of the integrated Pipelines resources
*/}}
{{- define "pipelines.name" -}}
open-webui-pipelines
{{- end -}}
{{/*
Constructs a semicolon-separated string of Ollama API endpoint URLs from the ollamaUrls list
defined in the values.yaml file
*/}}
{{- define "ollamaUrls" -}}
{{- if .Values.ollamaUrls }}
{{- join ";" .Values.ollamaUrls | trimSuffix "/" }}
{{- end }}
{{- end }}
{{/*
Generates the URL for accessing the Ollama service within the Kubernetes cluster when the
ollama.enabled value is set to true, which means that the Ollama Helm chart is being installed
as a dependency of the Open WebUI chart
*/}}
{{- define "ollamaLocalUrl" -}}
{{- if .Values.ollama.enabled -}}
{{- $clusterDomain := .Values.clusterDomain }}
{{- $ollamaServicePort := .Values.ollama.service.port | toString }}
{{- printf "http://%s.%s.svc.%s:%s" (default .Values.ollama.name .Values.ollama.fullnameOverride) (.Release.Namespace) $clusterDomain $ollamaServicePort }}
{{- end }}
{{- end }}
{{/*
Constructs a string containing the URLs of the Ollama API endpoints that the Open WebUI
application should use based on which values are set for Ollama/ whether the Ollama
subchart is in use
*/}}
{{- define "ollamaBaseUrls" -}}
{{- $ollamaLocalUrl := include "ollamaLocalUrl" . }}
{{- $ollamaUrls := include "ollamaUrls" . }}
{{- if and .Values.ollama.enabled .Values.ollamaUrls }}
{{- printf "%s;%s" $ollamaUrls $ollamaLocalUrl }}
{{- else if .Values.ollama.enabled }}
{{- printf "%s" $ollamaLocalUrl }}
{{- else if .Values.ollamaUrls }}
{{- printf "%s" $ollamaUrls }}
{{- end }}
{{- end }}
{{/*
Create the chart name and version for the chart label
*/}}
{{- define "chart.name" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create the base labels to include on chart resources
*/}}
{{- define "base.labels" -}}
helm.sh/chart: {{ include "chart.name" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Create selector labels to include on all resources
*/}}
{{- define "base.selectorLabels" -}}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{/*
Create selector labels to include on all Open WebUI resources
*/}}
{{- define "open-webui.selectorLabels" -}}
{{ include "base.selectorLabels" . }}
app.kubernetes.io/component: {{ .Chart.Name }}
{{- end }}
{{/*
Create labels to include on chart all Open WebUI resources
*/}}
{{- define "open-webui.labels" -}}
{{ include "base.labels" . }}
{{ include "open-webui.selectorLabels" . }}
{{- end }}
{{/*
Create selector labels to include on chart all Ollama resources
*/}}
{{- define "ollama.selectorLabels" -}}
{{ include "base.selectorLabels" . }}
app.kubernetes.io/component: {{ include "ollama.name" . }}
{{- end }}
{{/*
Create labels to include on chart all Ollama resources
*/}}
{{- define "ollama.labels" -}}
{{ include "base.labels" . }}
{{ include "ollama.selectorLabels" . }}
{{- end }}
{{/*
Create selector labels to include on chart all Pipelines resources
*/}}
{{- define "pipelines.selectorLabels" -}}
{{ include "base.selectorLabels" . }}
app.kubernetes.io/component: {{ include "pipelines.name" . }}
{{- end }}
{{/*
Create labels to include on chart all Pipelines resources
*/}}
{{- define "pipelines.labels" -}}
{{ include "base.labels" . }}
{{ include "pipelines.selectorLabels" . }}
{{- end }}
{{/*
Create the service endpoint to use for Pipelines if the subchart is used
*/}}
{{- define "pipelines.serviceEndpoint" -}}
{{- if .Values.pipelines.enabled -}}
{{- $clusterDomain := .Values.clusterDomain }}
{{- $pipelinesServicePort := .Values.pipelines.service.port | toString }}
{{- printf "http://%s.%s.svc.%s:%s" (include "pipelines.name" .) (.Release.Namespace) $clusterDomain $pipelinesServicePort }}
{{- end }}
{{- end }}
{{/*
Create selector labels to include on chart all websocket resources
*/}}
{{- define "websocket.redis.selectorLabels" -}}
{{ include "base.selectorLabels" . }}
app.kubernetes.io/component: {{ .Values.websocket.redis.name }}
{{- end }}
{{/*
Create labels to include on chart all websocket resources
*/}}
{{- define "websocket.redis.labels" -}}
{{ include "base.labels" . }}
{{ include "websocket.redis.selectorLabels" . }}
{{- end }}
{{/*
Validate SSO ClientSecret to be set literally or via Secret
*/}}
{{- define "sso.validateClientSecret" -}}
{{- $provider := .provider }}
{{- $values := .values }}
{{- if and (empty (index $values $provider "clientSecret")) (empty (index $values $provider "clientExistingSecret")) }}
{{- fail (printf "You must provide either .Values.sso.%s.clientSecret or .Values.sso.%s.clientExistingSecret" $provider $provider) }}
{{- end }}
{{- end }}
{{- /*
Fail template rendering if invalid log component
*/ -}}
{{- define "logging.isValidComponent" -}}
{{- $component := . | lower -}}
{{- $validComponents := dict
"audio" true
"comfyui" true
"config" true
"db" true
"images" true
"main" true
"models" true
"ollama" true
"openai" true
"rag" true
"webhook" true
-}}
{{- hasKey $validComponents $component -}}
{{- end }}
{{- define "logging.assertValidComponent" -}}
{{- $component := lower . -}}
{{- $res := include "logging.isValidComponent" $component }}
{{- if ne $res "true" }}
{{- fail (printf "Invalid logging component name: '%s'. Valid names: audio, comfyui, config, db, images, main, models, ollama, openai, rag, webhook" $component) }}
{{- end }}
{{- end }}
{{- /*
Fail template rendering if invalid log level
*/ -}}
{{- define "logging.assertValidLevel" -}}
{{- $level := lower . }}
{{- $validLevels := dict "notset" true "debug" true "info" true "warning" true "error" true "critical" true }}
{{- if not (hasKey $validLevels $level) }}
{{- fail (printf "Invalid log level: '%s'. Valid values are: notset, debug, info, warning, error, critical" $level) }}
{{- end }}
{{- end }}
{{- /*
Render a logging env var for a component, validating value
*/ -}}
{{- define "logging.componentEnvVar" -}}
{{- $name := .componentName }}
{{- $level := .logLevel }}
{{- include "logging.assertValidComponent" $name -}}
{{- include "logging.assertValidLevel" $level }}
- name: {{ printf "%s_LOG_LEVEL" (upper $name) | quote }}
value: {{ $level | quote | trim }}
{{- end }}
{{- /*
Constructs a string containing the URLs of the Open WebUI based on the ingress configuration
used to populate the variable WEBUI_URL
*/ -}}
{{- define "open-webui.url" -}}
{{- $url := "" -}}
{{- range .Values.extraEnvVars }}
{{- if and (eq .name "WEBUI_URL") .value }}
{{- $url = .value }}
{{- end }}
{{- end }}
{{- if not $url }}
{{- $proto := "http" -}}
{{- if .Values.ingress.tls }}
{{- $proto = "https" -}}
{{- end }}
{{- $url = printf "%s://%s" $proto .Values.ingress.host }}
{{- end }}
{{- $url }}
{{- end }}

View File

@ -0,0 +1,6 @@
{{- if .Values.extraResources }}
{{- range .Values.extraResources }}
---
{{ toYaml . | nindent 0 }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,52 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "open-webui.name" . }}
namespace: {{ include "open-webui.namespace" . }}
labels:
{{- include "open-webui.labels" . | nindent 4 }}
{{- with .Values.ingress.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- if .Values.ingress.annotations }}
annotations:
{{- tpl (toYaml .Values.ingress.annotations | nindent 4) . }}
{{- end }}
spec:
{{- with .Values.ingress.class }}
ingressClassName: {{ . }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
- hosts:
- {{ .Values.ingress.host | quote }}
{{- range .Values.ingress.additionalHosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ default (printf "%s-tls" .Release.Name) .Values.ingress.existingSecret }}
{{- end }}
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "open-webui.name" . }}
port:
name: http
{{- range .Values.ingress.additionalHosts }}
- host: {{ . | quote }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "open-webui.name" $ }}
port:
name: http
{{- end }}
{{- end }}

View File

@ -0,0 +1,11 @@
{{- if .Values.managedCertificate.enabled }}
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: {{ .Values.managedCertificate.name | default "mydomain-cert" }}
spec:
domains:
{{- range .Values.managedCertificate.domains }}
- {{ . | quote }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,28 @@
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.provider "local") }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "open-webui.name" . }}
namespace: {{ include "open-webui.namespace" . }}
labels:
{{- include "open-webui.selectorLabels" . | nindent 4 }}
{{- with .Values.persistence.annotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
accessModes:
{{- range .Values.persistence.accessModes }}
- {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- if .Values.persistence.storageClass }}
storageClassName: {{ .Values.persistence.storageClass }}
{{- end }}
{{- with .Values.persistence.selector }}
selector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,14 @@
{{- if .Values.serviceAccount.enable }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Values.serviceAccount.name | default (include "open-webui.name" .) }}
namespace: {{ include "open-webui.namespace" . }}
labels:
{{- include "open-webui.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}

View File

@ -0,0 +1,36 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "open-webui.name" . }}
namespace: {{ include "open-webui.namespace" . }}
labels:
{{- include "open-webui.labels" . | nindent 4 }}
{{- with .Values.service.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
{{- include "open-webui.selectorLabels" . | nindent 4 }}
type: {{ .Values.service.type | default "ClusterIP" }}
ports:
- protocol: TCP
name: http
port: {{ .Values.service.port }}
targetPort: http
{{- if .Values.service.nodePort }}
nodePort: {{ .Values.service.nodePort | int }}
{{- end }}
{{- if .Values.service.loadBalancerClass }}
loadBalancerClass: {{ .Values.service.loadBalancerClass | quote }}
{{- end }}
{{- if and (eq .Values.service.type "ClusterIP") (.Values.service.clusterIP) }}
clusterIP: {{ .Values.service.clusterIP }}
{{- end }}
{{- if and (eq .Values.service.type "LoadBalancer") (.Values.service.loadBalancerIP) }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}

View File

@ -0,0 +1,98 @@
{{- if and .Values.websocket.enabled .Values.websocket.redis.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.websocket.redis.name }}
namespace: {{ include "open-webui.namespace" . }}
labels:
{{- include "websocket.redis.labels" . | nindent 4 }}
{{- with .Values.websocket.redis.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
annotations:
{{- with .Values.websocket.redis.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "websocket.redis.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "websocket.redis.labels" . | nindent 8 }}
{{- with .Values.websocket.redis.pods.labels }}
{{- toYaml . | nindent 8 }}
{{- end }}
annotations:
{{- with .Values.websocket.redis.pods.annotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- if .Values.websocket.redis.image.pullSecretName }}
imagePullSecrets:
- name: {{ .Values.websocket.redis.image.pullSecretName }}
{{- end }}
containers:
- name: {{ .Values.websocket.redis.name }}
image: "{{ .Values.websocket.redis.image.repository }}:{{ .Values.websocket.redis.image.tag }}"
imagePullPolicy: {{ .Values.websocket.redis.image.pullPolicy }}
{{- with .Values.websocket.redis.command }}
command:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.websocket.redis.args }}
args:
{{- toYaml . | nindent 10 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.websocket.redis.service.containerPort }}
{{- with .Values.websocket.redis.resources }}
resources:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.websocket.redis.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.websocket.redis.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.websocket.redis.securityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.websocket.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.websocket.redis.name }}
namespace: {{ include "open-webui.namespace" . }}
labels:
{{- include "websocket.redis.labels" . | nindent 4 }}
{{- with .Values.websocket.redis.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
annotations:
{{- with .Values.websocket.redis.service.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
{{- include "websocket.redis.selectorLabels" . | nindent 4 }}
type: {{ .Values.websocket.redis.service.type | default "ClusterIP" }}
ports:
- protocol: TCP
name: {{ .Values.websocket.redis.service.portName | default "http" }}
port: {{ .Values.websocket.redis.service.port }}
targetPort: http
{{- if .Values.websocket.redis.service.nodePort }}
nodePort: {{ .Values.websocket.redis.service.nodePort | int }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,418 @@
apiVersion: apps/v1
{{- if and .Values.persistence.enabled (eq .Values.persistence.provider "local") }}
kind: StatefulSet
{{- else }}
kind: Deployment
{{- end }}
metadata:
name: {{ include "open-webui.name" . }}
namespace: {{ include "open-webui.namespace" . }}
labels:
{{- include "open-webui.labels" . | nindent 4 }}
{{- with .Values.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.replicaCount }}
{{- if or (not .Values.persistence.enabled) (not (eq .Values.persistence.provider "local")) }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
{{- end }}
{{- if and .Values.persistence.enabled (eq .Values.persistence.provider "local") }}
serviceName: {{ include "open-webui.name" . }}
{{- end }}
selector:
matchLabels:
{{- include "open-webui.selectorLabels" . | nindent 6 }}
{{- if .Values.strategy }}
{{- if and .Values.persistence.enabled (eq .Values.persistence.provider "local") }}
updateStrategy:
{{- toYaml .Values.strategy | nindent 4 }}
{{- else }}
strategy:
{{- toYaml .Values.strategy | nindent 4 }}
{{- end }}
{{- end }}
template:
metadata:
labels:
{{- include "open-webui.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
initContainers:
- name: copy-app-data
{{- with .Values.image }}
image: {{ .repository }}:{{ .tag | default $.Chart.AppVersion }}
imagePullPolicy: {{ .pullPolicy }}
{{- end }}
command:
{{- toYaml (.Values.copyAppData.command | default (list "sh" "-c" "cp -R -n /app/backend/data/* /tmp/app-data/")) | nindent 10 }}
{{- with .Values.copyAppData.args }}
args:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.copyAppData.resources }}
resources: {{- toYaml . | nindent 10 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /tmp/app-data
{{- if .Values.persistence.subPath }}
subPath: {{ .Values.persistence.subPath }}
{{- end }}
{{- with .Values.volumeMounts.initContainer }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.extraInitContainers }}
{{- toYaml . | nindent 6 }}
{{- end }}
enableServiceLinks: false
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- if .Values.runtimeClassName }}
runtimeClassName: {{ .Values.runtimeClassName | quote }}
{{- end }}
{{- if .Values.serviceAccount.enable }}
serviceAccountName: {{ .Values.serviceAccount.name | default (include "open-webui.name" .) }}
{{- end }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{- with .Values.image }}
image: {{ .repository }}:{{ .tag | default $.Chart.AppVersion }}
imagePullPolicy: {{ .pullPolicy }}
{{- end }}
{{- with .Values.command }}
command:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.args }}
args:
{{- toYaml . | nindent 10 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.service.containerPort }}
{{- with .Values.livenessProbe }}
livenessProbe: {{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe: {{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.startupProbe }}
startupProbe: {{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.resources }}
resources: {{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /app/backend/data
{{- if .Values.persistence.subPath }}
subPath: {{ .Values.persistence.subPath }}
{{- end }}
{{- with .Values.volumeMounts.container }}
{{- toYaml . | nindent 8 }}
{{- end }}
env:
{{- $hasCustomWebUIUrl := false }}
{{- range .Values.extraEnvVars }}
{{- if eq .name "WEBUI_URL" }}
{{- $hasCustomWebUIUrl = true }}
{{- end }}
{{- end }}
{{- if and .Values.ingress.enabled (not $hasCustomWebUIUrl) }}
- name: WEBUI_URL
value: {{ include "open-webui.url" . | quote }}
{{- end }}
{{- if .Values.ollamaUrlsFromExtraEnv}}
{{- else if or .Values.ollamaUrls .Values.ollama.enabled }}
- name: "OLLAMA_BASE_URLS"
value: {{ include "ollamaBaseUrls" . | quote }}
{{- else }}
- name: "ENABLE_OLLAMA_API"
value: "False"
{{- end }}
{{- if and .Values.enableOpenaiApi .Values.openaiBaseApiUrl (not .Values.openaiBaseApiUrls) (not .Values.pipelines.enabled) }}
# If only an OpenAI API value is set, set it to OPENAI_API_BASE_URL
- name: "OPENAI_API_BASE_URL"
value: {{ .Values.openaiBaseApiUrl | quote }}
{{- else if and .Values.enableOpenaiApi .Values.openaiBaseApiUrl .Values.pipelines.enabled (not .Values.openaiBaseApiUrls) }}
# If Pipelines is enabled and OpenAI API value is set, use OPENAI_API_BASE_URLS with combined values
- name: "OPENAI_API_BASE_URLS"
value: "{{ include "pipelines.serviceEndpoint" . }};{{ .Values.openaiBaseApiUrl }}"
{{- else if and .Values.enableOpenaiApi .Values.pipelines.enabled (not .Values.openaiBaseApiUrl) (not .Values.openaiBaseApiUrls) }}
# If Pipelines is enabled and no OpenAI API values are set, set OPENAI_API_BASE_URL to the Pipelines server endpoint
- name: "OPENAI_API_BASE_URL"
value: {{ include "pipelines.serviceEndpoint" . | quote }}
{{- else if and .Values.enableOpenaiApi .Values.openaiBaseApiUrls .Values.pipelines.enabled }}
# If OpenAI API value(s) set and Pipelines is enabled, use OPENAI_API_BASE_URLS to support all the endpoints in the chart
- name: "OPENAI_API_BASE_URLS"
value: "{{ include "pipelines.serviceEndpoint" . }};{{ join ";" .Values.openaiBaseApiUrls }}"
{{- else if not .Values.enableOpenaiApi }}
- name: "ENABLE_OPENAI_API"
value: "False"
{{- end }}
{{- if .Values.tika.enabled }}
- name: "CONTENT_EXTRACTION_ENGINE"
value: "Tika"
- name: "TIKA_SERVER_URL"
value: http://{{ .Chart.Name }}-tika:9998
{{- end }}
{{- if eq .Values.persistence.provider "s3" }}
- name: "STORAGE_PROVIDER"
value: {{ .Values.persistence.provider }}
- name: "S3_ACCESS_KEY_ID"
{{- if .Values.persistence.s3.accessKeyExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.persistence.s3.accessKeyExistingSecret }}
key: {{ .Values.persistence.s3.accessKeyExistingAccessKey }}
{{- else }}
value: {{ .Values.persistence.s3.accessKey }}
{{- end }}
- name: "S3_SECRET_ACCESS_KEY"
{{- if .Values.persistence.s3.secretKeyExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.persistence.s3.secretKeyExistingSecret }}
key: {{ .Values.persistence.s3.secretKeyExistingSecretKey }}
{{- else }}
value: {{ .Values.persistence.s3.secretKey }}
{{- end }}
- name: "S3_ENDPOINT_URL"
value: {{ .Values.persistence.s3.endpointUrl }}
- name: "S3_BUCKET_NAME"
value: {{ .Values.persistence.s3.bucket }}
- name: "S3_REGION_NAME"
value: {{ .Values.persistence.s3.region }}
- name: "S3_KEY_PREFIX"
value: {{ .Values.persistence.s3.keyPrefix }}
{{- else if eq .Values.persistence.provider "gcs" }}
- name: "STORAGE_PROVIDER"
value: {{ .Values.persistence.provider }}
- name: "GOOGLE_APPLICATION_CREDENTIALS_JSON"
{{- if .Values.persistence.gcs.appCredentialsJsonExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.persistence.gcs.appCredentialsJsonExistingSecret }}
key: {{ .Values.persistence.gcs.appCredentialsJsonExistingSecretKey }}
{{- else }}
value: {{ .Values.persistence.gcs.appCredentialsJson }}
{{- end }}
- name: "GCS_BUCKET_NAME"
value: {{ .Values.persistence.gcs.bucket }}
{{- else if eq .Values.persistence.provider "azure" }}
- name: "STORAGE_PROVIDER"
value: {{ .Values.persistence.provider }}
- name: "AZURE_STORAGE_ENDPOINT"
value: {{ .Values.persistence.azure.endpointUrl }}
- name: "AZURE_STORAGE_CONTAINER_NAME"
value: {{ .Values.persistence.azure.container }}
- name: "AZURE_STORAGE_KEY"
{{- if .Values.persistence.azure.keyExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.persistence.azure.keyExistingSecret }}
key: {{ .Values.persistence.azure.keyExistingSecretKey }}
{{- else }}
value: {{ .Values.persistence.azure.key }}
{{- end }}
{{- end }}
{{- if .Values.websocket.enabled }}
- name: "ENABLE_WEBSOCKET_SUPPORT"
value: "True"
- name: "WEBSOCKET_MANAGER"
value: {{ .Values.websocket.manager | default "redis" | quote }}
- name: "WEBSOCKET_REDIS_URL"
value: {{ .Values.websocket.url | quote }}
{{- end }}
{{- if .Values.databaseUrl }}
- name: "DATABASE_URL"
value: {{ .Values.databaseUrl | quote }}
{{- end }}
{{- if .Values.sso.enabled }}
{{- if .Values.sso.enableSignup }}
- name: "ENABLE_OAUTH_SIGNUP"
value: "True"
{{- end }}
{{- if .Values.sso.mergeAccountsByEmail }}
- name: "OAUTH_MERGE_ACCOUNTS_BY_EMAIL"
value: "True"
{{- end }}
{{- if .Values.sso.google.enabled }}
- name: "GOOGLE_CLIENT_ID"
value: {{ .Values.sso.google.clientId | quote }}
{{- include "sso.validateClientSecret" (dict "provider" "google" "values" .Values.sso) }}
- name: "GOOGLE_CLIENT_SECRET"
{{- if .Values.sso.google.clientExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.sso.google.clientExistingSecret | quote }}
key: {{ .Values.sso.google.clientExistingSecretKey | quote }}
{{- else }}
value: {{ .Values.sso.google.clientSecret | quote }}
{{- end }}
{{- end }}
{{- if .Values.sso.microsoft.enabled }}
- name: "MICROSOFT_CLIENT_ID"
value: {{ .Values.sso.microsoft.clientId | quote }}
{{- include "sso.validateClientSecret" (dict "provider" "microsoft" "values" .Values.sso) }}
- name: "MICROSOFT_CLIENT_SECRET"
{{- if .Values.sso.microsoft.clientExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.sso.microsoft.clientExistingSecret | quote }}
key: {{ .Values.sso.microsoft.clientExistingSecretKey | quote }}
{{- else }}
value: {{ .Values.sso.microsoft.clientSecret | quote }}
{{- end }}
- name: "MICROSOFT_CLIENT_TENANT_ID"
value: {{ .Values.sso.microsoft.tenantId | quote }}
{{- end }}
{{- if .Values.sso.github.enabled }}
- name: "GITHUB_CLIENT_ID"
value: {{ .Values.sso.github.clientId | quote }}
{{- include "sso.validateClientSecret" (dict "provider" "github" "values" .Values.sso) }}
- name: "GITHUB_CLIENT_SECRET"
{{- if .Values.sso.github.clientExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.sso.github.clientExistingSecret | quote }}
key: {{ .Values.sso.github.clientExistingSecretKey | quote }}
{{- else }}
value: {{ .Values.sso.github.clientSecret | quote }}
{{- end }}
{{- end }}
{{- if .Values.sso.oidc.enabled }}
- name: "OAUTH_CLIENT_ID"
value: {{ .Values.sso.oidc.clientId | quote }}
{{- include "sso.validateClientSecret" (dict "provider" "oidc" "values" .Values.sso) }}
- name: "OAUTH_CLIENT_SECRET"
{{- if .Values.sso.oidc.clientExistingSecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.sso.oidc.clientExistingSecret | quote }}
key: {{ .Values.sso.oidc.clientExistingSecretKey | quote }}
{{- else }}
value: {{ .Values.sso.oidc.clientSecret | quote }}
{{- end }}
- name: "OPENID_PROVIDER_URL"
value: {{ .Values.sso.oidc.providerUrl | quote }}
- name: "OAUTH_PROVIDER_NAME"
value: {{ .Values.sso.oidc.providerName | quote }}
- name: "OAUTH_SCOPES"
value: {{ .Values.sso.oidc.scopes | quote }}
{{- end }}
{{- if .Values.sso.enableRoleManagement }}
- name: "ENABLE_OAUTH_ROLE_MANAGEMENT"
value: "True"
- name: "OAUTH_ROLES_CLAIM"
value: {{ .Values.sso.roleManagement.rolesClaim | quote }}
{{- if .Values.sso.roleManagement.allowedRoles }}
- name: "OAUTH_ALLOWED_ROLES"
value: {{ .Values.sso.roleManagement.allowedRoles | quote }}
{{- end }}
{{- if .Values.sso.roleManagement.adminRoles }}
- name: "OAUTH_ADMIN_ROLES"
value: {{ .Values.sso.roleManagement.adminRoles | quote }}
{{- end }}
{{- end }}
{{- if .Values.sso.enableGroupManagement }}
- name: "ENABLE_OAUTH_GROUP_MANAGEMENT"
value: "True"
- name: "OAUTH_GROUP_CLAIM"
value: {{ .Values.sso.groupManagement.groupsClaim | quote }}
{{- end }}
{{- if .Values.sso.trustedHeader.enabled }}
- name: "WEBUI_AUTH_TRUSTED_EMAIL_HEADER"
value: {{ .Values.sso.trustedHeader.emailHeader | quote }}
{{- if .Values.sso.trustedHeader.nameHeader }}
- name: "WEBUI_AUTH_TRUSTED_NAME_HEADER"
value: {{ .Values.sso.trustedHeader.nameHeader | quote }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.logging.level }}
{{- include "logging.assertValidLevel" .Values.logging.level }}
- name: "GLOBAL_LOG_LEVEL"
value: {{ .Values.logging.level | quote }}
{{- end }}
{{- if .Values.logging.components }}
{{- range $name, $level := .Values.logging.components }}
{{- if $level }}
{{- include "logging.componentEnvVar" (dict "componentName" $name "logLevel" $level) | indent 8 }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.extraEnvVars }}
{{- toYaml .Values.extraEnvVars | nindent 8 }}
{{- end }}
{{- if .Values.commonEnvVars }}
{{- toYaml .Values.commonEnvVars | nindent 8 }}
{{- end }}
{{- if .Values.extraEnvFrom }}
envFrom:
{{- toYaml .Values.extraEnvFrom | nindent 8 }}
{{- end }}
tty: true
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- if and .Values.persistence.enabled .Values.persistence.existingClaim }}
- name: data
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim }}
{{- else if or (not .Values.persistence.enabled) (not (eq .Values.persistence.provider "local")) }}
- name: data
emptyDir: {}
{{- else if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
- name: data
persistentVolumeClaim:
claimName: {{ include "open-webui.name" . }}
{{- end }}
{{- with .Values.volumes }}
{{- toYaml . | nindent 6 }}
{{- end }}