diff --git a/.gitignore b/.gitignore index 0a982d0..39a5f27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ **/config/* -values.user.yaml \ No newline at end of file +values.user.yaml +charts \ No newline at end of file diff --git a/llama-cpp/.helmignore b/llama-cpp/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/llama-cpp/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/llama-cpp/Chart.yaml b/llama-cpp/Chart.yaml new file mode 100644 index 0000000..a52fbb6 --- /dev/null +++ b/llama-cpp/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: llama-cpp +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +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.0.2 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/llama-cpp/README.md b/llama-cpp/README.md new file mode 100644 index 0000000..d0f6503 --- /dev/null +++ b/llama-cpp/README.md @@ -0,0 +1,22 @@ +# TuringPi Llama.cpp Chart + +Deploys [Llama.cpp server](https://github.com/ggerganov/llama.cpp/tree/master/examples/server) onto your TuringPi +cluster, complete with a persistent volume to store the model files, replication and an ingress. Assumes you have +followed the instructions at [docs.turingpi.com](https://docs.turingpi.com/docs/how-to-plan-kubernetes-installation) to +configure Longhorn, MetaLB and Traefik. By default, uses `lmstudio-ai/gemma-2b-it-GGUF` model, but this can be +overridden with custom values. + +## Installation + +```shell +helm install llama-cpp https://elepedus.github.io/llama-cpp/llama-cpp-0.0.1.tgz --namespace=llama-cpp +``` + +## Usage + +By default, the ingress exposes the web UI at `llama.cluster.local`, at the same IP address as you configured +for `cluster.local` Make sure to update your `/etc/hosts` file so the new subdomain is accessible: + +``` +10.0.0.70 turing-cluster turing-cluster.local llama.cluster llama.cluster.local +``` \ No newline at end of file diff --git a/llama-cpp/templates/NOTES.txt b/llama-cpp/templates/NOTES.txt new file mode 100644 index 0000000..81dc060 --- /dev/null +++ b/llama-cpp/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "llama-cpp.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "llama-cpp.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "llama-cpp.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "llama-cpp.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/llama-cpp/templates/_helpers.tpl b/llama-cpp/templates/_helpers.tpl new file mode 100644 index 0000000..cb23544 --- /dev/null +++ b/llama-cpp/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "llama-cpp.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "llama-cpp.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "llama-cpp.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "llama-cpp.labels" -}} +helm.sh/chart: {{ include "llama-cpp.chart" . }} +{{ include "llama-cpp.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "llama-cpp.selectorLabels" -}} +app.kubernetes.io/name: {{ include "llama-cpp.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "llama-cpp.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "llama-cpp.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/llama-cpp/templates/deployment.yaml b/llama-cpp/templates/deployment.yaml new file mode 100644 index 0000000..4259483 --- /dev/null +++ b/llama-cpp/templates/deployment.yaml @@ -0,0 +1,80 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "llama-cpp.fullname" . }} + labels: + {{- include "llama-cpp.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "llama-cpp.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "llama-cpp.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: {{ printf "%s:%s" .Values.image.repository (.Values.image.tag | default .Chart.AppVersion) }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: [ "/server"] + args: + - "--port" + - {{ .Values.service.port | quote }} + - "--host" + - "0.0.0.0" + {{- range $key, $value := .Values.llama.args }} + {{- if $value }} + - "--{{ $key }}" + - "{{ $value }}" + {{- else }} + - "--{{ $key }}" + {{- end }} + {{- end }} + + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/llama-cpp/templates/ingress.yaml b/llama-cpp/templates/ingress.yaml new file mode 100644 index 0000000..7aa86eb --- /dev/null +++ b/llama-cpp/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "llama-cpp.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "llama-cpp.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/llama-cpp/templates/pvc.yaml b/llama-cpp/templates/pvc.yaml new file mode 100644 index 0000000..0eca049 --- /dev/null +++ b/llama-cpp/templates/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: models +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ .Values.storage.size }} + storageClassName: {{ .Values.storage.storageClass }} diff --git a/llama-cpp/templates/service.yaml b/llama-cpp/templates/service.yaml new file mode 100644 index 0000000..82770a3 --- /dev/null +++ b/llama-cpp/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: { { include "llama-cpp.fullname" . } } + labels: { { - include "llama-cpp.labels" . | nindent 4 } } +spec: + type: { { .Values.service.type } } + ports: + - port: { { .Values.service.port } } + targetPort: http + protocol: TCP + name: http + selector: { { - include "llama-cpp.selectorLabels" . | nindent 4 } } diff --git a/llama-cpp/templates/tests/test-connection.yaml b/llama-cpp/templates/tests/test-connection.yaml new file mode 100644 index 0000000..cadba72 --- /dev/null +++ b/llama-cpp/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "llama-cpp.fullname" . }}-test-connection" + labels: + {{- include "llama-cpp.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "llama-cpp.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/llama-cpp/values.schema.json b/llama-cpp/values.schema.json new file mode 100644 index 0000000..a16a7df --- /dev/null +++ b/llama-cpp/values.schema.json @@ -0,0 +1,213 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "fullnameOverride": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "imagePullSecrets": { + "type": "array" + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": "null" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + } + } + } + } + } + } + }, + "tls": { + "type": "array" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "port": { + "type": "string" + } + } + }, + "initialDelaySeconds": { + "type": "integer" + } + } + }, + "llama": { + "type": "object", + "properties": { + "args": { + "type": "object", + "properties": { + "hf-file": { + "type": "string" + }, + "hf-repo": { + "type": "string" + }, + "model": { + "type": "string" + }, + "n-predict": { + "type": "string" + }, + "parallel": { + "type": "string" + } + } + } + } + }, + "nameOverride": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object" + }, + "readinessProbe": { + "type": "object", + "properties": { + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "port": { + "type": "string" + } + } + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "securityContext": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "storage": { + "type": "object", + "properties": { + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "tolerations": { + "type": "array" + }, + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "mountPath": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "persistentVolumeClaim": { + "type": "object", + "properties": { + "claimName": { + "type": "string" + } + } + } + } + } + } + } +} diff --git a/llama-cpp/values.yaml b/llama-cpp/values.yaml new file mode 100644 index 0000000..82cb43e --- /dev/null +++ b/llama-cpp/values.yaml @@ -0,0 +1,101 @@ +# yaml-language-server: $schema=./values.schema.json + +# Default values for llama-cpp. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + # repository: "local/llama.cpp" + repository: "ghcr.io/ggerganov/llama.cpp" + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "server-60cdf40cc32f0ad4cb11e0ca8fd38f3b93d8d640" + +llama: + args: + model: "/models/gemma-2b-it-q4_k_m.gguf" + hf-repo: "lmstudio-ai/gemma-2b-it-GGUF" + hf-file: "gemma-2b-it-q4_k_m.gguf" + n-predict: "-1" + parallel: "2" + +storage: + size: 24Gi + storageClass: "local-path" +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "traefik" + annotations: + hosts: + - host: llama.cluster.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +livenessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 900 +readinessProbe: + httpGet: + path: /health + port: http + +# Additional volumes on the output Deployment definition. +volumes: + - name: "models" + persistentVolumeClaim: + claimName: "models" + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: + - name: "models" + mountPath: "/models" + + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/open-webui/.helmignore b/open-webui/.helmignore new file mode 100644 index 0000000..260f898 --- /dev/null +++ b/open-webui/.helmignore @@ -0,0 +1,25 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +.drone.yml +*.tmproj +.vscode/ +values-minikube.yaml diff --git a/open-webui/Chart.lock b/open-webui/Chart.lock new file mode 100644 index 0000000..6bb9ae1 --- /dev/null +++ b/open-webui/Chart.lock @@ -0,0 +1,15 @@ +dependencies: +- name: ollama + repository: https://otwld.github.io/ollama-helm/ + version: 1.4.0 +- name: pipelines + repository: https://helm.openwebui.com + version: 0.0.6 +- name: tika + repository: https://apache.jfrog.io/artifactory/tika + version: 2.9.0 +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 20.6.3 +digest: sha256:b5e309a6aa07e946ccb1f49f84dc359a0af837b8d830efb88498d6f8da2aea8f +generated: "2025-01-29T07:24:10.947566155+08:00" diff --git a/open-webui/Chart.yaml b/open-webui/Chart.yaml new file mode 100644 index 0000000..b6d2e4e --- /dev/null +++ b/open-webui/Chart.yaml @@ -0,0 +1,44 @@ +annotations: + licenses: MIT +apiVersion: v2 +appVersion: 0.5.4 +dependencies: +- condition: ollama.enabled + import-values: + - child: service + parent: ollama.service + name: ollama + repository: https://otwld.github.io/ollama-helm/ + version: '>=0.24.0' +- condition: pipelines.enabled + import-values: + - child: service + parent: pipelines.service + name: pipelines + repository: https://helm.openwebui.com + version: '>=0.0.1' +- condition: tika.enabled + name: tika + repository: https://apache.jfrog.io/artifactory/tika + version: '>=2.9.0' +- alias: redis-cluster + condition: redis-cluster.enabled + name: redis + repository: https://charts.bitnami.com/bitnami + version: '>=20.6.2' +description: "Open WebUI: A User-Friendly Web Interface for Chat Interactions \U0001F44B" +home: https://www.openwebui.com/ +icon: https://raw.githubusercontent.com/open-webui/open-webui/main/static/favicon.png +keywords: +- llm +- chat +- web-ui +- open-webui +name: open-webui +sources: +- https://github.com/open-webui/helm-charts +- https://github.com/open-webui/open-webui/pkgs/container/open-webui +- https://github.com/otwld/ollama-helm/ +- https://hub.docker.com/r/ollama/ollama +- https://charts.bitnami.com/bitnami +version: 5.4.0 diff --git a/open-webui/README.md b/open-webui/README.md new file mode 100644 index 0000000..ef4a5b4 --- /dev/null +++ b/open-webui/README.md @@ -0,0 +1,126 @@ +# open-webui + +![Version: 5.4.0](https://img.shields.io/badge/Version-5.4.0-informational?style=flat-square) ![AppVersion: 0.5.4](https://img.shields.io/badge/AppVersion-0.5.4-informational?style=flat-square) + +Open WebUI: A User-Friendly Web Interface for Chat Interactions 👋 + +**Homepage:** + +## Source Code + +* +* +* +* + +## Installing + +Before you can install, you need to add the `open-webui` repo to [Helm](https://helm.sh) + +```shell +helm repo add open-webui https://helm.openwebui.com/ +helm repo update +``` + +Now you can install the chart: + +```shell +helm upgrade --install open-webui open-webui/open-webui +``` + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://apache.jfrog.io/artifactory/tika | tika | >=2.9.0 | +| https://charts.bitnami.com/bitnami | redis-cluster(redis) | >=20.6.2 | +| https://helm.openwebui.com | pipelines | >=0.0.1 | +| https://otwld.github.io/ollama-helm/ | ollama | >=0.24.0 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Affinity for pod assignment | +| annotations | object | `{}` | | +| clusterDomain | string | `"cluster.local"` | Value of cluster domain | +| containerSecurityContext | object | `{}` | Configure container security context ref: | +| copyAppData.resources | object | `{}` | | +| extraEnvVars | list | `[{"name":"OPENAI_API_KEY","value":"0p3n-w3bu!"}]` | Env vars added to the Open WebUI deployment. Most up-to-date environment variables can be found here: https://docs.openwebui.com/getting-started/env-configuration/ | +| extraEnvVars[0] | object | `{"name":"OPENAI_API_KEY","value":"0p3n-w3bu!"}` | Default API key value for Pipelines. Should be updated in a production deployment, or be changed to the required API key if not using Pipelines | +| extraResources | list | `[]` | Extra resources to deploy with Open WebUI | +| image | object | `{"pullPolicy":"IfNotPresent","repository":"ghcr.io/open-webui/open-webui","tag":""}` | Open WebUI image tags can be found here: https://github.com/open-webui/open-webui | +| imagePullSecrets | list | `[]` | Configure imagePullSecrets to use private registry ref: | +| ingress.additionalHosts | list | `[]` | | +| ingress.annotations | object | `{}` | Use appropriate annotations for your Ingress controller, e.g., for NGINX: nginx.ingress.kubernetes.io/rewrite-target: / | +| ingress.class | string | `""` | | +| ingress.enabled | bool | `false` | | +| ingress.existingSecret | string | `""` | | +| ingress.host | string | `""` | | +| ingress.tls | bool | `false` | | +| livenessProbe | object | `{}` | Probe for liveness of the Open WebUI container ref: | +| nameOverride | string | `""` | | +| namespaceOverride | string | `""` | | +| nodeSelector | object | `{}` | Node labels for pod assignment. | +| ollama.enabled | bool | `true` | Automatically install Ollama Helm chart from https://otwld.github.io/ollama-helm/. Use [Helm Values](https://github.com/otwld/ollama-helm/#helm-values) to configure | +| ollama.fullnameOverride | string | `"open-webui-ollama"` | If enabling embedded Ollama, update fullnameOverride to your desired Ollama name value, or else it will use the default ollama.name value from the Ollama chart | +| ollamaUrls | list | `[]` | A list of Ollama API endpoints. These can be added in lieu of automatically installing the Ollama Helm chart, or in addition to it. | +| openaiBaseApiUrl | string | `""` | OpenAI base API URL to use. Defaults to the Pipelines service endpoint when Pipelines are enabled, and "https://api.openai.com/v1" if Pipelines are not enabled and this value is blank | +| persistence.accessModes | list | `["ReadWriteOnce"]` | If using multiple replicas, you must update accessModes to ReadWriteMany | +| persistence.annotations | object | `{}` | | +| persistence.enabled | bool | `true` | | +| persistence.existingClaim | string | `""` | Use existingClaim if you want to re-use an existing Open WebUI PVC instead of creating a new one | +| persistence.selector | object | `{}` | | +| persistence.size | string | `"2Gi"` | | +| persistence.storageClass | string | `""` | | +| persistence.subPath | string | `""` | Subdirectory of Open WebUI PVC to mount. Useful if root directory is not empty. | +| pipelines.enabled | bool | `true` | Automatically install Pipelines chart to extend Open WebUI functionality using Pipelines: https://github.com/open-webui/pipelines | +| pipelines.extraEnvVars | list | `[]` | This section can be used to pass required environment variables to your pipelines (e.g. Langfuse hostname) | +| podAnnotations | object | `{}` | | +| podLabels | object | `{}` | | +| podSecurityContext | object | `{}` | Configure pod security context ref: | +| readinessProbe | object | `{}` | Probe for readiness of the Open WebUI container ref: | +| redis-cluster | object | `{"auth":{"enabled":false},"enabled":false,"fullnameOverride":"open-webui-redis","replica":{"replicaCount":3}}` | Deploys a Redis cluster with subchart 'redis' from bitnami | +| redis-cluster.auth | object | `{"enabled":false}` | Redis Authentication | +| redis-cluster.auth.enabled | bool | `false` | Enable Redis authentication (disabled by default). For your security, we strongly suggest that you switch to 'auth.enabled=true' | +| redis-cluster.enabled | bool | `false` | Enable Redis installation | +| redis-cluster.fullnameOverride | string | `"open-webui-redis"` | Redis cluster name (recommended to be 'open-webui-redis') - In this case, redis url will be 'redis://open-webui-redis-master:6379/0' or 'redis://[:@]open-webui-redis-master:6379/0' | +| redis-cluster.replica | object | `{"replicaCount":3}` | Replica configuration for the Redis cluster | +| redis-cluster.replica.replicaCount | int | `3` | Number of Redis replica instances | +| replicaCount | int | `1` | | +| resources | object | `{}` | | +| service | object | `{"annotations":{},"containerPort":8080,"labels":{},"loadBalancerClass":"","nodePort":"","port":80,"type":"ClusterIP"}` | Service values to expose Open WebUI pods to cluster | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.automountServiceAccountToken | bool | `false` | | +| serviceAccount.enable | bool | `true` | | +| serviceAccount.name | string | `""` | | +| startupProbe | object | `{}` | Probe for startup of the Open WebUI container ref: | +| strategy | object | `{}` | Strategy for updating the workload manager: deployment or statefulset | +| tika.enabled | bool | `false` | Automatically install Apache Tika to extend Open WebUI | +| tolerations | list | `[]` | Tolerations for pod assignment | +| topologySpreadConstraints | list | `[]` | Topology Spread Constraints for pod assignment | +| volumeMounts | object | `{"container":[],"initContainer":[]}` | Configure container volume mounts ref: | +| volumes | list | `[]` | Configure pod volumes ref: | +| websocket.enabled | bool | `false` | Enables websocket support in Open WebUI with env `ENABLE_WEBSOCKET_SUPPORT` | +| websocket.manager | string | `"redis"` | Specifies the websocket manager to use with env `WEBSOCKET_MANAGER`: redis (default) | +| websocket.redis | object | `{"annotations":{},"args":[],"command":[],"enabled":true,"image":{"pullPolicy":"IfNotPresent","repository":"redis","tag":"7.4.2-alpine3.21"},"labels":{},"name":"open-webui-redis","resources":{},"service":{"annotations":{},"containerPort":6379,"labels":{},"nodePort":"","port":6379,"type":"ClusterIP"}}` | Deploys a redis | +| websocket.redis.annotations | object | `{}` | Redis annotations | +| websocket.redis.args | list | `[]` | Redis arguments (overrides default) | +| websocket.redis.command | list | `[]` | Redis command (overrides default) | +| websocket.redis.enabled | bool | `true` | Enable redis installation | +| websocket.redis.image | object | `{"pullPolicy":"IfNotPresent","repository":"redis","tag":"7.4.2-alpine3.21"}` | Redis image | +| websocket.redis.labels | object | `{}` | Redis labels | +| websocket.redis.name | string | `"open-webui-redis"` | Redis name | +| websocket.redis.resources | object | `{}` | Redis resources | +| websocket.redis.service | object | `{"annotations":{},"containerPort":6379,"labels":{},"nodePort":"","port":6379,"type":"ClusterIP"}` | Redis service | +| websocket.redis.service.annotations | object | `{}` | Redis service annotations | +| websocket.redis.service.containerPort | int | `6379` | Redis container/target port | +| websocket.redis.service.labels | object | `{}` | Redis service labels | +| websocket.redis.service.nodePort | string | `""` | Redis service node port. Valid only when type is `NodePort` | +| websocket.redis.service.port | int | `6379` | Redis service port | +| websocket.redis.service.type | string | `"ClusterIP"` | Redis service type | +| websocket.url | string | `"redis://open-webui-redis:6379/0"` | Specifies the URL of the Redis instance for websocket communication. Template with `redis://[:@]:/` | + +---------------------------------------------- + +Autogenerated from chart metadata using [helm-docs](https://github.com/norwoodj/helm-docs/). diff --git a/open-webui/README.md.gotmpl b/open-webui/README.md.gotmpl new file mode 100644 index 0000000..89fee1c --- /dev/null +++ b/open-webui/README.md.gotmpl @@ -0,0 +1,36 @@ +{{ template "chart.header" . }} + +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +## Installing + +Before you can install, you need to add the `open-webui` repo to [Helm](https://helm.sh) + +```shell +helm repo add open-webui https://helm.openwebui.com/ +helm repo update +``` + +Now you can install the chart: + +```shell +helm upgrade --install open-webui open-webui/open-webui +``` + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +---------------------------------------------- + +Autogenerated from chart metadata using [helm-docs](https://github.com/norwoodj/helm-docs/). diff --git a/open-webui/templates/NOTES.txt b/open-webui/templates/NOTES.txt new file mode 100644 index 0000000..1fe5e46 --- /dev/null +++ b/open-webui/templates/NOTES.txt @@ -0,0 +1,77 @@ +{{- ` +🎉 Welcome to Open WebUI!! + ___ __ __ _ _ _ ___ + / _ \ _ __ ___ _ __ \ \ / /__| |__ | | | |_ _| +| | | | '_ \ / _ \ '_ \ \ \ /\ / / _ \ '_ \| | | || | +| |_| | |_) | __/ | | | \ V V / __/ |_) | |_| || | + \___/| .__/ \___|_| |_| \_/\_/ \___|_.__/ \___/|___| + |_| +` }} +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 }} diff --git a/open-webui/templates/_helpers.tpl b/open-webui/templates/_helpers.tpl new file mode 100644 index 0000000..953244b --- /dev/null +++ b/open-webui/templates/_helpers.tpl @@ -0,0 +1,171 @@ +{{/* +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 }} diff --git a/open-webui/templates/extra-resources.yaml b/open-webui/templates/extra-resources.yaml new file mode 100644 index 0000000..5124a0b --- /dev/null +++ b/open-webui/templates/extra-resources.yaml @@ -0,0 +1,6 @@ +{{- if .Values.extraResources }} +{{- range .Values.extraResources }} +--- +{{ toYaml . | nindent 0 }} +{{- end }} +{{- end }} diff --git a/open-webui/templates/ingress.yaml b/open-webui/templates/ingress.yaml new file mode 100644 index 0000000..6b89ff4 --- /dev/null +++ b/open-webui/templates/ingress.yaml @@ -0,0 +1,49 @@ +{{- 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.annotations }} + annotations: + {{- toYaml . | 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 }} diff --git a/open-webui/templates/pvc.yaml b/open-webui/templates/pvc.yaml new file mode 100644 index 0000000..c412e7f --- /dev/null +++ b/open-webui/templates/pvc.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +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 }} diff --git a/open-webui/templates/service-account.yaml b/open-webui/templates/service-account.yaml new file mode 100644 index 0000000..ecea069 --- /dev/null +++ b/open-webui/templates/service-account.yaml @@ -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 }} \ No newline at end of file diff --git a/open-webui/templates/service.yaml b/open-webui/templates/service.yaml new file mode 100644 index 0000000..bce51b6 --- /dev/null +++ b/open-webui/templates/service.yaml @@ -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 }} + diff --git a/open-webui/templates/websocket-redis.yaml b/open-webui/templates/websocket-redis.yaml new file mode 100644 index 0000000..5e95dc8 --- /dev/null +++ b/open-webui/templates/websocket-redis.yaml @@ -0,0 +1,71 @@ +{{- 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 }} + spec: + 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 }} +--- +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: http + port: {{ .Values.websocket.redis.service.port }} + targetPort: http + {{- if .Values.websocket.redis.service.nodePort }} + nodePort: {{ .Values.websocket.redis.service.nodePort | int }} + {{- end }} +{{- end }} diff --git a/open-webui/templates/workload-manager.yaml b/open-webui/templates/workload-manager.yaml new file mode 100644 index 0000000..97fcabe --- /dev/null +++ b/open-webui/templates/workload-manager.yaml @@ -0,0 +1,178 @@ +apiVersion: apps/v1 +{{- if .Values.persistence.enabled }} +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 .Values.persistence.enabled }} + serviceName: {{ include "open-webui.name" . }} + {{- end }} + selector: + matchLabels: + {{- include "open-webui.selectorLabels" . | nindent 6 }} + {{- if .Values.strategy }} + {{- if .Values.persistence.enabled }} + 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 }} + initContainers: + - name: copy-app-data + {{- with .Values.image }} + image: {{ .repository }}:{{ .tag | default $.Chart.AppVersion }} + imagePullPolicy: {{ .pullPolicy }} + {{- end }} + command: ['sh', '-c', 'cp -R -n /app/backend/data/* /tmp/app-data/'] + {{- 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 }} + enableServiceLinks: false + automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} + {{- 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 }} + 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: + {{- if or .Values.ollamaUrls .Values.ollama.enabled }} + - name: "OLLAMA_BASE_URLS" + value: {{ include "ollamaBaseUrls" . | quote }} + {{- else }} + - name: "ENABLE_OLLAMA_API" + value: "False" + {{- end }} + - name: "OPENAI_API_BASE_URL" + {{- if .Values.pipelines.enabled }} + value: {{ include "pipelines.serviceEndpoint" . }} + {{- else if .Values.openaiBaseApiUrl }} + value: {{ .Values.openaiBaseApiUrl | quote }} + {{- end }} + {{- if .Values.extraEnvVars }} + {{- toYaml .Values.extraEnvVars | nindent 8 }} + {{- end }} + {{- if .Values.tika.enabled }} + - name: "CONTENT_EXTRACTION_ENGINE" + value: "Tika" + - name: "TIKA_SERVER_URL" + value: http://{{ .Chart.Name }}-tika:9998 + {{- 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 }} + 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 }} + volumes: + {{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim }} + {{- else if not .Values.persistence.enabled }} + - 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 }} diff --git a/open-webui/values.schema.json b/open-webui/values.schema.json new file mode 100644 index 0000000..91675c0 --- /dev/null +++ b/open-webui/values.schema.json @@ -0,0 +1,357 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "annotations": { + "type": "object" + }, + "clusterDomain": { + "type": "string" + }, + "containerSecurityContext": { + "type": "object" + }, + "copyAppData": { + "type": "object", + "properties": { + "resources": { + "type": "object" + } + } + }, + "extraEnvVars": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "extraResources": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "imagePullSecrets": { + "type": "array" + }, + "ingress": { + "type": "object", + "properties": { + "additionalHosts": { + "type": "array" + }, + "annotations": { + "type": "object" + }, + "class": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "host": { + "type": "string" + }, + "tls": { + "type": "boolean" + } + } + }, + "livenessProbe": { + "type": "object" + }, + "nameOverride": { + "type": "string" + }, + "namespaceOverride": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "ollama": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + } + } + }, + "ollamaUrls": { + "type": "array" + }, + "openaiBaseApiUrl": { + "type": "string" + }, + "persistence": { + "type": "object", + "properties": { + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "annotations": { + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "existingClaim": { + "type": "string" + }, + "selector": { + "type": "object" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + }, + "subPath": { + "type": "string" + } + } + }, + "pipelines": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "extraEnvVars": { + "type": "array" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object" + }, + "readinessProbe": { + "type": "object" + }, + "redis-cluster": { + "type": "object", + "properties": { + "auth": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "enabled": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + }, + "replica": { + "type": "object", + "properties": { + "replicaCount": { + "type": "integer" + } + } + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "containerPort": { + "type": "integer" + }, + "labels": { + "type": "object" + }, + "loadBalancerClass": { + "type": "string" + }, + "nodePort": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "enable": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "startupProbe": { + "type": "object" + }, + "strategy": { + "type": "object" + }, + "tika": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "tolerations": { + "type": "array" + }, + "topologySpreadConstraints": { + "type": "array" + }, + "volumeMounts": { + "type": "object", + "properties": { + "container": { + "type": "array" + }, + "initContainer": { + "type": "array" + } + } + }, + "volumes": { + "type": "array" + }, + "websocket": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "manager": { + "type": "string" + }, + "redis": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "args": { + "type": "array" + }, + "command": { + "type": "array" + }, + "enabled": { + "type": "boolean" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "type": "string" + }, + "resources": { + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "containerPort": { + "type": "integer" + }, + "labels": { + "type": "object" + }, + "nodePort": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + } + } + }, + "url": { + "type": "string" + } + } + } + } +} diff --git a/open-webui/values.yaml b/open-webui/values.yaml new file mode 100644 index 0000000..47a2494 --- /dev/null +++ b/open-webui/values.yaml @@ -0,0 +1,278 @@ +# yaml-language-server: $schema=./values.schema.json + +nameOverride: "" +namespaceOverride: "" + +ollama: + # -- Automatically install Ollama Helm chart from https://otwld.github.io/ollama-helm/. Use [Helm Values](https://github.com/otwld/ollama-helm/#helm-values) to configure + enabled: true + # -- If enabling embedded Ollama, update fullnameOverride to your desired Ollama name value, or else it will use the default ollama.name value from the Ollama chart + fullnameOverride: "open-webui-ollama" + # -- Example Ollama configuration with nvidia GPU enabled, automatically downloading a model, and deploying a PVC for model persistence + # ollama: + # gpu: + # enabled: true + # type: 'nvidia' + # number: 1 + # models: + # - llama3 + # runtimeClassName: nvidia + # persistentVolume: + # enabled: true + # volumeName: "example-pre-existing-pv-created-by-smb-csi" + +pipelines: + # -- Automatically install Pipelines chart to extend Open WebUI functionality using Pipelines: https://github.com/open-webui/pipelines + enabled: true + # -- This section can be used to pass required environment variables to your pipelines (e.g. Langfuse hostname) + extraEnvVars: [] + +tika: + # -- Automatically install Apache Tika to extend Open WebUI + enabled: false + +# -- A list of Ollama API endpoints. These can be added in lieu of automatically installing the Ollama Helm chart, or in addition to it. +ollamaUrls: [] + +websocket: + # -- Enables websocket support in Open WebUI with env `ENABLE_WEBSOCKET_SUPPORT` + enabled: false + # -- Specifies the websocket manager to use with env `WEBSOCKET_MANAGER`: redis (default) + manager: redis + # -- Specifies the URL of the Redis instance for websocket communication. Template with `redis://[:@]:/` + url: redis://open-webui-redis:6379/0 + # -- Deploys a redis + redis: + # -- Enable redis installation + enabled: true + # -- Redis name + name: open-webui-redis + # -- Redis labels + labels: {} + # -- Redis annotations + annotations: {} + # -- Redis image + image: + repository: redis + tag: 7.4.2-alpine3.21 + pullPolicy: IfNotPresent + # -- Redis command (overrides default) + command: [] + # -- Redis arguments (overrides default) + args: [] + # -- Redis resources + resources: {} + # -- Redis service + service: + # -- Redis container/target port + containerPort: 6379 + # -- Redis service type + type: ClusterIP + # -- Redis service labels + labels: {} + # -- Redis service annotations + annotations: {} + # -- Redis service port + port: 6379 + # -- Redis service node port. Valid only when type is `NodePort` + nodePort: "" + +# -- Deploys a Redis cluster with subchart 'redis' from bitnami +redis-cluster: + # -- Enable Redis installation + enabled: false + # -- Redis cluster name (recommended to be 'open-webui-redis') + # - In this case, redis url will be 'redis://open-webui-redis-master:6379/0' or 'redis://[:@]open-webui-redis-master:6379/0' + fullnameOverride: open-webui-redis + # -- Redis Authentication + auth: + # -- Enable Redis authentication (disabled by default). For your security, we strongly suggest that you switch to 'auth.enabled=true' + enabled: false + # -- Replica configuration for the Redis cluster + replica: + # -- Number of Redis replica instances + replicaCount: 3 + +# -- Value of cluster domain +clusterDomain: cluster.local + +annotations: {} +podAnnotations: {} +podLabels: {} +replicaCount: 1 +# -- Strategy for updating the workload manager: deployment or statefulset +strategy: {} +# -- Open WebUI image tags can be found here: https://github.com/open-webui/open-webui +image: + repository: ghcr.io/open-webui/open-webui + tag: "" + pullPolicy: "IfNotPresent" + +serviceAccount: + enable: true + name: "" + annotations: {} + automountServiceAccountToken: false + +# -- Configure imagePullSecrets to use private registry +# ref: +imagePullSecrets: [] +# imagePullSecrets: +# - name: myRegistryKeySecretName + +# -- Probe for liveness of the Open WebUI container +# ref: +livenessProbe: {} +# livenessProbe: +# httpGet: +# path: /health +# port: http +# failureThreshold: 1 +# periodSeconds: 10 + +# -- Probe for readiness of the Open WebUI container +# ref: +readinessProbe: {} +# readinessProbe: +# httpGet: +# path: /health/db +# port: http +# failureThreshold: 1 +# periodSeconds: 10 + +# -- Probe for startup of the Open WebUI container +# ref: +startupProbe: {} +# startupProbe: +# httpGet: +# path: /health +# port: http +# initialDelaySeconds: 30 +# periodSeconds: 5 +# failureThreshold: 20 + +resources: {} + +copyAppData: + resources: {} + +ingress: + enabled: false + class: "" + # -- Use appropriate annotations for your Ingress controller, e.g., for NGINX: + # nginx.ingress.kubernetes.io/rewrite-target: / + annotations: {} + host: "" + additionalHosts: [] + tls: false + existingSecret: "" +persistence: + enabled: true + size: 2Gi + # -- Use existingClaim if you want to re-use an existing Open WebUI PVC instead of creating a new one + existingClaim: "" + # -- Subdirectory of Open WebUI PVC to mount. Useful if root directory is not empty. + subPath: "" + # -- If using multiple replicas, you must update accessModes to ReadWriteMany + accessModes: + - ReadWriteOnce + storageClass: "" + selector: {} + annotations: {} + +# -- Node labels for pod assignment. +nodeSelector: {} + +# -- Tolerations for pod assignment +tolerations: [] + +# -- Affinity for pod assignment +affinity: {} + +# -- Topology Spread Constraints for pod assignment +topologySpreadConstraints: [] + +# -- Service values to expose Open WebUI pods to cluster +service: + type: ClusterIP + annotations: {} + port: 80 + containerPort: 8080 + nodePort: "" + labels: {} + loadBalancerClass: "" + +# -- OpenAI base API URL to use. Defaults to the Pipelines service endpoint when Pipelines are enabled, and "https://api.openai.com/v1" if Pipelines are not enabled and this value is blank +openaiBaseApiUrl: "" + +# -- Env vars added to the Open WebUI deployment. Most up-to-date environment variables can be found here: https://docs.openwebui.com/getting-started/env-configuration/ +extraEnvVars: + # -- Default API key value for Pipelines. Should be updated in a production deployment, or be changed to the required API key if not using Pipelines + - name: OPENAI_API_KEY + value: "0p3n-w3bu!" + # valueFrom: + # secretKeyRef: + # name: pipelines-api-key + # key: api-key + # - name: OPENAI_API_KEY + # valueFrom: + # secretKeyRef: + # name: openai-api-key + # key: api-key + # - name: OLLAMA_DEBUG + # value: "1" + +# -- Configure container volume mounts +# ref: +volumeMounts: + initContainer: [] + # - name: "" + # mountPath: "" + container: [] + # - name: "" + # mountPath: "" + +# -- Configure pod volumes +# ref: +volumes: [] +# - name: "" +# configMap: +# name: "" +# - name: "" +# emptyDir: {} + +# -- Configure pod security context +# ref: +podSecurityContext: + {} + # fsGroupChangePolicy: Always + # sysctls: [] + # supplementalGroups: [] + # fsGroup: 1001 + + +# -- Configure container security context +# ref: +containerSecurityContext: + {} + # runAsUser: 1001 + # runAsGroup: 1001 + # runAsNonRoot: true + # privileged: false + # allowPrivilegeEscalation: false + # readOnlyRootFilesystem: false + # capabilities: + # drop: + # - ALL + # seccompProfile: + # type: "RuntimeDefault" + +# -- Extra resources to deploy with Open WebUI +extraResources: + [] + # - apiVersion: v1 + # kind: ConfigMap + # metadata: + # name: example-configmap + # data: + # example-key: example-value