【完全ガイド】Google CloudでプライベートなChatGPT「Open WebUI」をセキュアに構築する

こんにちわ。 GSです。

今回はGoogle CloudでOpen WebUIを構築する方法を解説します。

本記事では、一つひとつのgcloudコマンドを実行しながらGoogle Cloud上にプライベートなAIチャット環境「Open WebUI」を構築していきます。Terraformのような一括デプロイではなく、各ステップを順に進めることで、Cloud Run、Cloud Storage、Cloud SQLなどのサービスがどのように連携するのかを体系的に理解できます。コマンドを実行し、結果を確認する過程を通じて、Google Cloudの基本から応用まで自然と身につき、最終的にはセキュアで拡張性のあるAI環境を自分の手で構築できる実力が養われます。初心者から中級者まで、実際に手を動かしながらクラウド技術を習得したいエンジニアにぴったりの実践ガイドです。

先に結論

この記事でわかること、得られること。

  • Open WebUI
    • Open WebUIが使えるようになる
    • Open WebUIのデプロイ設定方法が分かる
  • Google Cloud
    • Google Cloudをgcloudで操作することができる
    • Cloud Runが何となく分かる
      • サイドカーコンテナが何となく分かる
      • 独自ドメインで運用できるようになる
  • Cloud Storageが何となく分かる
    • Cloud Runにマウントして使えることが分かる
    • gsutilでファイルをアップロードできることが分かる
  • Cloud SQLが何となく分かる
  • Cloud Secret Managerが何となく分かる
  • Cloud Runのスケール対応が何となく分かる
  • Google Cloudにおけるプロダクトへのアクセス制限方法について何となく分かる
    • Cloud Armorが何となく分かる
    • Identity-Aware Proxy(IAP)が何となく分かる
  • OAuthやOIDCの設定が何となく分かる
  • VPCが何となく分かる
  • Cloud Load Balancingが何となく分かる

前提条件

以下の必須条件および状況に応じてオプション条件を満たしていることを前提とします。

必須

この記事を作業する人に対して

  • OPENAIのAPIキーがあること
  • Google Cloudのプロジェクトを作成していること
  • Google Cloudリソースを操作できる権限があること

オプション

この記事では段階的に環境を構築していきます。

  • Cloud DNSが操作できる権限があること

または

  • 扱いたい独自ドメインを管理しているサービスにアクセスできること

Open WebUIとは?

Open WebUIは、オープンソースのチャットインターフェースで、様々な大規模言語モデル(LLM)と対話するためのウェブベースのユーザーインターフェースです。元々はOllamaのフロントエンドとして開発されましたが、現在ではOpenAIをはじめ、追加の設定を行うことでAnthropic、Google、Mistral AIなど、多くのAIプロバイダーのモデルをサポートしています。

主な特徴

  • 多様なモデルサポート: OpenAI GPT-4/3.5、Anthropic Claude、Google Gemini、Mistral AI、Ollama、その他のローカルモデルなど、様々なAIモデルと接続できます。
  • RAG(検索拡張生成)機能: ウェブ検索、PDFアップロード、画像分析などを通じて、AIの回答を外部情報で強化できます。
  • チャット履歴管理: 会話履歴を保存し、後で参照したり続きから対話したりできます。
  • カスタマイズ可能: テーマ設定、プロンプトテンプレート、システムプロンプトなど、ユーザー体験をカスタマイズできる機能が豊富です。
  • マルチユーザー対応: 複数のユーザーアカウントをサポートし、チームでの利用が可能です。
  • セルフホスティング: 自分のサーバーやクラウド環境にデプロイして、データの管理を自分で行えます。

利用シナリオ

Open WebUIは以下のような用途で活用できます:

  • 個人やチームでのAIアシスタントとして
  • 社内向けのプライベートなAIチャットボットとして
  • 複数のAIモデルを一つのインターフェースから利用したい場合
  • データプライバシーを重視する環境でのAI活用

この記事では、Google Cloud上にOpen WebUIをデプロイする方法を解説します。これにより、セキュアで拡張性の高いAIチャットインターフェースを構築することができます。

SearXNGとは?

SearXNGは、プライバシーを重視したオープンソースのメタ検索エンジンです。複数の検索エンジン(Google、Bing、DuckDuckGoなど)から結果を収集し、それらを統合して提供します。Open WebUIには検索機能が統合されていないため、SearXNGを使用して最新のデータを取り込みます。o1のような検索機能がないモデルを利用しつつ、ネット上を検索させ結果を取り込みたいという場合、必須のサービスです。

しかしながら、GPT-4o searchモデルなどの検索機能があるモデルを利用している場合は、SearXNGを使用する必要はありません。

以下にSearXNGの主な特徴を紹介します:

主な特徴

  • プライバシー保護: ユーザーの検索クエリを匿名化し、検索エンジンに対して中継役として機能することで、ユーザーのプライバシーを保護します。
  • 多様な検索ソース: 一般的なウェブ検索だけでなく、画像、動画、ニュース、地図など、様々なカテゴリの検索結果を提供します。
  • カスタマイズ可能: 使用する検索エンジンの選択、結果の表示方法、インターフェースのテーマなど、多くの設定をカスタマイズできます。
  • トラッキングなし: ユーザーの行動を追跡せず、広告も表示しません。
  • セルフホスティング: 自分のサーバーにインストールして運用できるため、完全に制御可能です。
  • APIサポート: プログラムから検索結果にアクセスするためのAPIを提供しています。

Open WebUIとの連携

この記事では、Open WebUIとSearXNGをサイドカーコンテナとして配置し連携させて使用します。この組み合わせにより、以下のようなメリットがあります:

  • AIチャットボットが最新の情報にアクセスできるようになります(RAG機能)
  • ウェブ検索結果をプライバシーを保護しながら取得できます
  • 外部依存を減らし、より自律的なAIアシスタント環境を構築できます

SearXNGはOpen WebUIのRAG(検索拡張生成)機能のバックエンドとして機能し、AIの回答生成に役立つ最新の情報をウェブから取得します。

サイドカーコンテナとは?

サイドカーコンテナは、メインのアプリケーションコンテナと同じPod内で実行される補助的なコンテナです。Kubernetes環境やCloud Runなどのコンテナオーケストレーションプラットフォームで利用される設計パターンの一つです。

サイドカーコンテナの主な特徴と利点は以下の通りです:

  • 共有リソース: メインコンテナとネットワーク名前空間やボリュームを共有できるため、localhost経由で通信が可能です
  • 分離された責務: 機能ごとに別々のコンテナに分けることで、各コンテナの責務を明確にし、メンテナンス性を向上させます
  • 独立したライフサイクル: メインアプリケーションに影響を与えずに、サイドカーコンテナを更新・再起動できます
  • 専門化されたサービス: ログ収集、モニタリング、プロキシなど特定の機能に特化したコンテナを追加できます

今回のケースでは、Open WebUIがメインコンテナとなり、SearXNGがサイドカーコンテナとして動作します。これにより、Open WebUIはlocalhostを通じてSearXNGの検索機能にアクセスでき、両者が密接に連携しながらも、それぞれのコンテナが独自の責務を持つ構成が実現できます。

この構成により、Open WebUIの更新とSearXNGの更新を独立して行うことができ、また各コンテナが専門の機能に集中することでシステム全体の保守性が向上します。

操作環境

今回は環境の差異をできるだけなくすため、Google Cloud Shellを使用します。

Google Cloudの画面右上にある「Cloud Shellをアクティブにする」ボタンをクリックしてください。

「Cloud Shellをアクティブにする」ボタンをクリック

「Cloud Shell の承認」ダイアログが表示されるので、「承認」をクリックしてください。 ブラウザ上で、gcloudやある程度のLinuxコマンドが使えるターミナル環境がブラウザに表示されます。

以降、この記事に書いてあるコマンドは、このターミナル上でコマンドを打っていきます。

gcloudのための環境変数

この記事では多くのコマンドを打っていきますが、そのコマンドを汎用的なコマンドにするために環境変数を使用しています。

以下の環境変数を設定してください。

今回はデプロイ先リージョンをus-central1にしています。 ご利用予定の環境に合わせて変更してください。

export PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)")
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export LOCATION=us-central1
export OPEN_WEBUI_DOMAIN=open-webui-${PROJECT_NUMBER}.${REGION}.run.app
export OPENWEBUI_BUCKET_NAME=${PROJECT_ID}-open-webui
export SEARXNG_BUCKET_NAME=${PROJECT_ID}-open-webui-searxng-config-bucket

適切に設定できているかを確認してみましょう。

echo PROJECT_NUMBER: $PROJECT_NUMBER \
PROJECT_ID: $PROJECT_ID \
REGION: $REGION \
LOCATION: $LOCATION \
OPEN_WEBUI_DOMAIN: $OPEN_WEBUI_DOMAIN \
OPENWEBUI_BUCKET_NAME: $OPENWEBUI_BUCKET_NAME \
SEARXNG_BUCKET_NAME: $SEARXNG_BUCKET_NAME

それぞれの値が表示されれば、環境変数の設定は完了です。

Google Cloud API

Google Cloud で必要な API を事前に有効化するための gcloud services enable コマンドがあります。 このコマンドを使用することで、インタラクティブなプロンプトなしに必要な API を事前に有効化できます。

gcloud services enable secretmanager.googleapis.com

この記事全体で使う可能性のあるAPIを一括で有効化します。

gcloud services enable \
  artifactregistry.googleapis.com \
  secretmanager.googleapis.com \
  run.googleapis.com \
  sqladmin.googleapis.com \
  admin.googleapis.com \
  iap.googleapis.com \
  certificatemanager.googleapis.com \
  cloudresourcemanager.googleapis.com \
  redis.googleapis.com

Artifact Registry

Open WebUIは、GitHub Container Registryにイメージが登録されています。

Google Cloudからは、GitHub Container Registryにアクセスできないため、そのミラーをArtifact Registryに作成して使用します。

Artifact Registryリポジトリの作成

リポジトリを作成します。

gcloud artifacts repositories create ghcr  \
  --repository-format=docker \
  --location=${LOCATION} \
  --description="Remote repository for GitHub Container Registry" \
  --mode=remote-repository \
  --remote-docker-repo=https://ghcr.io \
  --remote-repo-config-desc="GitHub Container Registry"

### リポジトリの削除

リポジトリを削除したい場合は、以下のコマンドを実行します。

