SUSE AI FactoryでのOpen WebUI導入手順解説 〜AirGap環境へのOpen WebUI・Ollama構築〜

はじめに

今回は、SUSE AI Factory で提供されている、ブラウザからLLMとチャット形式で対話できるWebインターフェースのOpen WebUIの紹介をします。

本記事では最初にOpen WebUIの概要を説明し、その後、AirGap環境のRancherにOpen WebUIを構築する方法を解説します。

Open WebUIとは

Open WebUIは、LLMとチャット形式で対話するためのセルフホスト型のWebインターフェースです。

主な特徴は以下になります。

  • ブラウザからGUI上でチャット画面を利用することが可能
  • 適当なドキュメントを参照して回答させるRAGや文書作成のAIサポートなど、AIを利用した機能が豊富にある
  • 外部のツールとの連携により機能の拡張が可能
  • インターネット接続環境だけでなく、インターネット非接続環境でも動作するように設計されており、社外にデータを公開したくないといったセキュリティ要件がある場合でも導入できる
  • 推論エンジンのOllamaおよびOpenAI互換APIをサポートしており、利用目的に合わせてモデルを切り替えて動作させることが可能

つまり、Open WebUIは、自分たちの要件に合わせて構築でき、多様なモデルをブラウザ画面上で使い分けられる、統合的なWebインターフェースです。詳細な機能については今後のブログで紹介します。

Open WebUIの設定方法

設定概要

今回利用するSUSE AIのHelm チャートでは、推論エンジンであるOllamaが Open WebUIとセットでパッケージ化されているため、まとめて同時に構築します。

Open WebUI構築の事前準備として以下の手順を実行します。

  • Open WebUIのデータを保存するPostgreSQLの構築
  • NFSディレクトリ上へのモデルデータの配置
    • 利用するモデルはGemma4:12B, embeddinggemma:300mの2種類
  • モデルデータを保存するNFSディレクトリと連携するPVの作成

その後、Open WebUI・Ollamaのインストールおよび管理者アカウントの作成まで行います。

本記事で構築するコンポーネントのバージョンは次のとおりです。

コンポーネント名バージョン
PostgreSQL18.6-16.2
Ollama0.32.14-11.78
Open WebUI0.6.41-14.20

前提条件

基本的な前提条件は、過去の記事をご参照ください。

上記に加えて、以下の条件が追加されます。

  • 作業用端末にNFSを準備して、NFS Provisioner等でStorageClassとして利用できる状態になっていること
  • SUSE AI Factoryがインストール済みであること

Open WebUI用のPostgreSQL構築

コンテナレジストリのプロジェクト作成

PostgreSQLのHelmチャートとコンテナイメージを配置するためのプロジェクトは以下のとおりです。

プロジェクト名用途
postgresql-chartPostgreSQLのHelmチャート配置先
suse-aiPostgreSQLのコンテナイメージ配置先

suse-aiは前回のブログで作成しているので、postgresql-chartのみ新規作成します。

コンテナレジストリにPostgreSQLのHelmチャート・コンテナイメージを登録

作業用端末で以下のコマンドを実行し、PostgreSQLのHelmチャートとコンテナイメージをコンテナレジストリへ登録します。

# PostgreSQLのHelmチャートをダウンロード
$ helm pull oci://dp.apps.rancher.io/charts/postgresql --version 0.8.0
# 出力例
Pulled: dp.apps.rancher.io/charts/postgresql:0.8.0
Digest: sha256:f7785fb03cf1b7924411366c07f215bb54324b974d9bf8c875f8b35b66ed2e7d

# Helmチャートをコンテナレジストリに登録
$ helm push postgresql-0.8.0.tgz oci://<コンテナレジストリのドメイン>/postgresql-chart --insecure-skip-tls-verify
# 出力例
Pushed: <コンテナレジストリのドメイン>/postgresql-chart/postgresql:0.8.0
Digest: sha256:83bca4535238e17dacef2cb36a080d8e9cdfb835711612f7442f28f108868a48

# PostgreSQLで使用するコンテナイメージをコンテナレジストリに登録
$ skopeo copy \
docker://dp.apps.rancher.io/containers/postgresql:18.6-16.2 \
docker://<コンテナレジストリのドメイン>/suse-ai/containers/postgresql:18.6-16.2
# 出力例
Getting image source signatures
Copying blob b98a90725c89 done   |
Copying blob f9f0dbd5b8f1 skipped: already exists
Copying config 618df7c397 done   |
Writing manifest to image destination

