Docker上でOllamaとOpen WebUIを使ったローカルAIサーバーの構築:セルフホスト型RAGとWeb検索

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

アプローチの比較:ベアメタル vs. Docker化されたローカルAI

自宅ラボ(ホームラボ)のハードウェアで大規模言語モデル(LLM)を実行する際、最終的な論点は1つに行き着きます。週末をCUDAの依存関係のデバッグに費やしたいのか、それともAIアシスタントを活用した実用的なワークフローを構築したいのかということです。セルフホストでの推論環境には、主に3つのアーキテクチャが存在します。

  • 生のllama.cpp / CLIバイナリ: ホスト上で直接llama.cppをコンパイルすることで、最大限のスループットと最小限のメモリオーバーヘッドを実現できます。しかし、GGUF形式の重みファイルを手動で管理し、専用のAPIシムを作成し、フロントエンドと連携させる作業は、日常的なメンテナンスを非常に面倒なものにします。
  • プロダクション向けエンジン(vLLM / TGI): PagedAttentionや継続的バッチ処理(continuous batching)を備えた高スループットフレームワークは、マルチテナントの本番環境で真価を発揮します。しかし、シングルユーザーの自宅ラボ環境では、vLLMはデフォルトでVRAMの最大90%を事前確保してしまう上、標準のユーザーインターフェースが付属していません。
  • Docker上のOllama + Open WebUI: Ollamaは、シンプルなREST APIの背後で量子化、GPUオフロード、モデルのプルを適切に処理します。OllamaとOpen WebUIの両方をDockerコンテナにパッケージ化することで、ホストシステムをクリーンに保てます。さらに、マルチユーザー認証、チャット履歴、ドキュメントRAG、リアルタイムWeb検索が導入直後から利用可能です。

多くの自宅ラボ環境において、OllamaとOpen WebUIをコンテナ化して組み合わせる構成は、実行速度とメンテナンスの手軽さのバランスが最も取れた最適な選択肢です。

プライベートAIスタック運用のトレードオフ

セルフホストは完全なプライバシーをもたらしますが、ハードウェアの制約により実行可能なモデルには明確な限界があります。

メリット

  • 完全なデータプライバシー: プロンプト、社内文書、独自のソースコード、チャットログがローカルLANの外部に出ることは一切ありません。
  • トークン従量課金ゼロ: ハードウェアを用意してしまえば、1日50万トークンを処理しても発生するコストは消費電力分(負荷時で概ね30W〜250W程度)のみです。
  • オフライン動作: インターネット接続が切断された場合でも、コーディングアシスタント、要約ツール、社内ナレッジベースは停止せずに動作し続けます。
  • きめ細かな制御: コンテキストウィンドウサイズ、サンプリング温度、チャンクのオーバーラップ率、ベクトル埋め込みモデルなどを自由にカスタマイズできます。

デメリット

  • VRAM容量によるモデルサイズの制限: 量子化された8Bモデルの場合、重みとコンテキストを含めて約5.5GB〜6GBのVRAMが必要です。70Bクラスのモデルにステップアップするには、複数のGPUにまたがって少なくとも40GB〜48GBのVRAMが必要になります。
  • CPUフォールバック時の低速化: RTX 3060 12GBであればLlama 3.1 8B(Q4_K_M)で毎秒約35〜45トークンを出力できますが、GPUアクセラレーションのない8コアCPUでは、毎秒3〜6トークン程度まで速度が低下します。

セルフホスト環境は、複雑なマルチステップ推論の面ではクラウドの最先端モデルに及ばない場合もありますが、サブスクリプション料金が不要で、予測可能なレイテンシとデータに対する完全な制御権を得ることができます。

推奨ハードウェア要件