```bash
gcloud artifacts repositories delete ghcr --location=${LOCATION}

Artifact Registryリポジトリ一覧の確認

リポジトリ一覧を確認します。

gcloud artifacts repositories list

Artifact Registryリポジトリにキャッシュされているイメージ一覧の確認

リポジトリにキャッシュされているイメージ一覧を確認します。

gcloud artifacts docker images list ${REGION}-docker.pkg.dev/${PROJECT_ID}/ghcr

サービスアカウント

今回はCloud Runにサービスをデプロイしていきます。そのCloud Runのためのサービスアカウントを作成します。

サービスアカウントとは

サービスアカウントは、Google Cloud上でアプリケーションやワークロードが使用する特別な種類のアカウントです。人間のユーザーではなく、サービスやアプリケーションがGoogle Cloudリソースにアクセスするために使用されます。

サービスアカウントの主な特徴

アイデンティティとアクセス管理

  • Google Cloudリソースへのアクセスを制御するためのIAM(Identity and Access Management)と統合されています
  • 必要最小限の権限を付与する「最小権限の原則」に基づいて設定できます
  • 特定のサービスやリソースに対してのみ権限を付与することが可能です

セキュリティ

  • APIキーやパスワードではなく、より安全な認証メカニズムを提供します
  • 自動的にローテーションされる短期の認証情報を使用できます
  • 監査ログによりアクセスの追跡が可能です

柔軟性

  • 複数のサービスアカウントを作成して、異なる役割や責任を分離できます
  • 環境(開発、テスト、本番)ごとに異なるサービスアカウントを使用できます
  • Compute Engine、Cloud Run、Cloud Functionsなど様々なサービスで利用可能です

サービスアカウントの使用シナリオ

  • Cloud Runアプリケーションが他のGoogle Cloudサービス(Cloud Storage、Cloud SQL、Secret Managerなど)にアクセスする場合
  • バッチジョブやスケジュールされたタスクがAPIを呼び出す場合
  • マイクロサービスアーキテクチャにおける、サービス間の認証
  • CI/CDパイプラインがリソースをデプロイする場合

サービスアカウントを適切に設定することで、アプリケーションに必要な権限のみを付与し、セキュリティリスクを最小限に抑えながらGoogle Cloudリソースへのアクセスを管理することができます。

サービスアカウントの作成

サービスアカウントを作成します。

gcloud iam service-accounts create open-webui \
  --display-name="Open WebUI Service Account"

サービスアカウントの削除

サービスアカウントを削除したい場合は、以下のコマンドを実行します。

gcloud iam service-accounts delete open-webui@${PROJECT_ID}.iam.gserviceaccount.com

サービスアカウントにIAMポリシーのバインド

Cloud RunからGoogle Cloudのサービスにアクセスするためには、サービスアカウントにIAMポリシーをバインドする必要があります。

シークレットマネージャーにアクセスするためのIAMポリシーをバインドします。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

ストレージにアクセスし、ファイル作成編集するためのIAMポリシーをバインドします。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/storage.objectAdmin"

Cloud SQLにアクセスするためのIAMポリシーをバインドします。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/cloudsql.client"

RedisにアクセスするためのIAMポリシーをバインドします。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/redis.editor"

IAMポリシーの削除

IAMポリシーを削除したい場合は、以下のコマンドを実行します。 –roleに削除したいロールを指定します。 以下の例では「secretmanager.secretAccessor」ロールを削除しています。

gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

Google Cloud Storage

gcsにはいくつかの設定やファイルを保存します。今回は

  • ユーザーのアップロードファイル
  • SearXNGの設定ファイル

のためのバケットを作成します。

SearXNGのバケットはCloud Run内のコンテナへマウントされて使用されます。コンテナからは通常のファイルやディレクトリとしてアクセスできます。

Google Cloud Storage(GCS)とは?

Google Cloud Storage(GCS)は、Googleが提供するオブジェクトストレージサービスです。ファイルをオブジェクトとして保存し、世界中のどこからでもアクセスできるようにします。

Google Cloud Storageの主な特徴

高い耐久性と可用性

  • データは複数の場所に冗長的に保存され、99.999999999%(11個の9)の耐久性を実現
  • 標準ストレージクラスでは99.99%の可用性を提供
  • 地理的に分散したロケーションにデータを保存することも可能

柔軟なストレージクラス

  • 標準ストレージ: 頻繁にアクセスされるデータ向け
  • Nearline Storage: 月に1回程度アクセスされるデータ向け
  • Coldline Storage: 四半期に1回程度アクセスされるデータ向け
  • Archive Storage: 年に1回未満のアクセスで、長期保存が必要なデータ向け

強力なセキュリティ

  • IAMによる詳細なアクセス制御
  • データの暗号化(保存時および転送時)
  • VPCサービスコントロールによる境界保護

統合性

  • 他のGoogleサービス(BigQuery、Cloud Run、Compute Engineなど)と簡単に連携
  • RESTful APIを通じて様々なアプリケーションから利用可能

Google Cloud Storageの利用シナリオ

  • ウェブサイトのコンテンツ配信
  • データバックアップとアーカイブ
  • ビッグデータ分析のためのデータレイク
  • アプリケーションのユーザーアップロードファイルの保存
  • 機械学習モデルの保存と配布

Cloud RunとGCSの連携

Cloud RunからGCSを利用する方法は主に2つあります:

  1. APIを通じたアクセス: Cloud Runのアプリケーションから、GCSのクライアントライブラリやRESTful APIを使用してバケット内のオブジェクトにアクセス
  2. マウント: Cloud Storage FUSEを使用して、GCSバケットをファイルシステムとしてマウント

この記事では、Open WebUIのユーザーアップロードファイルの保存先としてGCSを利用し、SearXNGの設定ファイルをGCSに保存してCloud Runコンテナにマウントする方法を解説します。

Open WebUIに対するユーザーのアップロードファイル保存バケットの作成

ユーザーのアップロードファイル保存バケットを作成します。

gcloud storage buckets create gs://${OPENWEBUI_BUCKET_NAME} --location=${LOCATION}

ユーザーのアップロードファイル保存バケットの削除

上記で作成したバケットを削除したい場合は、以下のコマンドを実行します。

gcloud storage buckets delete gs://${OPENWEBUI_BUCKET_NAME}

SearXNGの設定ファイル保存バケットの作成

SearXNGの設定ファイルを保存するバケットを作成します。

gcloud storage buckets create gs://${SEARXNG_BUCKET_NAME} --location=${LOCATION}

SearXNGファイル保存バケットの削除

上記で作成したバケットを削除したい場合は、以下のコマンドを実行します。

gcloud storage buckets delete gs://${SEARXNG_BUCKET_NAME}

OPENAI

Open WebUIでは、OPENAIのAPIを使用して、チャットや画像生成、音声生成などの機能を利用できます。

ここではOpen WebUIで、OPENAIに関する機能を使うための設定を行っていきます。

事前にOPENAIよりAPIキーを取得してください。

OPENAI APIキーのシークレットの作成

シークレットを作成します。YOUR_OPEN_WEBUI_OPENAI_API_KEY部分を実際に利用するキーに書き換えます。 別のキーに更新したい場合も、同じコマンドで更新できます。

ここで作成されたシークレットの値がOpen WebUIのCloud Runの環境変数に設定されます。

echo -n "YOUR_OPEN_WEBUI_OPENAI_API_KEY" | gcloud secrets create open_webui_openai_api_key \
  --replication-policy="automatic" \
  --data-file=-

シークレットの削除

シークレットを削除したい場合は、以下のコマンドを実行します。

gcloud secrets delete open_webui_openai_api_key

OAuth

OAuthに関する設定をおこないます。 この設定を行うことで、Open WebUIにGoogle Workspaceのユーザーがログインできるようになります。

gcloudである程度の設定を行えますが、機能的に厳しいため、ブラウザでGoogle Cloud Consoleを開いて操作します。

OAuthとは

OAuth(Open Authorization)は、ユーザーが自分のアカウント情報を第三者のアプリケーションに直接提供することなく、安全に認証・認可を行うための標準プロトコルです。

OAuth 2.0の主な特徴

安全な認証委任

  • ユーザーはパスワードを第三者アプリケーションに直接提供する必要がありません
  • 代わりに、信頼できる認証プロバイダー(GoogleやFacebookなど)を通じて認証します
  • アプリケーションはユーザーの同意を得た特定の権限(スコープ)のみを取得できます

柔軟なアクセス制御

  • アクセストークンを使用して、リソースへのアクセスを制御します
  • トークンには有効期限があり、セキュリティリスクを軽減します
  • 必要に応じてトークンを無効化することも可能です

様々な認証フロー

  • 認可コードフロー:Webアプリケーション向け
  • インプリシットフロー:ブラウザベースのアプリケーション向け
  • クライアントクレデンシャルフロー:サーバー間通信向け
  • リソースオーナーパスワードクレデンシャルフロー:高度な信頼関係がある場合向け

OpenID Connectとは

OpenID Connect(OIDC)は、OAuth 2.0プロトコルの上に構築された認証レイヤーです。OAuth 2.0が「認可」(何ができるか)に焦点を当てているのに対し、OpenID Connectは「認証」(誰であるか)に焦点を当てています。

OpenID Connectの主な特徴

  • ID Token: JWT(JSON Web Token)形式で、ユーザーの身元情報を含みます
  • UserInfo Endpoint: ユーザーに関する追加情報を取得するためのエンドポイント
  • 標準化されたクレーム: email、name、pictureなど、ユーザー情報の標準フィールド
  • ディスカバリー: 認証サーバーの設定を自動的に発見する機能

OpenID Connectの利点

  • シングルサインオン(SSO)の実現が容易になります
  • 標準化されたプロトコルにより、異なるプラットフォーム間での相互運用性が向上します
  • セキュリティが強化され、フィッシング攻撃などのリスクが軽減されます

Open WebUIでは、このOAuth 2.0とOpenID Connectを利用して、Googleアカウントでの安全なログインを実現しています。ユーザーはGoogleの認証システムを通じて認証され、Open WebUIはユーザーの基本情報のみを受け取り、パスワードなどの機密情報は一切取得しません。

OAuthブランドの作成

Google Cloud ConsoleでOAuthブランドを作成します。

OAuth同意画面

ブランディングより「開始」ボタンを押します。

ブランディングより「開始」ボタンを押します。

アプリ情報と連絡先メールアドレスを入力します。

アプリ情報と連絡先メールアドレスを入力

対象を「内部」に設定します。

対象を「内部」に設定

連絡先にメールアドレスを設定します。

連絡先にメールアドレスを設定

同意を選択し「作成」ボタンを押しましょう。

同意を選択し「作成」ボタンを押す

以上でブランディングの作成は完了です。

OAuthブランド一覧の確認

作成したOAuthブランドはGoogle Cloud Consoleで確認できますが、以下のコマンドでも確認できます。

gcloud iap oauth-brands list

OAuthクライアントの作成

OAuthクライアントはgcloudでも作成できますが、機能的にはGoogle Cloud Consoleで作成した方が良いです。

クライアントメニューより「+ CREATE CLIENT」を選択します。

「+ CREATE CLIENT」を選択

アプリケーションの種類を「Webアプリケーション」。名前は適切なものを設定してください。 最後に作成ボタンを押します。

アプリケーションの種類を「Webアプリケーション」。名前は適切なものを設定

OAuth Client IDをシークレットマネージャーへ登録

OAuth Client画面から、Client IDとClient Secretを取得し、その値でシークレットを作成します。YOUR_OPEN_WEBUI_OAUTH_CLIENT_ID部分を実際に利用するキーに書き換えます。

シークレットを作成
echo -n "YOUR_OPEN_WEBUI_OAUTH_CLIENT_ID" | gcloud secrets create open_webui_oauth_client_id \
  --replication-policy="automatic" \
  --data-file=-

OAuth Client IDシークレットの削除

上記で作成したシークレットを削除したい場合は、以下のコマンドを実行します。

gcloud secrets delete open_webui_oauth_client_id

OAuth Client Secretをシークレットマネージャーへ登録

シークレットを作成します。YOUR_OPEN_WEBUI_OAUTH_CLIENT_SECRET部分を実際に利用するキーに書き換えます。

echo -n "YOUR_OPEN_WEBUI_OAUTH_CLIENT_SECRET" | gcloud secrets create open_webui_oauth_client_secret \
  --replication-policy="automatic" \
  --data-file=-

OAuth Client Secretシークレットの削除

上記で作成したシークレットを削除したい場合は、以下のコマンドを実行します。

gcloud secrets delete open_webui_oauth_client_secret

Cloud SQL

Cloud SQLでPostgreSQLを作成して使用します。
Cloud SQLはOpen WebUIの設定やチャットのデータ管理に使用されます。

Cloud SQLとは

Cloud SQLは、Google Cloudが提供するフルマネージドのリレーショナルデータベースサービスです。MySQL、PostgreSQL、SQL Serverなどの主要なデータベースエンジンをサポートしており、インフラストラクチャの管理やメンテナンスの負担を軽減しながら、高可用性と耐久性のあるデータベース環境を提供します。

Cloud SQLの主な特徴

マネージドサービス

  • バックアップ、パッチ適用、レプリケーション、容量管理などの運用タスクを自動化
  • データベースエンジンのアップデートを自動的に管理
  • 監視とアラートの機能が組み込まれている

セキュリティ

  • データの保存時と転送時の暗号化
  • ネットワークファイアウォールによるアクセス制御
  • IAMとの統合による認証と認可
  • Virtual Private Cloud (VPC) 内でのプライベート接続

高可用性と耐久性

  • リージョン内での高可用性構成(99.95%のSLA)
  • 自動フェイルオーバー機能
  • 定期的な自動バックアップとポイントインタイムリカバリ
  • クロスリージョンレプリケーション(災害復旧用)

スケーラビリティ

  • 垂直スケーリング(マシンタイプのアップグレード)
  • 読み取りレプリカによる水平スケーリング
  • ストレージの自動拡張

統合性

  • Google Cloud内の他のサービス(Cloud Run、Compute Engine、BigQueryなど)との簡単な連携
  • Cloud SQLプロキシを使用した安全な接続
  • データベース移行サービス(DMS)によるデータ移行のサポート

Cloud SQLの利用シナリオ

  • Webアプリケーションやモバイルアプリのバックエンドデータベース
  • ビジネスアプリケーション(CRM、ERP、eコマースなど)のデータストア
  • データ分析や報告のためのデータウェアハウス
  • マイクロサービスアーキテクチャにおけるサービス固有のデータベース
  • レガシーデータベースのクラウド移行先

Cloud SQLを使用することで、データベース管理の複雑さを軽減しながら、スケーラブルで信頼性の高いデータベース環境を構築することができます。

インスタンスの作成

今回は単純な構成でPostgreSQL 17のインスタンスを作成します。 利用の環境に合わせて、各パラメーターを調整したり、バックアップの設定やリードレプリカの作成などを行ってください。 また、コマンドにある「YOUR_SECURE_PASSWORD」部分を実際に利用するパスワードに書き換えます。

gcloud sql instances create open-webui \
  --database-version=POSTGRES_17 \
  --tier=db-custom-1-3840 \
  --region=${REGION} \
  --edition=ENTERPRISE \
  --root-password="YOUR_SECURE_PASSWORD"

インスタンスの削除

インスタンスを削除したい場合は、以下のコマンドを実行します。

gcloud sql instances delete open-webui

データベースの作成

Open WebUIのデータベースを作成します。

gcloud sql databases create open-webui \
  --instance=open-webui

データベースの削除

データベースを削除したい場合は、以下のコマンドを実行します。

gcloud sql databases delete open-webui \
  --instance=open-webui

ユーザーの作成

Open WebUIのユーザーを作成します。 また、コマンドにある「YOUR_USER_PASSWORD」部分を実際に利用するパスワードに書き換えます。

gcloud sql users create open-webui \
  --instance=open-webui \
  --password="YOUR_USER_PASSWORD"

ユーザーの削除

ユーザーを削除したい場合は、以下のコマンドを実行します。

gcloud sql users delete open-webui \
  --instance=open-webui

データベースrootパスワードをシークレットマネージャーに作成

シークレットを作成します。YOUR_SECURE_PASSWORD部分をデータベースrootパスワードに書き換えます。

このシークレットは今回の作業では使うことはありません。 設定したパスワードを記録しておくためだけに作成しています。

ですのでこの工程は省略可能です。

echo -n "YOUR_SECURE_PASSWORD" | gcloud secrets create open_webui_database_root_password \
  --replication-policy="automatic" \
  --data-file=-

データベース接続URLをシークレットマネージャーに作成

シークレットを作成します。YOUR_USER_PASSWORD部分をデータベースアカウント作成時に指定したパスワードに書き換えます。

echo -n "postgresql://open-webui:YOUR_USER_PASSWORD@/open-webui?host=/cloudsql/${PROJECT_ID}:${REGION}:open-webui" | gcloud secrets create open_webui_database_url  \
  --replication-policy="automatic" \
  --data-file=-

データベース接続URLシークレットの削除

上記で作成したシークレットを削除したい場合は、以下のコマンドを実行します。

gcloud secrets delete open_webui_database_url

SearXNG設定

SearXNGの設定ファイルを保存するバケットを作成します。 以下は一般的な設定です。 細かい制御を行いたい場合は、SearXNGの公式ドキュメントを参照してください。

limiter.tomlを作成

limiter.tomlを作成します。

cat << 'EOF' >| limiter.toml
# This configuration file updates the default configuration file
# See https://github.com/searxng/searxng/blob/master/searx/botdetection/limiter.toml

[botdetection.ip_limit]
# activate link_token method in the ip_limit method
link_token = false

[botdetection.ip_lists]
block_ip = []
pass_ip = []
EOF

settings.yamlを作成

settings.yamlを作成します。

cat << 'EOF' >| settings.template.yml
use_default_settings: true
server:
  secret_key: "$(openssl rand -hex 32)"
search:
  formats:
    - html
    - json
  safe_search: 0
outgoing:
  request_timeout: 6.0
  max_request_timeout: 15.0
  retries: 3
EOF

一部シェルコマンドが含まれているため、以下のコマンドでシェルコマンドを展開します。

envsubst < settings.template.yml >| settings.yml

バケットに設定ファイルをアップロード

作成した設定ファイルをバケットにアップロードします。

gsutil cp limiter.toml settings.yml gs://${SEARXNG_BUCKET_NAME}/

作成したファイルがアップロードされているか確認してみましょう。

gsutil ls gs://${SEARXNG_BUCKET_NAME}/

ファイルが見えれば成功です。

SearXNGの設定ファイルを削除

作成した設定ファイルを削除したい場合は、以下のコマンドを実行します。

gsutil rm "gs://${SEARXNG_BUCKET_NAME}/*"

Cloud Run

アプリケーションの実態であるコンテナをCloud Runへデプロイします。

Cloud Runとは

Cloud Runは、コンテナ化されたアプリケーションをサーバーレスで実行できるマネージドコンピューティングプラットフォームです。

主な特徴

サーバーレス

  • インフラストラクチャの管理が不要
  • 使用した分だけ課金される従量課金制
  • 自動でスケーリング

コンテナベース

  • DockerコンテナをそのままデプロイできるためCI/CDとの親和性が高い
  • 言語やフレームワークを問わずアプリケーションを実行可能
  • コンテナイメージの管理が容易

セキュリティ

  • HTTPSエンドポイントを自動で提供
  • IAMによる認証・認可の制御
  • VPCとの接続も可能

運用性

  • リビジョン管理によるロールバックが容易
  • ヘルスチェックによる自動復旧
  • ログやメトリクスの可視化

Cloud Runを使用することで、インフラストラクチャの管理から解放され、アプリケーションの開発に集中することができます。

Cloud Run構成定義yamlファイルの作成

今回はyamlファイルを用いてCloud Runサービスを作成します。

以下のコマンドで、Open WebUIの環境を作成するためのテンプレートファイルを作成します。

cat << 'EOF' >| open-webui.template.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: open-webui
  annotations:
    run.googleapis.com/ingress: all
    run.googleapis.com/ingress-status: all
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/minScale: '0'
        autoscaling.knative.dev/maxScale: '1'
        run.googleapis.com/cloudsql-instances: ${PROJECT_ID}:${LOCATION}:open-webui
    spec:
      containerConcurrency: 40
      timeoutSeconds: 600
      serviceAccountName: open-webui@${PROJECT_ID}.iam.gserviceaccount.com
      containers:
      - name: open-webui
        image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/ghcr/open-webui/open-webui@sha256:9b7fb388f0828b597e67c263667214c93592cbc5cac3047be89f5e92bc1085ba
        ports:
        - name: http1
          containerPort: 8081
        env:
        - name: DEFAULT_USER_ROLE
          value: user
        - name: ENABLE_LOGIN_FORM
          value: 'True'
        - name: STORAGE_PROVIDER
          value: gcs
        - name: GCS_BUCKET_NAME
          value: ${OPENWEBUI_BUCKET_NAME}
        - name: ENABLE_OAUTH_SIGNUP
          value: 'True'
        - name: OPENID_PROVIDER_URL
          value: https://accounts.google.com/.well-known/openid-configuration
        - name: ENABLE_OAUTH_GOOGLE
          value: 'True'
        - name: GOOGLE_REDIRECT_URI
          value: https://${OPEN_WEBUI_DOMAIN}/oauth/google/callback
        - name: WEBUI_URL
          value: https://${OPEN_WEBUI_DOMAIN}
        - name: ENABLE_OLLAMA_API
          value: 'False'
        - name: ENABLE_EVALUATION_ARENA_MODELS
          value: 'False'
        - name: ENABLE_RAG_WEB_SEARCH
          value: 'True'
        - name: RAG_WEB_SEARCH_ENGINE
          value: "searxng"
        - name: RAG_WEB_SEARCH_RESULT_COUNT
          value: '3'
        - name: RAG_WEB_SEARCH_CONCURRENT_REQUESTS
          value: '10'
        - name: SEARXNG_QUERY_URL
          value: "http://localhost:8080/search?q=<query>"
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_database_url
        - name: OPENAI_API_KEY
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_openai_api_key
        - name: GOOGLE_CLIENT_ID
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_oauth_client_id
        - name: GOOGLE_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_oauth_client_secret
        resources:
          limits:
            cpu: 2000m
            memory: 2.0Gi
        startupProbe:
          httpGet:
            path: /
            port: 8081
          initialDelaySeconds: 10
          periodSeconds: 3
          failureThreshold: 30
      - name: searxng
        image: searxng/searxng:latest
        env:
        - name: SEARXNG_HOSTNAME
          value: 'localhost:8080'
        - name: SEARXNG_PORT
          value: '8080'
        - name: SEARXNG_BIND_ADDRESS
          value: '0.0.0.0'
        - name: SEARXNG_STATIC_USE_HASH
          value: 'true'
        - name: SEARXNG_LIMITER
          value: 'false'
        - name: SEARXNG_IMAGE_PROXY
          value: 'true'
        resources:
          limits:
            cpu: 1000m
            memory: 1Gi
        volumeMounts:
        - name: searxng-config
          mountPath: /etc/searxng
      volumes:
      - name: searxng-config
        csi:
          driver: gcsfuse.run.googleapis.com
          readOnly: false
          volumeAttributes:
            bucketName: ${SEARXNG_BUCKET_NAME}
EOF

続けて以下のコマンドを実行し、yamlファイルを作成します。

envsubst < open-webui.template.yaml > open-webui.yaml

Cloud Runサービスの作成

作成したyamlファイルを用いてCloud Runサービスを作成します。

gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed

Cloud Runサービスの削除

上記で作成したサービスを削除したい場合は、以下のコマンドを実行します。

gcloud run services delete open-webui --project=${PROJECT_ID} --region=${REGION} 

Cloud RunサービスのIAMポリシーの設定

Cloud RunサービスのIAMポリシーを設定します。

この設定は非常に重要で、たとえばOpen WebUIのCloud Runを削除して作り直した場合などには常に再実行する必要があります。 今回はこの設定で、誰でもアクセスできるようにしています。逆を言えば、この設定を行わないと、誰もアクセスできないようになります。

gcloud run services add-iam-policy-binding open-webui --member="allUsers" --role="roles/run.invoker" --region=${REGION}

OAuth認証設定

OAuthを使うための設定を行っていきます。 この設定の中で、Open ID Connectを使うための設定も間接的に行っています。

ブランディング

Google Cloud Console → APIとサービス → OAuth 同意画面 → ブランディング

の認証済みドメインへ

echo ${OPEN_WEBUI_DOMAIN}

で表示されるドメイン名を追加します。

ドメイン名を追加

OAuth2.0クライアント

Google Cloud Console → APIとサービス → OAuth同意画面 → クライアント → 前工程で作成したOAuth2.0クライアントを選択

前工程で作成したOAuth2.0クライアントを選択

承認済みの JavaScript 生成元を追加

Cloud Run作成時に表示されたURLまたは

gcloud run services describe open-webui --region=${REGION} --format="value(status.url)"

で表示されるURLを「承認済みの JavaScript 生成元」に追加します。 「+URIを追加」をクリックして、URLを追加します。

承認済みのリダイレクトURIを追加

「承認済みのリダイレクト URI」には、Cloud Run作成時に表示されたURLまたはbash

gcloud run services describe open-webui --region=${REGION} --format="value(status.url)"

で表示されるURLに、/oauth/google/callbackを追加した値を追加します。 「+URIを追加」をクリックして、URLを追加します。 追加するURLは、https://${デプロイ後に表示されるURL}/oauth/google/callbackのようになるはずです。

データアクセス

Google Cloud Console → APIとサービス → OAuth同意画面 → データアクセス

ここからScopeの設定を行います。

「スコープを追加または削除」を押して、上から3つを選択します。

  • …/auth/userinfo.email Google アカウントのメインのメールアドレスの参照
  • …/auth/userinfo.profile ユーザーの個人情報の表示(ユーザーが一般公開しているすべての個人情報を含む)
  • openid Google で公開されているお客様の個人情報とお客様を関連付ける

これらを選択した後、「更新」を押します。

Scopeの設定

Open WebUIを利用してみる

以上で、Cloud Runサービスの作成は完了です。 Cloud Run作成完了後に表示されるURLへアクセスしてみましょう。 Open WebUIのログイン画面が表示されます。 URLがわからないという場合、以下のコマンドでURLを確認できます。

gcloud run services describe open-webui --region=${REGION} --format="value(status.url)"

アクセスした際に

Error: Forbidden
Your client does not have permission to get URL / from this server.

というエラーが表示される場合は、Cloud RunサービスのIAMポリシーを適用していない可能性が高いです。またIAMポリシー適用には時間がかかるため、動かないからと言ってすぐに設定を変えてみたりせず、しばらく待ってから再度確認してください。

今回のセットアップではGoogle Workspaceユーザーを使用したOAuthによるログインを有効にしているので、トップ画面より「Continue with Google」ボタンでログインし、そのまま使用することが可能です。

トップ画面より「Continue with Google」ボタンでログイン

独自ドメインでの運用

ここまでの設定でもOpen WebUIを使うことは可能です。 ただ実際に使っていくとなると、独自ドメインを使用したくなると思います。 今回はGoogle Cloudで独自ドメインのゾーンを作成し、そのゾーンに独自ドメインをマッピングして運用してみます。 そのため、その使用予定の独自ドメインを管理することができるだけの状況下にあることを前提とします。

独自ドメインを使うための前準備

まずは独自ドメインとDNSのゾーン名称を環境変数に設定します。 YOUR_OPEN_WEBUI_DOMAIN / YOUR_ZONE_NAMEには、使用予定の独自ドメインとDNSのゾーン名称を設定します。

export OPEN_WEBUI_DOMAIN=YOUR_OPEN_WEBUI_DOMAIN
export ZONE_NAME=YOUR_ZONE_NAME

open-webui.example.comなら、export OPEN_WEBUI_DOMAIN=open-webui.example.comとします。 example.comなら、export ZONE_NAME=example-comとします。 指定した独自ドメインを使用して再度yamlファイルを生成します。

envsubst < open-webui.template.yaml >| open-webui.yaml

作成したyamlファイルを用いてCloud Runサービスを作成します。

gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed

独自ドメインのマッピング

ドメインマッピングを作成します。

gcloud beta run domain-mappings create --service open-webui --domain ${OPEN_WEBUI_DOMAIN} --region ${REGION}

(Cloud DNSでゾーン管理している人向け)独自ドメインのDNSレコードの作成

独自ドメインのDNSレコードを作成します。 レコードを追加するゾーンについては、すでに作成済みであり、ゾーンの所有確認が完了しているとします。

gcloud dns record-sets create ${OPEN_WEBUI_DOMAIN} \
  --rrdatas="ghs.googlehosted.com." \
  --ttl=300 \
  --type=CNAME \
  --zone=${ZONE_NAME}

DNSレコードが正しく設定されたかを確認するには以下のコマンドを実行し、CNAMEレコードが存在することを確認します。

gcloud dns record-sets list --zone=${ZONE_NAME}

または、nslookupやdigコマンドを使用して確認することもできます。

nslookup ${OPEN_WEBUI_DOMAIN}

(Cloud DNSでゾーン管理していない人向け)独自ドメインのDNSレコードの作成

ご自身が利用されているDNSサービスで、CNAMEレコードを作成してください。

証明書のプロビジョニング

DNSレコードが正しく設定されると、Google Cloudは自動的にSSL証明書のプロビジョニングを開始します。証明書のステータスは以下のコマンドで確認できます。

gcloud beta run domain-mappings describe --domain ${OPEN_WEBUI_DOMAIN} --region ${REGION}

証明書のプロビジョニングには時間がかかる場合があります。 いくつかのステータスがtrueになれば証明書のプロビジョニングが完了しています。 完了できていることが確認できたら、今回設定した独自ドメインへブラウザでアクセスしてみましょう。 画面が表示されれば設定は完了です。

ロードバランサー下での運用

より一層細かい制御を行いたいという場合、ロードバランサー下での運用を行うことも可能です。

ロードバランサー下での運用の前準備

前工程での独自ドメイン運用設定を行っている場合、まずはその設定を削除します。

ドメインマッピングの削除

ドメインマッピングを削除します。

gcloud beta run domain-mappings delete --domain ${OPEN_WEBUI_DOMAIN} --region ${REGION}

ドメイン名のDNSレコードの削除

CNAMEレコードを削除します。 ゾーン名称は適切な値に変更してください。

gcloud dns record-sets delete ${OPEN_WEBUI_DOMAIN} --type=CNAME --zone=${ZONE_NAME}

グローバルIPアドレスの予約

ロードバランサー下での運用にはグローバルIPアドレスが必要です。 前もってグローバルIPアドレスを予約しておきます。

gcloud compute addresses create open-webui-ip \
    --global

予約したIPアドレスの確認

gcloud compute addresses describe open-webui-ip --global --format="get(address)"

Cloud Run NEGの作成

gcloud compute network-endpoint-groups create open-webui-neg \
    --region=${REGION} \
    --network-endpoint-type=SERVERLESS \
    --cloud-run-service=open-webui

バックエンドサービスの作成

gcloud compute backend-services create open-webui-backend \
    --global \
    --load-balancing-scheme=EXTERNAL_MANAGED

NEGをバックエンドサービスに追加

gcloud compute backend-services add-backend open-webui-backend \
    --global \
    --network-endpoint-group=open-webui-neg \
    --network-endpoint-group-region=${REGION}

URLマップの作成

gcloud compute url-maps create open-webui-url-map \
    --default-service=open-webui-backend

Cloud DNSへAレコードの作成

グローバルIPアドレスの予約時に取得したIPアドレスを使用します。 ゾーンは適切な値に変更してください。

gcloud dns record-sets create ${OPEN_WEBUI_DOMAIN} \
    --type=A \
    --ttl=300 \
    --rrdatas=$(gcloud compute addresses describe open-webui-ip --global --format="get(address)") \
    --zone=${ZONE_NAME}

マネージドSSL証明書の作成

gcloud compute ssl-certificates create open-webui-cert \
    --domains=${OPEN_WEBUI_DOMAIN} \
    --global

HTTPSプロキシの作成

gcloud compute target-https-proxies create open-webui-https-proxy \
    --ssl-certificates=open-webui-cert \
    --url-map=open-webui-url-map

転送ルールの作成

gcloud compute forwarding-rules create open-webui-https-rule \
    --load-balancing-scheme=EXTERNAL_MANAGED \
    --network-tier=PREMIUM \
    --address=open-webui-ip \
    --target-https-proxy=open-webui-https-proxy \
    --global \
    --ports=443

Cloud Runに対する外部からの直接アクセスを遮断

まず最新の情報でopen-webui.yamlファイルを更新します。

envsubst < open-webui.template.yaml >| open-webui.yaml

open-webui.yamlファイルの以下の部分を変更します。 この設定の変更を行いデプロイすることで、Cloud Runに対する外部からの直接アクセスを遮断できます。

sed -i 's/run.googleapis.com\/ingress: all/run.googleapis.com\/ingress: internal-and-cloud-load-balancing/g' open-webui.yaml
sed -i 's/run.googleapis.com\/ingress-status: all/run.googleapis.com\/ingress-status: internal-and-cloud-load-balancing/g' open-webui.yaml

その後、デプロイします。

gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed

この時点で、Cloud Runデプロイ後に表示されるURLや、

gcloud run services describe open-webui --region=${REGION} --format="value(status.url)"

で表示されるURLにアクセスしても、Cloud Runに対する外部からの直接アクセスを遮断されているため、アクセスできなくなっているはずです。

代わりに設定した独自ドメインにアクセスすると、Open WebUIの画面が表示されるはずです。

今回の行程においては証明書のプロビジョニングを行っています。この処理は通常20分ほどかかるため、証明書のプロビジョニングが完了するまでは、設定した独自ドメインにアクセスしてもアクセスできない可能性が高いです。

証明書のプロビジョニングが完了しているかを確認したい場合は、以下のコマンドを実行してください。

gcloud compute ssl-certificates describe open-webui-cert --global

status: PROVISIONINGの場合は、証明書のプロビジョニングが完了するまで待ってください。 status: ACTIVEの場合は、証明書のプロビジョニングが完了しています。

Open WebUIに対するアクセス制御

ロードバランサー配下においたことにより、ロードバランサーの背後にあるCloud Runサービスに対するアクセス制御を行うことができます。

今回はセキュリティポリシーの適用による日本からのアクセスに限定する方法と、Identity-Aware ProxyによるGoogle Workspaceユーザーのみがアクセスできるようになる方法を紹介します。

なおこの2つの方法は同時に適用することはできません。

Identity-Aware Proxyによるアクセス制御の一部が日本以外からのアクセスとなり、セキュリティポリシーの適用による日本からのアクセスに限定する方法とは矛盾するからです。

セキュリティポリシー(Cloud Armor)で制御したい場合

日本からのアクセスのみ許可するように設定してみます。

セキュリティポリシーの作成

まずはポリシーを作成します。

gcloud compute security-policies create open-webui-security-policy \
    --description "open-webuiに対するセキュリティポリシー"

作成したポリシーに対して、日本からのアクセスを許可するルールを作成します。

gcloud compute security-policies rules create 1000 \
    --security-policy open-webui-security-policy \
    --description "日本からのアクセスを許可" \
    --expression "origin.region_code == 'JP'" \
    --action "allow"

作成したポリシーにおけるデフォルトルール(明示したルールにマッチしない場合のルール)を拒否に設定します。 2147483647はデフォルトルールのIDです。

gcloud compute security-policies rules update 2147483647 \
    --security-policy open-webui-security-policy \
    --description "デフォルトでアクセスを拒否" \
    --action "deny-403"

セキュリティポリシーをバックエンドサービスに適用

gcloud compute backend-services update open-webui-backend \
    --security-policy=open-webui-security-policy \
    --global

以上の設定で、日本からのアクセスのみ許可するようになります。 海外のProxyなどを利用して、アクセスできなくなっていることを確認してみてください。

セキュリティポリシーの適用を解除したい場合、

gcloud compute backend-services update open-webui-backend \
    --security-policy= \
    --global

で、セキュリティポリシーの適用を解除できます。

Identity-Aware Proxy(IAP)で制御したい場合

Identity-Aware Proxyで、Google Workspaceユーザーのみがアクセスできるようにしてみます。

Identity-Aware Proxy(IAP)とは

Identity-Aware Proxy(IAP)は、Google Cloudが提供するセキュリティサービスで、アプリケーションやリソースへのアクセスを細かく制御することができます。従来のVPNやファイアウォールとは異なり、ユーザーの身元(アイデンティティ)に基づいてアクセス制御を行います。

IAPの主な特徴

ユーザーベースのアクセス制御

  • Google WorkspaceやCloud Identityのユーザーアカウントを使用して認証を行います
  • 特定のユーザー、グループ、ドメイン単位でアクセス権を付与できます
  • IPアドレスではなく「誰であるか」に基づいてアクセスを制御します

セキュリティの向上

  • VPNを使わずともセキュアなアクセスが可能になります
  • 多要素認証(MFA)と組み合わせることで、さらにセキュリティを強化できます
  • すべてのアクセスはログに記録され、監査が可能です

簡単な導入

  • アプリケーションコードの変更なしに導入できます
  • Google Cloud Consoleから簡単に設定可能です
  • 既存のCloud RunやApp Engineなどのサービスにシームレスに統合できます

Identity-Aware Proxy(IAP)の仕組み

Identity-Aware Proxy(IAP)は、ユーザーがアプリケーションにアクセスする際に「門番」のような役割を果たします:

  1. ユーザーがアプリケーションのURLにアクセスします
  2. Identity-Aware Proxy(IAP)がリクエストを受け取り、ユーザーに認証を要求します
  3. ユーザーがGoogle認証情報でログインします
  4. Identity-Aware Proxy(IAP)はユーザーの身元を確認し、アクセス権があるか確認します
  5. アクセス権がある場合のみ、リクエストをアプリケーションに転送します

これにより、認証されていないユーザーはアプリケーションにアクセスできなくなり、セキュリティが大幅に向上します。

Identity-Aware Proxy(IAP)の利用シナリオ

  • 社内ツールへのアクセスを特定の従業員のみに制限したい場合
  • 顧客向けアプリケーションを特定の顧客のみに公開したい場合
  • 開発環境や管理コンソールへのアクセスを開発者のみに制限したい場合
  • VPNを使わずに社内リソースへのセキュアなアクセスを提供したい場合

Identity-Aware Proxy(IAP)を使用することで、「誰が」「どのリソースに」アクセスできるかを細かく制御でき、セキュリティを強化しながらも利便性を損なわないアクセス管理が可能になります。

backend-servicesにIAPを有効化

先ほど作成したbackend-servicesに対し、Identity-Aware Proxy(IAP)を有効化します。 Google Cloud ConsoleのIdentity-Aware Proxy(IAP)のページで、確認できるようになります。

gcloud compute backend-services update open-webui-backend \
    --global \
    --iap

backend-servicesのIAPを削除

backend-servicesを削除する場合は、以下のコマンドを実行します。

ただこのコマンド単体では削除に失敗する可能性が高いです。

gcloud compute backend-services delete open-webui-backend --global

実際削除しようと思うと、関係するリソースを先に削除する必要があります。

# 1. 転送ルールの削除
gcloud compute forwarding-rules delete open-webui-https-rule --global

# 2. HTTPS プロキシの削除
gcloud compute target-https-proxies delete open-webui-https-proxy

# 3. URL マップの削除
gcloud compute url-maps delete open-webui-url-map

# 4. バックエンドサービスの削除(これで成功するはず)
gcloud compute backend-services delete open-webui-backend --global

指定したドメインのみ許可

指定したドメインのみ許可する場合は、以下のコマンドを実行します。 たとえば、example.comのメールアドレスのみを許可する場合は、以下のコマンドを実行します。

gcloud iap web add-iam-policy-binding \
  --member=domain:example.com \
  --role=roles/iap.httpsResourceAccessor \
  --resource-type=backend-services \
  --service=open-webui-backend

指定したドメインの削除

指定したドメインを削除する場合は、以下のコマンドを実行します。 以下の例は、example.comを削除したい場合のコマンドです。

gcloud iap web remove-iam-policy-binding \
  --member=domain:example.com \
  --role=roles/iap.httpsResourceAccessor \
  --resource-type=backend-services \
  --service=open-webui-backend

独自ドメインをOAuth設定に追加

OAuth認証設定と同じ手順で、独自ドメインをOAuth設定に追加します。

Identity-Aware Proxy(IAP)越しにアクセス

以上で、Identity-Aware Proxy(IAP)の設定は完了です。 トップページのアドレスにアクセスすると、「Googleでログイン」画面が表示されます。

「Googleでログイン」画面が表示されます。

ここでGoogle Workspaceのユーザーでログインすると、Open WebUIにアクセスできるようになります。

ここまでの内容で、ロードバランサー下での運用は完了です。

スケール対応

現在のopen-webui.yamlの設定では、1つのインスタンスしか起動しないようになっています。 これは、現在の設定のままだと、セッション情報の保存場所がローカル(インスタンス内)になっていて、インスタンスを複数起動しても、インスタンス間セッション情報が共有されず、正しいセッション管理ができないためです。

想定している同時アクセス数がそれほど多くない場合は1インスタンスで運用しても問題ないでしょう。 しかし、同時アクセス数が多い場合は、インスタンスを複数起動して水平スケールを行う必要があります。

VPC

セッション情報の共有ためにRedisを使います。その際、Cloud RunからRedisにアクセスするためには、VPCを使う必要があります。

VPCとは?

VPC(Virtual Private Cloud)は、Google Cloud Platform上に作成できる仮想ネットワークです。VPCを使用することで、クラウド内のリソース間で安全に通信できる独立したネットワーク環境を構築できます。

VPCの主な特徴と利点は以下の通りです:

  • 分離されたネットワーク環境: 他のプロジェクトやユーザーのリソースから論理的に分離された環境を提供します。
  • カスタムIPアドレス範囲: 自分で定義したIPアドレス範囲を使用できます。
  • ファイアウォールルール: ネットワークトラフィックを制御するためのルールを設定できます。
  • プライベート接続: インターネットを経由せずにGoogleのサービスに接続できます。
  • VPNやCloud Interconnectとの連携: オンプレミス環境との安全な接続が可能です。

今回のケースでは、Cloud RunからRedisへの接続をインターネットを経由せずに安全に行うためにVPCを使用します。これにより、セッション情報を複数のCloud Runインスタンス間で共有し、水平スケーリングを実現します。

VPCの作成

今回はVPCをカスタムモードで作成します。 作成されるVPC名は、PROJECT_IDと同じになります。

gcloud compute networks create ${PROJECT_ID} \
    --subnet-mode=custom

VPCの削除

サブネットが作成されているとエラーになります。

gcloud compute networks delete ${PROJECT_ID}

サブネットの作成

VPCにサブネットを作成します。 Cloud RunとVPCの間をDirect VPC Egressで接続するため、少し広め(24ではなく16)のサブネットを作成します。

gcloud compute networks subnets create ${PROJECT_ID}-open-webui \
    --network=${PROJECT_ID} \
    --region=${REGION} \
    --range=10.0.0.0/16 \
    --enable-private-ip-google-access

サブネットの削除

gcloud compute networks subnets delete ${PROJECT_ID}-open-webui \
    --region=${REGION}

Redis

Redisとは?

Redisは、高性能なインメモリデータストア・キャッシュシステムです。主な特徴と利点は以下の通りです。

  • 高速なパフォーマンス: データをメモリ上に保持するため、非常に高速なレスポンスが可能です。
  • 多様なデータ構造: 文字列、ハッシュ、リスト、セット、ソート済みセットなど、様々なデータ構造をサポートしています。
  • 永続化機能: データをディスクに保存することで、再起動時にもデータを復元できます。
  • パブリッシュ/サブスクライブ: メッセージングシステムとしても利用可能です。
  • 分散システムのサポート: 複数のインスタンスでデータを共有できます。

今回のOpen WebUI環境では、Redisを以下の目的で使用します。

  1. セッション管理: ユーザーセッション情報を保存し、複数のCloud Runインスタンス間で共有します。
  2. WebSocketサポート: リアルタイム通信のためのWebSocket接続を管理します。
  3. SearXNG検索エンジン: 検索結果のキャッシュやレート制限の管理に使用します。

これにより、Open WebUIを水平スケーリング可能な構成で運用することができます。

Redisインスタンスの作成

Redisインスタンスを作成します。 その際、Redisと先ほど作成したVPCを接続します。 Redisのスペックは利用環境に合わせて適宜変更してください。

Redisの作成は他のリソース作成より時間がかかります。

gcloud redis instances create open-webui \
    --region=${REGION} \
    --tier=basic \
    --size=1 \
    --redis-version=redis_7_0 \
    --connect-mode=DIRECT_PEERING \
    --network=${PROJECT_ID}

Redisインスタンスの削除

gcloud redis instances delete open-webui \
    --region=${REGION}

Redisの接続先設定確認

Redisの接続先設定を確認します。

gcloud redis instances describe open-webui \
    --region=${REGION} \
    --format="value(host)"

firwall

Cloud RunからMemorystore for RedisにアクセスするためのFirewallルールを作成します。Open WebUIのサービスにはredisというタグがついているため、このタグを使ってFirewallルールを作成します。

gcloud compute firewall-rules create allow-redis-traffic \
  --direction=INGRESS \
  --priority=1000 \
  --network=${PROJECT_ID} \
  --action=ALLOW \
  --rules=tcp:6379 \
  --source-tags=redis

作成したFirewallルールの確認

gcloud compute firewall-rules list --filter="network=${PROJECT_ID}"

スケール用open-webui.template.yamlの作成

以下のコマンドで、open-webui-redis.template.yamlを作成します。

cat << 'EOF' >| open-webui-redis.template.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: open-webui
  annotations:
    run.googleapis.com/ingress: internal-and-cloud-load-balancing
    run.googleapis.com/ingress-status: internal-and-cloud-load-balancing
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/minScale: '0'
        autoscaling.knative.dev/maxScale: '2'
        run.googleapis.com/vpc-access-egress: private-ranges-only
        run.googleapis.com/network-interfaces: '[{"network":"${PROJECT_ID}","subnetwork":"${PROJECT_ID}-open-webui","tags":["redis"]}]'
        run.googleapis.com/cloudsql-instances: ${PROJECT_ID}:${LOCATION}:open-webui
    spec:
      containerConcurrency: 40
      timeoutSeconds: 600
      serviceAccountName: open-webui@${PROJECT_ID}.iam.gserviceaccount.com
      containers:
      - name: open-webui
        image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/ghcr/open-webui/open-webui@sha256:9b7fb388f0828b597e67c263667214c93592cbc5cac3047be89f5e92bc1085ba
        ports:
        - name: http1
          containerPort: 8081
        env:
        - name: DEFAULT_USER_ROLE
          value: user
        - name: ENABLE_LOGIN_FORM
          value: 'True'
        - name: STORAGE_PROVIDER
          value: gcs
        - name: GCS_BUCKET_NAME
          value: ${OPENWEBUI_BUCKET_NAME}
        - name: ENABLE_OAUTH_SIGNUP
          value: 'True'
        - name: OPENID_PROVIDER_URL
          value: https://accounts.google.com/.well-known/openid-configuration
        - name: ENABLE_OAUTH_GOOGLE
          value: 'True'
        - name: GOOGLE_REDIRECT_URI
          value: https://${OPEN_WEBUI_DOMAIN}/oauth/google/callback
        - name: WEBUI_URL
          value: https://${OPEN_WEBUI_DOMAIN}
        - name: ENABLE_OLLAMA_API
          value: 'False'
        - name: ENABLE_EVALUATION_ARENA_MODELS
          value: 'False'
        - name: ENABLE_RAG_WEB_SEARCH
          value: 'True'
        - name: RAG_WEB_SEARCH_ENGINE
          value: "searxng"
        - name: RAG_WEB_SEARCH_RESULT_COUNT
          value: '3'
        - name: RAG_WEB_SEARCH_CONCURRENT_REQUESTS
          value: '10'
        - name: SEARXNG_QUERY_URL
          value: "http://localhost:8080/search?q=<query>"
        - name: ENABLE_WEBSOCKET_SUPPORT
          value: 'True'
        - name: WEBSOCKET_MANAGER
          value: redis
        - name: WEBSOCKET_REDIS_URL
          value: redis://${REDIS_HOST}:6379/0
        - name: REDIS_URL
          value: redis://${REDIS_HOST}:6379/0
        # - name: ENABLE_GOOGLE_DRIVE_INTEGRATION
        #   value: 'True'
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_database_url
        - name: OPENAI_API_KEY
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_openai_api_key
        - name: GOOGLE_CLIENT_ID
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_oauth_client_id
        - name: GOOGLE_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              key: latest
              name: open_webui_oauth_client_secret
        # - name: GOOGLE_DRIVE_CLIENT_ID
        #   valueFrom:
        #     secretKeyRef:
        #       key: latest
        #       name: open_webui_google_drive_client_id
        # - name: GOOGLE_DRIVE_API_KEY
        #   valueFrom:
        #     secretKeyRef:
        #       key: latest
        #       name: open_webui_google_drive_api_key
        # - name: ANTHROPIC_API_KEY
        #   valueFrom:
        #     secretKeyRef:
        #       key: latest
        #       name: open_webui_anthropic_api_key
        resources:
          limits:
            cpu: 2000m
            memory: 2.0Gi
        startupProbe:
          httpGet:
            path: /
            port: 8081
          initialDelaySeconds: 10
          periodSeconds: 3
          failureThreshold: 30
      - name: searxng
        image: searxng/searxng@sha256:662971a55feacea2eacd2a8a2f51b3e26b56a73080dd131d079d15d7b991faed
        env:
        - name: SEARXNG_HOSTNAME
          value: 'localhost:8080'
        - name: SEARXNG_PORT
          value: '8080'
        - name: SEARXNG_BIND_ADDRESS
          value: '0.0.0.0'
        - name: SEARXNG_STATIC_USE_HASH
          value: 'true'
        - name: SEARXNG_LIMITER
          value: 'false'
        - name: SEARXNG_IMAGE_PROXY
          value: 'true'
        - name: SEARXNG_REDIS_URL
          value: redis://${REDIS_HOST}:6379/0
        resources:
          limits:
            cpu: 1000m
            memory: 1Gi
        volumeMounts:
        - name: searxng-config
          mountPath: /etc/searxng
      volumes:
      - name: searxng-config
        csi:
          driver: gcsfuse.run.googleapis.com
          readOnly: false
          volumeAttributes:
            bucketName: ${SEARXNG_BUCKET_NAME}
EOF

スケール用open-webui.yamlの作成

テンプレートファイルから新しいopen-webui.yamlを作成します。

新しいテンプレートファイルではRedisに関する情報が必要なため、環境変数にセットします。

export REDIS_HOST=$(gcloud redis instances describe open-webui --region=${REGION} --format="value(host)")

続けて新しいopen-webui.yamlを作成します。

envsubst < open-webui-redis.template.yaml >| open-webui.yaml

スケール対応版Open WebUIのデプロイ

作成したopen-webui.yamlを使用してデプロイします。

gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed

以上で、スケール対応版Open WebUIのデプロイが完了です。

今回の設定では最大2インスタンスで運用するようになっています。

Open WebUIの設定

ここでは、Open WebUIの設定のうち、比較的複雑な設定を必要とする項目についてその設定方法を詳しく説明します。

Google Driveの設定

Open WebUIにはGoogle Driveからファイルをアップロードする機能があります。

APIを有効化

Google Drive APIとGoogle Picker APIを有効化します。

gcloud services enable \
  drive.googleapis.com \
  picker.googleapis.com

Google Drive用OAuthクライアントの作成

Google Cloud ConsoleでOAuthクライアントを作成します。

基本的な手順は以前説明したOAuthクライアントの作成」と同様です。

Google Cloud ConsoleでOAuthクライアントを作成

Google Drive用OAuth Client IDをシークレットマネージャーへ登録

OAuth Client画面から、Client IDとClient Secretを取得し、その値でシークレットを作成します。YOUR_OPEN_WEBUI_GOOGLE_DRIVE_CLIENT_ID部分を実際に利用するキーに書き換えます。

echo -n "YOUR_OPEN_WEBUI_GOOGLE_DRIVE_CLIENT_ID" | gcloud secrets create open_webui_google_drive_client_id \
  --replication-policy="automatic" \
  --data-file=-

Google Drive用APIキーを作成

Google Drive用APIキーを作成

「+認証情報を作成」をクリックしてキーを作成します。

キーを作成

APIの制限で、「Google Picker API」と「Google Drive API」を選択しましょう。 「鍵を表示します」をクリックすることで、Google Drive用APIキーを取得できます。

「鍵を表示します」をクリックすることで、Google Drive用APIキーを取得

Google Drive用APIキーをシークレットマネージャーへ登録

取得したAPIキーをシークレットマネージャーへ登録します。 YOUR_OPEN_WEBUI_GOOGLE_DRIVE_API_KEY部分を実際に利用するキーに書き換えます。

echo -n "YOUR_OPEN_WEBUI_GOOGLE_DRIVE_API_KEY" | gcloud secrets create open_webui_google_drive_api_key \
  --replication-policy="automatic" \
  --data-file=-

Google Drive用データアクセス

Google Drive用データアクセスを設定します。 データアクセスを参照して設定してください。

今回追加するのは

  • drive.file
  • drive.readonly

の2つです。

データアクセスを参照して設定

open-webui.yamlの設定

open-webui.yamlの設定を変更します。 open-webui.yamlにはGoogle Driveに関する設定がコメントアウトされた状態で含まれています。コメントアウトを解除して設定します。

以下の部分のコメントを解除してください。

(略)
        # - name: ENABLE_GOOGLE_DRIVE_INTEGRATION
        #   value: 'True'
(略)
        # - name: GOOGLE_DRIVE_CLIENT_ID
        #   valueFrom:
        #     secretKeyRef:
        #       key: latest
        #       name: open_webui_google_drive_client_id
        # - name: GOOGLE_DRIVE_API_KEY
        #   valueFrom:
        #     secretKeyRef:
        #       key: latest
        #       name: open_webui_google_drive_api_key
(略)

Google Drive対応版Open WebUIのデプロイ

作成したopen-webui.yamlを使用してデプロイします。

gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed

アップロード機能を使ってみる

チャット入力欄の「+」からGoogle Driveを選択すると、OAuthの認可画面が表示されます。 許可を認めることで、Google Driveのファイルをアップロードすることができます。

Google Driveのファイルをアップロードすることができます

まとめ

長文になりましたが、Open WebUIの実装について様々なパターンを紹介できたのではないでしょうか。

Cloud ArmorやIdentity-Aware Proxy(IAP)によるセキュリティ設定、VPCを活用したスケーリング対応など、Google Cloudの機能を活用することで、Open WebUIをより安全かつ安定的に運用できます。

本記事で解説したCloud ArmorやIdentity-Aware Proxy(IAP)は導入が比較的容易で、高い効果を発揮します。これらの知識は他のシステムにも応用可能です。

また、今回は詳しく触れませんでしたが、Cloud RunにはGPUコンテナオプション(一部リージョンのみのベータ機能)があります。このGPUを活用することで、ollamaをCloud Run内で実行し、Open WebUI上でセキュアなLLM実行環境を構築することも可能です。

Cloud Runは様々なアプリケーションの実行基盤として活用できます。ぜひ本記事を参考に、独自のユースケースでも試してみてください。

SHARE

  • facebook
  • twitter

SQRIPTER

AGEST Engineers

AGEST

記事一覧

AGESTのエンジニアが情報発信してます!
AGESTのサービスやソリューションのお問い合わせページはこちらです。

株式会社AGEST

RANKINGアクセスランキング
#TAGS人気のタグ
  • 新規登録/ログイン
  • 株式会社AGEST
NEWS最新のニュース

Sqriptsはシステム開発における品質(Quality)を中心に、エンジニアが”理解しやすい”Scriptに変換して情報発信するメディアです

  • 新規登録/ログイン
  • 株式会社AGEST