# PostgreSQLで使用するコンテナイメージをコンテナレジストリに登録
$ skopeo copy \
docker://dp.apps.rancher.io/containers/bci-micro:15.7-61.11 \
docker://<コンテナレジストリのドメイン>/suse-ai/containers/bci-micro:15.7-61.11

Rancher管理UIへのOCIリポジトリ登録

Rancher管理UIにログインし、「downstream」からDownstreamクラスターの管理画面に遷移します。

「Apps」→「Repositories」に移動します。

「Add Repository」から以下の設定値で「OCI Repository」の登録をします。

設定項目設定値
TargetOCI Repository
Name任意のリポジトリ名
OCI Repository Host URLoci://<コンテナレジストリのドメイン>/postgresql-chart
AuthenticationCreate an HTTP Basic Auth Secret
Username<コンテナレジストリのユーザー名>
Password<コンテナレジストリのパスワード>
Skip TLS Verifications有効化

PostgreSQLのインストール

作業用端末からkubectlでDownstreamクラスターに接続し、以下のコマンドでPostgreSQLのパスワードを設定したSecretを作成します。

# PostgreSQL用のNamespaceを作成
$ kubectl create ns postgresql
# 出力例
namespace/postgresql created

# PostgreSQL用のNamespaceにパスワードを設定したSecretを作成
$ kubectl create secret generic postgresql-secret \
  --from-literal=postgresPassword="<任意の管理者パスワード>" \
  --from-literal=password="<任意のDBユーザーパスワード>" \
  --from-literal=replicationPassword="<任意のレプリケーションパスワード>" \
  -n postgresql
# 出力例
secret/postgresql-secret created

Rancher管理UIのDownstreamクラスター管理画面から、「Apps」→「Charts」に移動し、「postgresql」のHelmチャートインストールページに移動します。

「Install this version」から以下の設定値でPostgreSQLをインストールします。

設定項目 設定値
Namespace postgresql
Name postgresql
Edit YAML 以下のvalues.yamlを参照
※PVのStorageClassはNFSを指すようにします。
# values.yaml
# 認証情報および既存Secretの参照設定
auth:
  database: "Open WebUI"
  username: "suse_ai_user"
  existingSecret: "postgresql-secret"
  passwordKey: password
  postgresPasswordKey: postgresPassword
  postgresUsername: postgres
  replicationPasswordKey: replicationPassword
  replicationUsername: replication

# プライベートレジストリ上のコンテナイメージ指定
images:
  postgresql:
    registry: <コンテナレジストリのドメイン>
    repository: suse-ai/containers/postgresql
    tag: 18.6-16.2
  volume-permissions:
    registry: <コンテナレジストリのドメイン>
    repository: suse-ai/containers/bci-micro
    tag: 15.7-61.11

# 永続ボリューム(PV)の指定
persistence:
  enabled: true
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  storageClassName: "<NFSのstorageClassName>"

作業用端末からkubectlでDownstreamクラスターに接続し、以下のコマンドでPostgreSQLのPodが起動していることを確認します。

$ kubectl get pod -n postgresql
# 出力例
NAME                        READY   STATUS    RESTARTS   AGE
postgresql-0-1790918761-0   1/1     Running   0          57s

モデルデータの配置

作業用端末のNFSディレクトリ上にモデルデータ配置用ディレクトリを作成

作業用端末で以下のコマンドを実行し、モデルデータ配置用のディレクトリを作成します。

$ mkdir /nfs/ollama-models
$ sudo chmod 777 /nfs/ollama-models

モデルデータをダウンロード

作業用端末で以下のコマンドを実行し、前手順で作成したディレクトリにモデルデータをダウンロードします。

$ cd /nfs/ollama-models

# models_download.shのファイル内容をコピーする
$ vi models_download.sh

# モデルをダウンロードするスクリプトを実行
$ bash ./models_download.sh
# 出力例
==========================================
Processing: gemma4:12b
==========================================
Downloading manifest...
  [DOWNLOADING] sha256-e5ca99f918964e7d5a912f974eae708ae59370883a5b182fc0660fe7adf3f0e4 ...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
...略
Download complete

