Dieses Dokument enthält eine detaillierte Anleitung zum Bereitstellen von Open WebUI, einer selbst gehosteten, browserbasierten Chat-Oberfläche, in GDC-Umgebungen (Google Distributed Cloud) mit Air Gap. Open WebUI stellt über die Ollama- und OpenAI-kompatiblen APIs eine Verbindung zu den Inferenz-Backends her, die mit den Ollama- und vLLM-Nutzerhandbüchern bereitgestellt wurden. So können Entwickler und Endnutzer mit den Open-Weight-Modellen interagieren, ohne API-Aufrufe schreiben zu müssen.
Architektur
Open WebUI wird als Deployment mit einem einzelnen Replikat in einem eigenen Namespace des Standardclusters ausgeführt. Der Status (Nutzerkonten, Chats, Einstellungen) wird auf einem ReadWriteOnce-PersistentVolumeClaim gespeichert. Ein ConfigMap enthält die Verbindungseinstellungen für die Inferenz-Backends, die über ihre clusterinternen Service-Namen erreicht werden, und ein Secret enthält den Signaturschlüssel für die Sitzung. Ein Kubernetes-Service vom Typ LoadBalancer stellt die Weboberfläche bereit und NetworkPolicy- / ProjectNetworkPolicy-Objekte sichern den Zugriff darauf.
Hinweis
Achten Sie darauf, dass mindestens ein Inferenz-Backend mit dem Nutzerhandbuch für Gemma-Modelle mit Ollama, dem Nutzerhandbuch für Gemma-Modelle mit vLLM oder dem Nutzerhandbuch für Mistral-Modelle mit vLLM bereitgestellt wurde und dass Sie Zugriff auf das Verzeichnis ${HOME}/gdcag-solutions der entsprechenden Referenzimplementierung auf der Workstation haben.
Identity and Access Management
Prüfen Sie, ob die erforderlichen IAM-Konten, -Rollen und -Berechtigungen richtig konfiguriert sind.
GDC-Nutzerrollen für die Organisation:
- Optional: Standard-Cluster-Administrator (Cluster über die Console ansehen)
GDC-Nutzerrollen im Projekt:
- Standard-Cluster-Administrator (
standard-cluster-admin)
GDC-Nutzerrolle für den Standardcluster:
StandardClusterRoleBindingfür dieStandardClusterRolecluster-admin(erstellt von einem Projekt-IAM-Administrator, siehe Abschnitt Identity and Access Management der Referenzimplementierung)
Workstation
Führen Sie alle Befehle in diesem Leitfaden auf einer Workstation mit den erforderlichen Tools und der erforderlichen Verbindung zur Umgebung und zum Internet aus, sofern in einem Schritt nichts anderes angegeben ist.
Erstellen Sie die Verzeichnisstruktur für das Nutzerhandbuch:
mkdir -p ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.d mkdir -p ${HOME}/gdcag-solutions/open-weight-models/open-webui/secrets chmod u=rwx,go= ${HOME}/gdcag-solutions/open-weight-models/open-webui/secretsErstellen Sie den Signaturschlüssel für die Sitzung:
openssl rand -hex 32 > ${HOME}/gdcag-solutions/open-weight-models/open-webui/secrets/open_webui_secret_key chmod u=rw,go= ${HOME}/gdcag-solutions/open-weight-models/open-webui/secrets/open_webui_secret_keyErstellen Sie die Konfigurationsdatei für die Nutzerhandbuch-Umgebung:
cat << 'EOF' > ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.d/open-webui.sh && echo "Successfully created." || echo "Failed to create!" # Open WebUI export GDCS_OPEN_WEBUI_IMAGE_TAG="v0.11.3" export GDCS_OPEN_WEBUI_NAME="open-webui" export GDCS_OPEN_WEBUI_PVC_SIZE="20Gi" export GDCS_OPEN_WEBUI_SECRET_KEY="$(cat ${GDCS_USER_GUIDE_HOME}/secrets/open_webui_secret_key)" # Inference backends (in-cluster Service addresses, several backends separated by ';'). # The user guides name the Service after the model: Ollama uses GDCS_OLLAMA_MODEL_KUBERNETES # (gemma4:e4b -> gemma4-e4b) and vLLM uses GDCS_HF_MODEL_KUBERNETES (such as vllm-gemma or vllm-mistral) # (mistralai/Mistral-7B-Instruct-v0.2 -> mistralai-mistral-7b-instruct-v0-2); kubectl get service # in the workload namespace (ollama-gemma, vllm-gemma or vllm-mistral) lists them. export GDCS_OPEN_WEBUI_ENABLE_OLLAMA_API="OPEN_WEBUI_ENABLE_OLLAMA_API" export GDCS_OPEN_WEBUI_OLLAMA_BASE_URLS="OPEN_WEBUI_OLLAMA_BASE_URLS" export GDCS_OPEN_WEBUI_ENABLE_OPENAI_API="OPEN_WEBUI_ENABLE_OPENAI_API" export GDCS_OPEN_WEBUI_OPENAI_API_BASE_URLS="OPEN_WEBUI_OPENAI_API_BASE_URLS" export GDCS_OPEN_WEBUI_OPENAI_API_KEYS="none" # vLLM does not check API keys unless started with --api-key # Workload export GDCS_WORKLOAD_NAMESPACE="open-webui" # CPU resources export GDCS_WORKLOAD_CPU_LIMIT="2" export GDCS_WORKLOAD_CPU_REQUEST="1" # Memory resources export GDCS_WORKLOAD_MEMORY_LIMIT="4Gi" export GDCS_WORKLOAD_MEMORY_REQUEST="2Gi" EOFErsetzen Sie Folgendes:
OPEN_WEBUI_ENABLE_OLLAMA_API:true, wenn Sie ein Ollama-Backend bereitgestellt haben, andernfallsfalse.OPEN_WEBUI_OLLAMA_BASE_URLS: die clusterinternen URLs der Ollama-Dienste, getrennt durch;, z. B.http://gemma4-e4b.ollama-gemma.svc.cluster.local. Lassen Sie das Feld leer, wenn Sie kein Ollama-Backend bereitgestellt haben.OPEN_WEBUI_ENABLE_OPENAI_API:true, wenn Sie ein vLLM-Backend bereitgestellt haben, andernfallsfalse.OPEN_WEBUI_OPENAI_API_BASE_URLS: die clusterinternen URLs der vLLM-Dienste mit dem Pfad/v1, getrennt durch;, z. B.http://mistralai-mistral-7b-instruct-v0-2.vllm-mistral.svc.cluster.local/v1oderhttp://google-gemma-4-e2b-it.vllm-gemma.svc.cluster.local/v1. Lassen Sie das Feld leer, wenn Sie kein vLLM-Backend bereitgestellt haben.
Erstellen Sie die Loader-Datei für die Nutzerhandbuch-Umgebung:
cat << 'EOF' > ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.sh && echo "Successfully created." || echo "Failed to create!" source "${HOME}/gdcag-solutions/open-weight-models/IMPLEMENTATION/env.sh" export GDCS_USER_GUIDE_HOME="${HOME}/gdcag-solutions/open-weight-models/open-webui" echo "GDCS_USER_GUIDE_HOME=${GDCS_USER_GUIDE_HOME}" # Sourced in dependency order source "${GDCS_USER_GUIDE_HOME}/env.d/open-webui.sh" EOFErsetzen Sie Folgendes:
IMPLEMENTATION:ollamaodervllm, die Referenzimplementierung, die Sie auf dieser Workstation abgeschlossen haben.
Bearbeiten und prüfen Sie die Umgebungsdatei mit Ihrem bevorzugten Editor:
${EDITOR:-vi} ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.d/open-webui.shRufen Sie die Umgebungsdatei auf:
source ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.shDie Ausgabe sieht etwa so aus:
GDCS_ROOT_HOME=HOME_DIRECTORY_PATH/gdcag-solutions GDCS_IMPLEMENTATION_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/open-weight-models/IMPLEMENTATION GDCS_USER_GUIDE_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/open-weight-models/open-webui
Cluster
Konfigurieren Sie
gdcloud:gdcloud config set core/account "default-user" gdcloud config set core/organization_console_url "${GDC_ZONAL_CONSOLE_URL}" gdcloud config set core/project "${GDC_PROJECT}" gdcloud config set core/zone "${GDC_ZONE}"Authentifizieren Sie sich bei der GDC-Umgebung:
gdcloud auth loginClusteranmeldedaten abrufen:
gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \ --project="${GDC_PROJECT}" \ --standard \ --zone="${GDC_ZONE}"Prüfen Sie, ob die in der Umgebungsdatei referenzierten Inferenz-Back-Ends
Servicevorhanden sind:for url in $(echo "${GDCS_OPEN_WEBUI_OLLAMA_BASE_URLS};${GDCS_OPEN_WEBUI_OPENAI_API_BASE_URLS}" | tr ';' ' '); do host=$(echo "${url}" | sed -E 's#https?://([^/:]+).*#\1#') kubectl get service "${host%%.*}" --namespace="$(echo "${host}" | cut -d. -f2)" --output=wide done
Implementierung
Artefaktmigration
Definieren Sie die Liste der erforderlichen Container-Images für die Lösung:
declare -a GDCS_REGISTRY_IMAGES=( "ghcr.io/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG}" ) export SERIALIZED_IMAGES=$(declare -p GDCS_REGISTRY_IMAGES)Fügen Sie die erforderlichen Container-Images mit dem Skript der Referenzimplementierung in die Artifact Registry ein:
${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
Namespace
Erstellen Sie den Namespace:
kubectl create namespace "${GDCS_WORKLOAD_NAMESPACE}"Fügen Sie die
imagePullSecrethinzu:kubectl create secret docker-registry "${GDCS_HARBOR_K8S_PULL_SECRET}" \ --dry-run=client \ --from-file=.dockerconfigjson=${GDCS_HARBOR_K8S_DOCKER_CONFIG}/config.json \ --namespace="${GDCS_WORKLOAD_NAMESPACE}" \ --output=yaml | kubectl apply -f -Erstellen Sie die
Secretmit dem Sitzungssignaturschlüssel:kubectl create secret generic "${GDCS_OPEN_WEBUI_NAME}" \ --dry-run=client \ --from-literal=WEBUI_SECRET_KEY="${GDCS_OPEN_WEBUI_SECRET_KEY}" \ --namespace="${GDCS_WORKLOAD_NAMESPACE}" \ --output=yaml | kubectl apply -f -
Speicher
Erstellen Sie das Manifest für das
PersistentVolumeClaimfür die Open WebUI-Daten:cat <<EOF > "${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-rwo-pvc.yaml" && echo "Successfully created." || echo "Failed to create!" apiVersion: v1 kind: PersistentVolumeClaim metadata: name: ${GDCS_OPEN_WEBUI_NAME}-rwo spec: accessModes: - ReadWriteOnce resources: requests: storage: ${GDCS_OPEN_WEBUI_PVC_SIZE} storageClassName: standard-rwo volumeMode: Filesystem EOFWenden Sie das Manifest für
PersistentVolumeClaiman:kubectl apply \ --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-rwo-pvc.yaml" \ --namespace="${GDCS_WORKLOAD_NAMESPACE}"
Weboberfläche
Erstellen Sie das Manifest für
ConfigMap,DeploymentundServicevon Open WebUI. Open WebUI wird im Offlinemodus (OFFLINE_MODE) ausgeführt, behält dieseConfigMapals Source of Truth (ENABLE_PERSISTENT_CONFIG=false) bei und deaktiviert die Funktionen, für die ein Internetzugriff erforderlich ist:cat <<EOF > "${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-deployment.yaml" && echo "Successfully created." || echo "Failed to create!" apiVersion: v1 kind: ConfigMap metadata: name: ${GDCS_OPEN_WEBUI_NAME} data: DATA_DIR: "/app/backend/data" ENABLE_COMMUNITY_SHARING: "false" ENABLE_IMAGE_GENERATION: "false" ENABLE_OLLAMA_API: "${GDCS_OPEN_WEBUI_ENABLE_OLLAMA_API}" ENABLE_OPENAI_API: "${GDCS_OPEN_WEBUI_ENABLE_OPENAI_API}" ENABLE_PERSISTENT_CONFIG: "false" ENABLE_SIGNUP: "true" ENABLE_VERSION_UPDATE_CHECK: "false" ENABLE_WEB_SEARCH: "false" OFFLINE_MODE: "true" OLLAMA_BASE_URLS: "${GDCS_OPEN_WEBUI_OLLAMA_BASE_URLS}" OPENAI_API_BASE_URLS: "${GDCS_OPEN_WEBUI_OPENAI_API_BASE_URLS}" OPENAI_API_KEYS: "${GDCS_OPEN_WEBUI_OPENAI_API_KEYS}" PORT: "8080" --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: ${GDCS_OPEN_WEBUI_NAME} name: ${GDCS_OPEN_WEBUI_NAME} spec: replicas: 1 selector: matchLabels: app: ${GDCS_OPEN_WEBUI_NAME} strategy: type: Recreate template: metadata: labels: app: ${GDCS_OPEN_WEBUI_NAME} spec: containers: - envFrom: - configMapRef: name: ${GDCS_OPEN_WEBUI_NAME} - secretRef: name: ${GDCS_OPEN_WEBUI_NAME} image: ${GDCS_HARBOR_PROJECT_URI}/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG} imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 3 httpGet: path: /health port: 8080 periodSeconds: 30 timeoutSeconds: 10 name: open-webui ports: - containerPort: 8080 name: http readinessProbe: failureThreshold: 3 httpGet: path: /health port: 8080 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 resources: limits: cpu: "${GDCS_WORKLOAD_CPU_LIMIT}" memory: "${GDCS_WORKLOAD_MEMORY_LIMIT}" requests: cpu: "${GDCS_WORKLOAD_CPU_REQUEST}" memory: "${GDCS_WORKLOAD_MEMORY_REQUEST}" securityContext: allowPrivilegeEscalation: false startupProbe: failureThreshold: 60 httpGet: path: /health port: 8080 periodSeconds: 10 timeoutSeconds: 5 volumeMounts: - mountPath: /app/backend/data name: data imagePullSecrets: - name: ${GDCS_HARBOR_K8S_PULL_SECRET} volumes: - name: data persistentVolumeClaim: claimName: ${GDCS_OPEN_WEBUI_NAME}-rwo --- apiVersion: v1 kind: Service metadata: name: ${GDCS_OPEN_WEBUI_NAME} spec: ports: - name: http port: 80 protocol: TCP targetPort: 8080 selector: app: ${GDCS_OPEN_WEBUI_NAME} type: LoadBalancer EOFWenden Sie das Manifest für die Open WebUI-
ConfigMap,DeploymentundServicean:kubectl apply \ --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-deployment.yaml" \ --namespace="${GDCS_WORKLOAD_NAMESPACE}"Erstellen Sie das Manifest für die Open WebUI-
NetworkPolicy:cat <<EOF > "${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-netpol.yaml" && echo "Successfully created." || echo "Failed to create!" apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-${GDCS_OPEN_WEBUI_NAME}-ingress namespace: ${GDCS_WORKLOAD_NAMESPACE} spec: ingress: - from: - ipBlock: cidr: 0.0.0.0/0 - namespaceSelector: {} ports: - port: 8080 protocol: TCP podSelector: {} policyTypes: - Ingress EOFWenden Sie das Manifest für die Open WebUI-
NetworkPolicyan:kubectl apply \ --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-netpol.yaml"
Warten Sie, bis der
Podausgeführt wird:watch --color --interval 5 --no-title \ "kubectl get pods --selector=app=${GDCS_OPEN_WEBUI_NAME} \ --namespace=${GDCS_WORKLOAD_NAMESPACE} | GREP_COLORS='mt=01;92' grep -E --color=always -e '^' -e 'Running'"Warten Sie, bis der
Deploymentbereit ist:watch --color --interval 5 --no-title \ "kubectl get deployment/${GDCS_OPEN_WEBUI_NAME} \ --namespace=${GDCS_WORKLOAD_NAMESPACE} | GREP_COLORS='mt=01;92' grep -E --color=always -e '^' -e '1/1 1 1'"Optional: Streamen Sie die Containerlogs, um den Startfortschritt zu überwachen:
kubectl logs deployment/${GDCS_OPEN_WEBUI_NAME} \ --follow \ --namespace="${GDCS_WORKLOAD_NAMESPACE}"
Validierung
Rufen Sie die LoadBalancer-IP-Adresse für Open WebUI ab:
export OPEN_WEBUI_LB_IP=$(kubectl get service/${GDCS_OPEN_WEBUI_NAME} --namespace="${GDCS_WORKLOAD_NAMESPACE}" --output=jsonpath='{.status.loadBalancer.ingress[*].ip}') echo "OPEN_WEBUI_LB_IP=${OPEN_WEBUI_LB_IP}"Prüfen Sie die Integritäts- und Versionsendpunkte mit dem Load Balancer:
curl --show-error --silent http://${OPEN_WEBUI_LB_IP}/health && echo curl --show-error --silent http://${OPEN_WEBUI_LB_IP}/api/version && echoDie Ausgabe sieht etwa so aus:
{"status":true} {"version":"0.11.3"}Prüfen Sie die Status- und Versionsendpunkte mithilfe der Portweiterleitung:
kubectl port-forward service/${GDCS_OPEN_WEBUI_NAME} \ --namespace="${GDCS_WORKLOAD_NAMESPACE}" 8080:80 & PF_PID=$! sleep 2 curl --show-error --silent http://127.0.0.1:8080/health && echo curl --show-error --silent http://127.0.0.1:8080/api/version && echo kill ${PF_PID}Prüfen Sie, ob Open WebUI die Inferenz-Backends erreichen kann:
kubectl exec deployment/${GDCS_OPEN_WEBUI_NAME} \ --namespace="${GDCS_WORKLOAD_NAMESPACE}" \ -- sh -c 'for url in $(echo "${OLLAMA_BASE_URLS};${OPENAI_API_BASE_URLS}" | tr ";" " "); do case "${url}" in *"/v1") echo "${url}/models"; curl --max-time 10 --show-error --silent "${url}/models" | head -c 300; echo;; *) echo "${url}/api/tags"; curl --max-time 10 --show-error --silent "${url}/api/tags" | head -c 300; echo;; esac; done'Öffnen Sie
http://${OPEN_WEBUI_LB_IP}in einem Browser und erstellen Sie das erste Konto. Das erste erstellte Konto wird zum Administratorkonto. Wählen Sie in der Chatansicht ein Modell aus und senden Sie einen Prompt.
Vorgänge
Inferenz-Backends hinzufügen oder ändern
Aktualisieren Sie
GDCS_OPEN_WEBUI_OLLAMA_BASE_URLSoderGDCS_OPEN_WEBUI_OPENAI_API_BASE_URLSinenv.d/open-webui.sh, laden Sie die Umgebungsdatei und führen Sie den Manifestschritt in der Weboberfläche noch einmal aus. Wenden Sie dann das Manifest an und starten Sie Open WebUI neu. DieConfigMapwird bei jedem Start gelesen, da die persistente Konfiguration deaktiviert ist:kubectl apply \ --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-deployment.yaml" \ --namespace="${GDCS_WORKLOAD_NAMESPACE}" kubectl rollout restart deployment/${GDCS_OPEN_WEBUI_NAME} \ --namespace="${GDCS_WORKLOAD_NAMESPACE}"
Upgrade
Legen Sie die neue
GDCS_OPEN_WEBUI_IMAGE_TAGin der Umgebungsdatei fest, rufen Sie sie auf, fügen Sie das neue Image hinzu und führen Sie ein Rollout derDeploymentdurch:source ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.sh declare -a GDCS_REGISTRY_IMAGES=( "ghcr.io/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG}" ) export SERIALIZED_IMAGES=$(declare -p GDCS_REGISTRY_IMAGES) ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh kubectl set image deployment/${GDCS_OPEN_WEBUI_NAME} \ open-webui="${GDCS_HARBOR_PROJECT_URI}/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG}" \ --namespace="${GDCS_WORKLOAD_NAMESPACE}"
Sicherung
Erstellen Sie ein
VolumeSnapshotdes Daten-Volumes (dasstandardVolumeSnapshotClassist auf GDC-Standardclustern verfügbar):cat <<EOF | kubectl apply --namespace="${GDCS_WORKLOAD_NAMESPACE}" -f - apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshot metadata: name: ${GDCS_OPEN_WEBUI_NAME}-$(date +%Y%m%d-%H%M) spec: source: persistentVolumeClaimName: ${GDCS_OPEN_WEBUI_NAME}-rwo volumeSnapshotClassName: standard EOF
Fehlerbehebung
| Symptom | Wahrscheinliche Ursache | Aktion |
|---|---|---|
| In der Chatansicht wird kein Modell angeboten | Backend-Service-Adresse falsch, Backend nicht bereit oder Backend-NetworkPolicy lässt den Open WebUI-Namespace nicht zu |
Führen Sie den Schritt zur Backend-Überprüfung unter Validierung aus. Prüfen Sie das Backend Deployment und die zugehörige NetworkPolicy. |
Pod Neustarts während des Startvorgangs |
Langsamer erster Start am PersistentVolume |
Prüfen Sie kubectl describe pod. Die startupProbe erlaubt 10 Minuten. |
| Hochladen von Dokumenten (RAG) schlägt fehl | Der Offlinemodus blockiert den Download des Standardeinbettungsmodells | Konfigurieren Sie RAG_EMBEDDING_ENGINE=ollama mit einem von Ollama bereitgestellten Einbettungsmodell oder lassen Sie RAG deaktiviert. |
LoadBalancer-IP-Adresse bleibt <pending> oder ist nicht erreichbar |
Load Balancer in der Umgebung nicht verfügbar oder ProjectNetworkPolicy fehlt |
Verwenden Sie den Schritt zur Validierung der Portweiterleitung. Bitten Sie den Project NetworkPolicy Admin um eine ProjectNetworkPolicy. |
Sitzung nach einem Neustart von Pod ungültig |
WEBUI_SECRET_KEY geändert |
Secret stabil halten; aus secrets/open_webui_secret_key wiederherstellen |
Bereinigen
Löschen Sie die Open WebUI-Ressourcen:
kubectl delete namespace "${GDCS_WORKLOAD_NAMESPACE}"Löschen Sie die lokalen Dateien:
rm -rf ${HOME}/gdcag-solutions/open-weight-models/open-webui
Zusätzliche Materialien
- Open WebUI-Dokumentation
- Referenz zu Umgebungsvariablen für Open WebUI
- Ollama OpenAI-Kompatibilität
- OpenAI-kompatibler vLLM-Server