Kubernetes
Libre WebUI には、helm/libre-webui に Helm チャートが同梱されています。
Kubernetes 上の Work
Work は Kubernetes 上でネイティブに動作します。Docker デーモン、CLI、ソケットは一切使用しません。 インストール時に有効化します。
helm install libre-webui ./helm/libre-webui --set work.enabled=true
これによりバックエンドが WORK_RUNTIME_BACKEND=kubernetes に切り替わり、次のリソースが作成されます。
- 専用のサンドボックス名前空間(
work.namespace、既定値libre-webui-work)。実行中のサンドボックスごとに 1 個の Pod、タスクのワークスペースごとに 1 個の PersistentVolumeClaim(work.workspaceSize、既定値5Gi)を 保持します。これは実際のタスク単位のディスククォータです。名前付き Work ポリシーでは、そのポリシーから作成する タスクに別のサイズを設定できます。 - 名前空間内だけを対象とする Role と RoleBinding。バックエンドの ServiceAccount に、その名前空間内で
pods(get/list/create/delete)、pods/exec(get/create)、persistentvolumeclaims(get/list/create/delete)だけを許可します。Secret への権限もクラスター全体の権限もありません。 この付与が Docker ソケットを完全に置き換えます。サンドボックスの仕様でホストパスをマウントできないことは、 アプリケーションではなく API サーバーが強制します。 - すべてのサンドボックス通信を既定で拒否する NetworkPolicy。プレビューポートへの ingress はバックエンドからのみ許可し、
ネットワークが有効なサンドボックスには、
work.networkPolicy.blockedEgressCidrsを除くインターネットへの egress を許可します。 既定の除外対象はプライベートアドレス範囲、一部のマネージドクラスターが Pod と Service の CIDR に使う CGNAT 範囲、 クラウドメタデータ用のリンクローカル範囲です。お使いのクラスターの Pod/Service CIDR が対象に含まれることを確認してください。 サンドボックスの DNS はkube-systemに対してのみ許可されます。ノードローカル DNS を実行するクラスターでは、 独自の DNS 例外設定が必要です。
サンドボックスは root 以外のユーザーで、読み取り専用のルートファイルシステム、全ケイパビリティの削除、
seccomp RuntimeDefault、ServiceAccount トークンなしの状態で実行されます。ファイル、コマンド、git、対話型ターミナルは
API サーバーの exec サブリソースを経由します。プレビューは署名付き same-origin プロキシを通じてサンドボックスの
Pod IP から配信されるため、バックエンドをクラスター内で実行する必要があります(チャートの標準トポロジー)。
このバックエンドではホストフォルダーのワークスペースに対応しません。
運用上の注意が 2 点あります。NetworkPolicy を強制するには、それを実装する CNI が必要です (Calico、Cilium、最近の kind リリース、大半のマネージドクラスターの既定構成が対応)。サンドボックスの分離が有効だと 判断する前に、お使いのクラスターで確認してください。CI のエンドツーエンドテストスイートは、実行先クラスターで 強制されているかを報告します。また、ノードのコンテナランタイムソケットを WebUI Pod へ絶対にマウントしないでください。 Kubernetes バックエンドは、まさにそれを不要にするためのものです。
インストール
helm install libre-webui oci://ghcr.io/libre-webui/charts/libre-webui
既定のチャートは、永続ストレージと同梱の Ollama サービスを使って Libre WebUI をデプロイします。
0.14.1 への移行版は、検証済みのマルチアーキテクチャ対応イメージダイジェストに固定されています。それ以降のチャートは、
一致するセマンティックバージョンの appVersion イメージを既定値とします。意図的に別のイメージを使う場合に限り、
image.tag または image.digest を明示的に設定してください。空でない image.tag は移行用ダイジェストより優先されます。
既定の solo プロファイルは、意図的に停止する場合の replicaCount: 0 と、通常運用の replicaCount: 1 を受け付けます。
SQLite、ローカルファイル、プロセス内の調整機能は、複数の Pod の背後で安全に使えないため、それより大きい値と
HorizontalPodAutoscaler は拒否されます。レプリカ数が 0 のリリースでもコントロールプレーンのリソースは作成されますが、
Libre WebUI の通信は処理しません。
複数のレプリカを使う場合は、完全な team プロファイルを設定します。このプロファイルは PostgreSQL/PGVector、
S3-compatible blob storage、Redis、独立した永続ワーカーを使用します。共有バックエンドとローカルバックエンドを
部分的に混在させる構成はチャートが拒否します。次のような保護された values ファイルから始めてください。
replicaCount: 3
env:
LIBRE_PLATFORM_MODE: team
DATABASE_BACKEND: postgres
DATABASE_SSL_MODE: verify-full
POSTGRES_MIGRATION_MODE: apply
POSTGRES_POOL_MAX: 10
POSTGRES_CONNECT_TIMEOUT_MS: 5000
POSTGRES_IDLE_TIMEOUT_MS: 30000
POSTGRES_STATEMENT_TIMEOUT_MS: 30000
POSTGRES_MIGRATION_LOCK_TIMEOUT_MS: 60000
OLLAMA_TIMEOUT: 300000
OLLAMA_LONG_OPERATION_TIMEOUT: 900000
OLLAMA_MAX_CONTEXT: 32768
BLOB_STORE_BACKEND: s3
VECTOR_STORE_BACKEND: pgvector
COORDINATION_BACKEND: redis
JOB_WORKER_MODE: external
STORAGE_ENCRYPTION_ACTIVE_KEY_ID: active
S3_BUCKET: libre-blobs
S3_REGION: us-east-1
S3_BLOB_PREFIX: libre/blobs
worker:
replicaCount: 1
secrets:
databaseUrl: postgresql://libre:replace-me@postgres.example/libre
redisUrl: rediss://redis.example:6379/0
jwtSecret: '<one-stable-high-entropy-secret-for-every-replica>'
encryptionKey: '<legacy-64-character-lowercase-hex-key>'
storageEncryptionKeys: '{"legacy":"<legacy-64-character-lowercase-hex-key>","active":"<active-64-character-lowercase-hex-key>"}'
s3AccessKeyId: replace-me
s3SecretAccessKey: replace-me
secrets.encryptionKey は legacy の項目と完全に一致する必要があり、キーマップには
STORAGE_ENCRYPTION_ACTIVE_KEY_ID も含める必要があります。secrets.jwtSecret は、すべてのアプリ Pod とワーカー Pod で
共有する、固定された高エントロピーの 1 つの値にしてください。セッションが Pod ごとに生成される値へ依存しないよう、
チャートはこの値がない team モードを拒否します。マネージド PostgreSQL では検証付き TLS を維持し、databaseUrl に
ドライバーの TLS パラメーターを追加しないでください。プールの上限はアプリ Pod とワーカー Pod のそれぞれに適用されるため、
少なくとも (replicaCount + worker.replicaCount) * POSTGRES_POOL_MAX 個のデータベース接続に
運用上の余裕を加えて確保してください。保護した values ファイルを使ってインストールします。
helm upgrade --install libre-webui \
oci://ghcr.io/libre-webui/charts/libre-webui \
--values /absolute/path/to/libre-team-values.yaml
このファイルをコミットしたり、--set で本番用シークレットを渡したりしないでください。保護された暗号化 values ワークフローで
保存します。モデルプロバイダーと Work サンドボックス Pod は個別にスケールしてください。work.enabled=true の場合、外部の
team ワーカーはアプリ Pod と同じランタイムイメージ、StorageClass、work.env の上限を受け取ります。
ドキュメントの埋め込み、永続チャット、Work の実行でプロバイダー呼び出しを処理するため、ワーカーにはアプリと同じ
解決済み Ollama エンドポイント、リクエストタイムアウト、自動的に採用する最大コンテキストも渡されます。
稼働中の team アプリケーション(正の replicaCount、またはオートスケーリングが有効)には、少なくとも 1 個の外部ワーカーが
必要です。チャートはワーカーが 0 の構成をインストール前に拒否します。完全に停止する場合は、replicaCount と
worker.replicaCount の両方を 0 に設定します。アプリの数だけを 0 にするのは、意図的なワーカー専用の
ドレイン/復旧モードです。Web 通信は処理されませんが、ワーカーはキューにある永続処理を続けます。
Team のアップグレードとスキーマ互換性
Libre はスキーマバージョンの完全一致ポリシーを採用しており、バージョン混在または無停止のデータベースアップグレードには
対応しません。アプリケーションと外部ワーカーの Deployment はそれぞれ Recreate を使用し、1 つの Deployment 内で
旧 Pod と新 Pod が重なるのを防ぎます。Kubernetes は 2 つの Deployment を 1 つのアップグレード境界としては調整しません。
アップグレード前に、新規 ingress を停止し、実行中の永続ジョブと Work ジョブを完了させるかキャンセルし、
両方の旧 Deployment を 0 にスケールします。検証済みの team バックアップを取得し、旧アプリ Pod とワーカー Pod が
すべて終了したことを確認してください。その後に限り、POSTGRES_MIGRATION_MODE=apply を指定してリリースを
アップグレードします。1 つの新しいプロセスが PostgreSQL の advisory leader lock を保持し、ほかのすべての新しいプロセスは
待機して、同じ migration ledger を検証します。ロールバックする場合は、以前の検証済みバックアップを、空の PostgreSQL/S3
ターゲットへ復元してください。厳密に対応していないスキーマに古いバイナリを接続してはいけません。この手順では、
意図的なサービス中断が発生します。
ローカルからアクセスする
kubectl port-forward svc/libre-webui 8080:8080
http://localhost:8080 を開きます。
外部 Ollama
既存の Ollama エンドポイントを使用します。
helm install libre-webui oci://ghcr.io/libre-webui/charts/libre-webui \
--set ollama.bundled.enabled=false \
--set ollama.external.enabled=true \
--set ollama.external.url=http://my-ollama:11434
シークレット
本番環境では、固定の JWT シークレットと暗号化キーを設定します。既定では、空でない secrets.* の値から
<release>-libre-webui-secrets を作成します。
helm upgrade --install libre-webui \
oci://ghcr.io/libre-webui/charts/libre-webui \
--set-string secrets.jwtSecret="$(openssl rand -hex 64)" \
--set-string secrets.encryptionKey="$(openssl rand -hex 32)"
運用者が管理する Secret では、secrets.existingSecret を設定します。この場合、チャートは Secret を生成せず、
アプリケーション Pod とワーカー Pod の両方が指定されたオブジェクトを参照します。
secrets:
existingSecret: libre-webui-runtime
リリースをインストールする前に、その Secret を作成してください。jwt-secret と encryption-key を含める必要があります。
team モードでは、さらに database-url、redis-url、storage-encryption-keys が必要です。チャートが認識する任意のキーは、
session-secret、s3-access-key-id、s3-secret-access-key、s3-session-token です。
GitHub と Hugging Face の OAuth では、対応する空でない secrets.githubClientId または secrets.huggingfaceClientId の
値で連携を有効にすると、指定した Secret から *-client-id と *-client-secret の組も読み取れます。
チャートは意図的に Secret の値を検証またはコピーしません。必要なキーがない場合、Pod は起動できません。
本番環境の自動化では、external-secrets コントローラーとともに secrets.existingSecret を使用するか、
暗号化した Helm values ワークフローから固定値を指定する方法を推奨します。コマンドラインの --set 値はプロセスの調査で
露出する可能性があり、Helm リリースのメタデータに保持されます。プロバイダーの認証情報は意図的なチャート拡張で追加するか、
WebUI でユーザー単位の認証情報を設定してください。
アプリケーションと worker の NetworkPolicy
アプリケーションと、team モードでは外部の永続ワーカーに対する ingress ポリシーを生成するには、
networkPolicy.enabled=true を設定します。
networkPolicy:
enabled: true
アプリケーションが受け付ける ingress は HTTP コンテナポートのみです。ワーカーは ingress を一切受け付けません。 これらのポリシーは egress を制限しません。アプリケーションとワーカープロセスは、設定済みの PostgreSQL、Redis、S3、 Ollama、ツール、モデルプロバイダーのエンドポイントに引き続き接続する必要があり、それらのサービスをどこに配置するかは 運用者が決定します。
この設定は、Work サンドボックス名前空間の default-deny ポリシーを制御し、Work を有効にすると既定で有効になる
work.networkPolicy.enabled とは別です。どちらの設定にも、Kubernetes NetworkPolicy を実際に強制する CNI が必要です。
オブジェクトを生成しただけでは、ネットワーク分離が成立している証明にはなりません。
永続化
Libre WebUI のデータ PVC と Ollama モデル PVC を永続ストレージに配置します。Libre WebUI のデータボリュームと暗号化キーは一緒にバックアップしてください。
Work タスクのワークスペースは Libre WebUI のデータ PVC ではなく、サンドボックス名前空間内の独自 PVC に保存されます。 Work を完全に復旧するには、データベース(タスクの所有権、リソース名、実行)とこれらの PVC の両方が必要です。 同じポリシーのもとで一緒にバックアップしてください。
Ingress
公開アクセスでは、HTTPS を使う ingress を設定し、チャートから正確なブラウザーオリジンを指定します。
helm upgrade libre-webui \
oci://ghcr.io/libre-webui/charts/libre-webui \
--reuse-values \
--set env.TRUST_PROXY=1 \
--set-string env.CORS_ORIGIN=https://your-domain.example
TRUST_PROXY は正確なホップ数であり、真偽値ではありません。チャートの安全な既定値は 0 で、転送された
クライアントアドレスを無視します。Libre へ直接接続する ingress プロキシが 1 個だけの場合に限り 1 を使用してください。
それより長い固定チェーンでは、信頼するロードバランサー/プロキシのホップをすべて数え、そのチェーンを迂回して Service に
到達できないようにします。数が小さすぎるとプロキシアドレスのもとにクライアントがまとめられ、共有のログイン制限を
使い切る可能性があります。大きすぎると、クライアントが指定したアドレスを信頼してしまう可能性があります。
チャートが受け付けるのは 0 から 16 までで、上限のない true は決して受け付けません。この値は HTTP アプリケーション Pod にだけ送られます。
現在のチャートでは、BASE_URL と OAuth callback URL の値は公開されていません。OAuth を使うデプロイでは、
チャートを拡張するか Deployment にパッチを適用してこれらの変数を設定する必要があります。callback URL は
公開ドメインと一致させてください。
リソース計画
クラスター内でローカル Ollama を使用する場合は、実行予定のモデルに十分なメモリと GPU 容量があるノードに Ollama Pod をスケジュールします。クラスターに専用の Ollama または推論サービスがすでにある場合は、通常、外部 Ollama のほうが簡単です。