# modelsディレクトリ配下にblobs・manifestsの2つのディレクトリが作成されていることを確認する
$ ls /nfs/ollama-models/models
# 出力例
blobs  manifests

models_download.shは以下のmodels_download.shを参照してください。

通常はOllamaはインターネット上のOllama公式レジストリから直接モデルを取得します。しかし、AirGap環境では公式レジストリから直接モデルを取得できないので、このスクリプトを用いて、公式レジストリからモデルファイルを作業用端末のNFSディレクトリに直接ダウンロードします。そのNFSディレクトリをPV連携することで、間接的にAirGap環境のOllamaにモデルをデプロイすることが可能になります。

#!/bin/bash
# models_download.sh
set -e

# 対象モデルのリスト (形式 "リポジトリ名:タグ")
MODELS=(
  "gemma4:12b"
  "embeddinggemma:300m"
)

# 保存先ベースディレクトリの作成
mkdir -p ./models/blobs

for model in "${MODELS[@]}"; do
  repo=$(echo "$model" | cut -d':' -f1)
  tag=$(echo "$model" | cut -d':' -f2)

  echo "=========================================="
  echo "Processing: ${repo}:${tag}"
  echo "=========================================="

  # 1. 該当モデルの認証トークンを取得
  TOKEN=$(curl -s "https://registry.ollama.ai/v2/token?service=registry.ollama.ai&scope=repository:library/${repo}:pull" | jq -r .token)

  # 2. マニフェスト用ディレクトリの作成と取得
  manifest_dir="./models/manifests/registry.ollama.ai/library/${repo}"
  mkdir -p "$manifest_dir"
  manifest_path="${manifest_dir}/${tag}"

  echo "Downloading manifest..."
  curl -s -H "Authorization: Bearer $TOKEN" \
    -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
    "https://registry.ollama.ai/v2/library/${repo}/manifests/${tag}" \
    -o "$manifest_path"

  # 3. Blob (モデル重み・構成ファイル) のダウンロード
  digests=$(jq -r '.config.digest, .layers[].digest' "$manifest_path")

  for digest in $digests; do
    filename=$(echo "$digest" | sed 's/:/-/')
    blob_path="./models/blobs/$filename"

    if [ -f "$blob_path" ]; then
      echo "  [SKIP] $filename (すでに存在します)"
    else
      echo "  [DOWNLOADING] $filename ..."
      curl -L -H "Authorization: Bearer $TOKEN" \
        "https://registry.ollama.ai/v2/library/${repo}/blobs/${digest}" \
        -o "$blob_path"
    fi
  done
done

echo ""
echo "Download complete"

Open WebUI・Ollamaの構築

PostgreSQL認証用のSecretを作成

作業用端末からkubectlでDownstreamクラスターに接続し、以下のコマンドでPostgreSQL認証用のSecretを作成します。

パスワードはPostgreSQL用のSecretを作成した際に設定した値と同じ設定値を入力する。

# Open WebUI用のNamespaceを作成
$ kubectl create ns open-webui-system
# 出力例
namespace/open-webui-system created

# Open WebUI用のNamespaceにPostgreSQL認証用のSecretを作成
$ kubectl create secret generic postgresql-secret \
  --from-literal=password="<PostgreSQL用のSecretに設定したDBユーザーパスワード>" \
  -n open-webui-system
# 出力例
secret/postgresql-secret created

Ollamaへのモデルデータ連携用PVを作成

作業用端末で作業用のディレクトリを作成します。

$ mkdir ollama
$ cd ollama

モデルデータを配置したディレクトリを指定したPV設定ファイルollama-model-pv.yamlを作成します。

# ollama-model-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: ollama-models-pv
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: ""
  nfs:
    server: <作業用端末のIPアドレス>
    path: "/nfs/ollama-models"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ollama-models-pvc
  namespace: open-webui-system
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 50Gi
  storageClassName: ""
  volumeName: ollama-models-pv

作業用端末からkubectlでDownstreamクラスターに接続し、以下のコマンドでPV・PVCを作成します。

$ kubectl apply -f ollama-model-pv.yaml
# 出力例  
persistentvolume/ollama-models-pv created
persistentvolumeclaim/ollama-models-pvc created

Open WebUIのインストール

SUSE AI Factoryの管理UIから「Apps」→「Open WebUI」を選択します。

以下の設定値でOpen WebUIをインストールします。

設定項目設定値
Instance Nameopen-webui
Namespaceopen-webui-system
Chart Nameopen-webui
Version8.19.1
Deployment TypeFleet Bundle
Select Target Cluster(s)downstream
Configuration以下のopen-webui-values.yamlを参照
# open-webui-values.yaml
affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        preference:
          matchExpressions:
            # control-plane ラベルが存在しないノードの優先度を上げる
            - key: node-role.kubernetes.io/control-plane
              operator: DoesNotExist

replicaCount: 2  # レプリカ追加

image:
  registry: <コンテナレジストリのドメイン>/suse-ai
  repository: containers/open-webui
  tag: 0.6.41-14.20
  pullPolicy: IfNotPresent

ingress:
  enabled: true
  class: traefik
  host: <Open WebUIのドメイン>
  tls: false

persistence:
  enabled: true
  accessModes:
    - ReadWriteMany
  size: 2Gi
  storageClass: <nfsのstrorageclassname> 

extraEnvVars:
  - name: WEBUI_SECRET_KEY
    value: "<ランダムな値を設定>"
  - name: DATABASE_TYPE
    value: "postgres"
  - name: DATABASE_HOST
    value: "postgresql.postgresql.svc.cluster.local"
  - name: DATABASE_PORT
    value: "5432"
  - name: DATABASE_NAME
    value: "Open WebUI"
  - name: DATABASE_USER
    value: "suse_ai_user"
  - name: DATABASE_PASSWORD
    valueFrom:
      secretKeyRef:
        name: postgresql-secret
        key: password
  
ollama:
  enabled: true
  fullnameOverride: open-webui-ollama
  image:
    registry: <コンテナレジストリのドメイン>/suse-ai
    repository: containers/ollama
    tag: "0.32.14-11.78"
  ollama:
    gpu:
      enabled: true
      type: "nvidia"
      number: 1
  ingress:
    enabled: true
    className: traefik
    hosts:
      - host: <Ollamaのドメイン>
        paths:
          - path: /
            pathType: Prefix
  extraEnv:
    - name: OLLAMA_MAX_LOADED_MODELS # モデルデータの最大同時ロード数
      value: "2"
    - name: OLLAMA_NUM_PARALLEL # 4リクエストまで同時処理できるようにする
      value: "4"
  persistentVolume:
    enabled: true
    existingClaim: "ollama-models-pvc" # モデルデータ配置用PVを割り当て
  resources:
    requests:
      cpu: "2"
      memory: "4Gi"
    limits:
      cpu: "4"
      memory: "8Gi"
  nodeSelector:
    accelerator: nvidia-gpu
  tolerations:
    - key: "nvidia.com/gpu"
      operator: "Equal"
      value: "dedicated"
      effect: "NoSchedule"

websocket:
  enabled: true
  manager: redis
  url: redis://open-webui-redis:6379/0
  redis:
    name: open-webui-redis
    image:
      registry: <コンテナレジストリのドメイン>/suse-ai
      repository: containers/redis
      tag: 8.4.0-2.1
      pullPolicy: IfNotPresent
    affinity:
      nodeAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            preference:
              matchExpressions:
                - key: node-role.kubernetes.io/control-plane
                  operator: DoesNotExist

作業用端末からkubectlでDownstreamクラスターに接続し、以下のコマンドでOpen WebUI・OllamaのPodが起動していることを確認します。

$ kubectl get pod -n open-webui-system
# 出力例
NAME                                      READY   STATUS             RESTARTS   AGE
open-webui-0                              1/1     Running            0          39m
open-webui-1                              1/1     Running            0          39m
open-webui-ollama-7f7847cd5f-vtj68        1/1     Running            0          39m
open-webui-pipelines-754467f8b8-dgc76     1/1     Running            0          39m
open-webui-redis-774866f675-pdn45         1/1     Running            0          39m

Open WebUIのアカウント作成

ブラウザからOpen WebUIにアクセスし、アカウントの作成を行います。

※初回登録のアカウントが管理者アカウントとなります。

アカウント作成後、Open WebUIのチャット画面にログインできることを確認します。

おわりに

本記事ではOpen WebUIについての概要とAirGap環境での設定・構築方法について紹介しました。これでCLIではなく、GUIで便利にAIを利用することが可能になります。

次回はSUSE AI Factory で提供されている推論エンジンの1つであるOllamaの仕組みと特徴を解説したいと思います。

参考

 

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です