バックグラウンドで埋め込みパイプラインを実行しながらも快適な推論レスポンスを維持するために、以下のハードウェア構成を目安にしてください。

  • ホストOS: Ubuntu Server 24.04 LTS または Debian 12 (bookworm)。
  • GPU: 8GB〜16GBのVRAMを搭載したNVIDIAグラフィックボード。RTX 3060 12GB、RTX 4060 Ti 16GB、または中古のRTX 3090 24GBであれば、8Bクラスのモデル(Llama 3.1、Mistral 7B、DeepSeek-R1-Distill-Qwen-8B)を快適に動作させることができます。最新のDDR5システムメモリでも1B〜3B程度の軽量モデルなら動作しますが、快適なパフォーマンスを得るにはGPUが必須です。
  • システムメモリ: ドキュメントの埋め込み処理とベクトルインデックス作成の並行処理によるメモリ不足(OOM)を防ぐため、最低32GB以上のRAMを推奨。
  • ストレージ: 100GB以上の空き容量を持つ高速なNVMe SSD。モデルの重みファイルに1つあたり4GB〜15GB必要なほか、Open WebUIのChromaDBベクトルストア用の容量も確保する必要があります。
  • ランタイム: Docker Engine 24.0以上およびNVIDIA Container Toolkit。

ステップ別の構築手順

Docker Composeを使用して、GPUアクセラレーションを有効化したOllama、フロントエンドのOpen WebUI、そしてプライバシー重視のWeb検索連携を行うSearXNGの3つのコンテナで構成されるスタックを構築します。

ステップ 1: NVIDIA Container Toolkitのインストール

NVIDIA GPUを搭載している場合は、DockerからCUDAに直接アクセスできるようにContainer Toolkitをインストールします。

# NVIDIA Container Toolkitのリポジトリを追加
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

# ツールキットをインストールしてDockerを設定
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

ステップ 2: Docker Compose設定ファイルの作成

スタック用のプロジェクトフォルダを作成し、Compose定義ファイルを作成します。

mkdir -p ~/homelab/local-ai && cd ~/homelab/local-ai
nano docker-compose.yml

以下のサービス設定を記述します。

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ./ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

  searxng:
    image: searxng/searxng:latest
    container_name: searxng
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - SEARXNG_BASE_URL=http://searxng:8080/
    volumes:
      - ./searxng_data:/etc/searxng

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    restart: unless-stopped
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_SECRET_KEY=generate-a-random-32-char-secret-here
      - ENABLE_RAG_WEB_SEARCH=True
      - RAG_WEB_SEARCH_ENGINE=searxng
      - SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json
    volumes:
      - ./open_webui_data:/app/backend/data
    depends_on:
      - ollama
      - searxng

ステップ 3: コンテナの起動とモデルのダウンロード

バックグラウンドでスタックを起動します。

docker compose up -d

次に、Ollamaに対話用の8Bモデルと専用の埋め込みモデルをプルします。

# Llama 3.1 8Bをプル (~4.7 GB)
docker exec -it ollama ollama pull llama3.1:8b

# ドキュメント検索用の埋め込みモデルをプル (~274 MB)
docker exec -it ollama ollama pull nomic-embed-text

ステップ 4: Open WebUIの設定

  1. ブラウザを開き、http://<サーバーのIPアドレス>:3000 にアクセスします。
  2. 管理者アカウントを登録します。最初に登録されたユーザーに自動的に完全な管理者権限が付与されます。
  3. Admin Panel > Settings > Documents に移動します。Embedding Model Engine を ollama に設定し、ドロップダウンから nomic-embed-text を選択します。これにより、メインモデルのリソースを浪費することなく、ドキュメントのチャンク分割処理を専用モデルにオフロードできます。
  4. Admin Panel > Settings > Web Search に移動します。検索機能が有効になっており、エンジンが SearXNG に、クエリURLが http://searxng:8080/search?q=<query>&format=json に設定されていることを確認します。

ステップ 5: ドキュメントRAGとリアルタイムWeb検索のテスト

新しいチャットを開始して、両方の機能が動作するか確認します。

  • ドキュメント検索(RAG): 添付アイコン(+)をクリックし、PDF、テキストファイル、またはコードリポジトリのエクスポート(例:20ページのサーバーマニュアルなど)をアップロードします。その内容について具体的な質問を投げかけてみてください。Open WebUIがドキュメントのチャンクを埋め込みベクトル化し、ローカルのベクトルデータベースを検索して、関連スコアの高いスニペットをプロンプトのコンテキストに直接注入します。
  • リアルタイムWeb検索: チャットバーの地球アイコンを有効化し、「Debian 12の最新のセキュリティアドバイザリは何ですか?」といった最新情報を質問します。Open WebUIがSearXNGに問い合わせて検索結果を解析し、回答内に情報ソースの引用元を直接明記します。
Share: