11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ローカルLLMが落ちても自動で切り替えたい:Ollama連携をEnvoy AI Gatewayで試してみた

11
Posted at

はじめに

こんにちは。本記事は「Envoy AI Gateway」関連記事、第3回となります。

  • モデルを変える度にコードを修正したくない
  • 特定のモデルが落ちた時に、自動で別のモデルに切り替えてほしい
  • 誰がどれだけトークンを使っているのか把握したい

このような悩みを解決してくれるのがAI Gatewayです。

前々回の記事では、AI GatewayおよびEnvoy AI Gatewayの概要や特徴に関してまとめました。

Envoy AI Gateway は、クラウドネイティブなプロキシとして実績のある Envoy Proxy、Envoy Gateway をベースに構築されています。これにより、使い慣れたKubernetesのリソース定義で、冒頭で挙げたAI運用のよくある悩みを解決するAI Gatewayを簡単に導入、運用できるようになります。

前回の記事では、ローカルKubernetes上でMock LLM(テスト用の固定文をランダムに返すLLM)を用いたモデル切り替え機能の検証を行いました。

今回は、より実運用に近づき、Mock LLMではなくローカルLLM(Ollama)を用いてEnvoy AI Gatewayの動作を検証します。
さらに、モデル切替機能だけでなく、実務で重要になるトークン管理についても触れていきます。

今回検証したこと

構築した環境

最終的に構築した検証環境は以下の図の通りです。
詳しい構築手順については次章以降で解説します。

image.png

※Kubernetes関連のアイコンは、Kubernetes Icons Set を使用しています。
※本アイコンセットは CC BY 4.0 の条件に基づき利用しています。

検証環境

今回の検証で使用した環境は以下の通りです。

項目 詳細
OS Linux(Ubuntu Server 24.04 LTS)
Kubernetesクラスタ構築ツール kind(v0.31.0)
Kubernetes CLI kubectl(v1.35.2)
パッケージマネージャー Helm(v3.20.0)
推論エンジン Ollama(0.18.3)
使用モデル Qwen3:0.6b

準備:Ollamaのインストールと動作確認

まず、推論エンジンとなる Ollama をインストールします。

Linux環境では公式スクリプトで簡単に導入でき、systemdで管理可能です。

curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl enable ollama
sudo systemctl start ollama

次にOllamaで使用するモデルをpullします。
今回は軽い検証用として Qwen3の0.6Bを使用します。

ollama pull qwen3:0.6b

ollama pull時にi/o timeoutが発生した話

社内のネットワーク制限によりollama pullが通らない場合があると思います。
私の場合は今回の検証で以下の事象に遭遇しました。

  • プロキシ設定済みのLinux環境でレジストリ(registry.ollama.ai)に到達できない。
  • 同ネットワーク内のWindows環境では成功。

原因の考察
Windows環境では、端末側のセキュリティ機能によりSSL/TLS通信に必要な証明書まわりの処理が自動で行われた一方、Linux環境では同様の処理が行われず、社内ネットワークのセキュリティ制限により通信が阻まれた可能性があります。

解決策
Windows環境(WSL)でPullしたモデルをSCPで転送することにしました。

scp -r /usr/share/ollama/.ollama/models <ユーザー名>@<ホスト名>:/home/ユーザー名/

Linux環境で受け取ったモデルを配置→権限修正→Ollama再起動して完了です。

sudo mkdir -p /usr/share/ollama/.ollama
sudo cp -r ~/models /usr/share/ollama/.ollama/
sudo chown -R ollama:ollama /usr/share/ollama/.ollama
sudo systemctl restart ollama

本手順を実施する際は、社内のセキュリティルール(データ持ち込み、SCP転送など)をご確認のうえ、ご対応ください。

モデルを正常にpullできたかを確認します。

ollama list

以下のように表示されていたらOKです。

$ ollama list
NAME          ID              SIZE      MODIFIED
qwen3:0.6b    7df6b6e09427    522 MB    52 seconds ago

Ollamaに対してリクエストを送り、指定したモデルから応答が返ることを確認します。

curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3:0.6b",
    "messages": [
      {
        "role": "user",
        "content": "こんにちは。ひとこと自己紹介してください。"
      }
    ]
  }'

以下のように、質問の回答になっているような応答が返ってきたら成功です。

{
  "id":"chatcmpl-529",
  "object":"chat.completion",
  "created":1774596846,
  "model":"qwen3:0.6b",
  "system_fingerprint":"fp_ollama",
  "choices":[
    {
      "index":0,
      "message":{"role":"assistant","content":"こんにちは!  \nこんにちは!私の名前は、「**知識の山**」です。  \nあなたために情報や質問を貰いたい場合、どうぞお気軽にお声をかけますね!  \n何か質問やお手伝いしたいことがあります!  \nご質問があれば、教えて貰ってます!😊",
      "reasoning":"Okay, the user just said \"こんにちは. 自己紹介して,\" which translates to \"Hello! Hello, introduce yourself.\" I need to respond to this.\n\nFirst, I should start with a friendly greeting. Then, perhaps ask how I can help. Let me think of a natural way. Maybe say something like, \"Hello! How can I assist you today?\" to keep it simple and open-ended.\n\nI also want to make sure I'm polite and not too formal. Maybe add a little enthusiasm to keep the conversation going. Something like, \"I'm excited to help you with something!\" Then offer further assistance. Keep it concise but lively. Alright, that should work.\n"},
      "finish_reason":"stop"
    }
  ],
  "usage":{"prompt_tokens":17,"completion_tokens":212,"total_tokens":229}
}

以上で、Ollamaの動作確認まで完了しました。

検証①:モデルを手動で切り替えてみる

backendをMock LLMからローカルLLM(Ollama)にしてみます。

前回の記事と同じ環境をまずは作成します。

Kubernetesクラスタの構築、およびEnvoy Gateway、Envoy AI Gatewayのインストールが完了している方は、以下の3つのYAMLファイルをapplyしてもらえればOKです。

  • 公式リポジトリのbasic.yaml
  • 私が公開しているリポジトリenvoy-ai-gateway-customのollama-backend.yaml
  • 同リポジトリのaigwroute-ollama.yaml

ollama-backend.yamlは、ローカルで動作しているOllamaをEnvoy AI Gatewayのバックエンドとして登録するためのマニフェストです。
aigwroute-ollama.yamlは、リクエストヘッダーに応じて、Mock LLMとOllamaへルーティングするためのマニフェストです。

basic.yamlについては前回の記事で解説しています。

kubectl apply -f https://raw.githubusercontent.com/envoyproxy/ai-gateway/main/examples/basic/basic.yaml
kubectl apply -f manifests/ollama-backend.yaml
kubectl apply -f manifests/aigwroute-ollama.yaml

ollama-backend.yamlをapplyする前に、addressをOllamaが動作しているホストのIPアドレスに変更してください。

次にOllamaを使用するために、ollama-backend.yamlを作成してapplyします。
エンドポイントにはローカル完結でやる場合は自身のipアドレスを指定します。
#自身のipアドレスのポート11434がOllama Serverのエンドポイントのため。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: ollama-local
  namespace: default
spec:
  endpoints:
    - ip:
        address: X.X.X.X
        port: 11434
---
apiVersion: aigateway.envoyproxy.io/v1beta1
kind: AIServiceBackend
metadata:
  name: ollama-openai-backend
  namespace: default
spec:
  schema:
    name: OpenAI
  backendRef:
    group: gateway.envoyproxy.io
    kind: Backend
    name: ollama-local

続いてモデルのルーティングルールを決めているAIGatewayRouteを編集します。

先程作成したbackendに則って、model-bのbackendRefsについてnameをollama-openai-backendに変更します。そして、先程pullしたモデル名でオーバーライドします。モデル名はollama listで確認できます。

apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: AIGatewayRoute
metadata:
  name: envoy-ai-gateway-basic
  namespace: default
spec:
  parentRefs:
    - name: envoy-ai-gateway-basic
      kind: Gateway
      group: gateway.networking.k8s.io
  rules:
    - matches:
        - headers:
            - type: Exact
              name: x-demo-model
              value: model-a
      backendRefs:
        - name: envoy-ai-gateway-basic-testupstream
    - matches:
        - headers:
            - type: Exact
              name: x-demo-model
              value: model-b
      backendRefs:
-       - name: envoy-ai-gateway-basic-testupstream-b
+       - name: ollama-openai-backend
+         modelNameOverride: qwen3:0.6b

確認します。

curl -i http://localhost:8080/v1/chat/completions -H "Content-Type: application/json" -H "x-demo-model: model-b" -d '{ "model": "anything", "messages": [ { "role": "user", "content": "自己紹介をしてください。" } ] }'

ルーティングルールを変更したことにより、バックエンドで稼働するモデルが Mock LLM から Ollama に変更され、出力が自己紹介ぽく変化します。

{
  "id":"chatcmpl-453",
  "object":"chat.completion",
  "created":1782734424,
  "model":"qwen3:0.6b",
  "system_fingerprint":"fp_ollama",
  "choices":[{
    "index":0,
    "message":{
      "role":"assistant",
      "content":"こんにちは!私は以下の資格を持ちます。  \n- 業績経験(実践的なスキル)  \n- 日常業務・コミュニケーション・協力・問題解決スキル  \n- 自分の価値 proposition として紹介してみせます。  \n\n何かありますか?私と何をしてみましょうか?😊","reasoning":"Alright, the user wants me to introduce myself. I should start with a friendly greeting. I need to make sure I mention my name, my role, and maybe some basic details like my skills. It's important to keep the tone warm and approachable. I should also include some self-introduction elements if I can. Let me check if I have all the necessary information and make sure to keep it concise.\n"},
      "finish_reason":"stop"
      }],
      "usage":{"prompt_tokens":17,"completion_tokens":142,"total_tokens":159}
  }

検証②:モデルを自動で切り替えてみる

Envoy AI Gatewayには標準で、Provider fallback機能があります。
フォールバックとは、優先して使うバックエンド(プライマリ)が失敗した際に、代替のバックエンド(セカンダリ)へ自動で切り替える仕組みです。

公式ドキュメントによるとプライマリのAIプロバイダが失敗した場合に、セカンダリに指定した別のAIプロバイダへフォールバック(自動切替)可能です。また、別のプロバイダでなく同じプロバイダ上の別モデルへフォールバックも可能です。

今回はプライマリにOllama、セカンダリにMock LLMを指定して、Ollamaを停止した時の挙動を確認してみようと思います。

AIGatewayRouteに以下のルートを追加します。
#aigwroute-failover.yamlをapplyでもOKです。

    - matches:
        - headers:
            - name: x-demo-model
              type: Exact
              value: model-c
      modelsOwnedBy: Envoy AI Gateway
      backendRefs:
        - name: ollama-openai-backend
         modelNameOverride: qwen3:0.6b
          priority: 0   # Primary
          weight: 1
        - name: envoy-ai-gateway-basic-testupstream
          priority: 1   # Secondary
          weight: 1

以下のリクエストを送り、確認します。

curl -i http://localhost:8080/v1/chat/completions   -H "Content-Type: application/json"   -H "x-demo-model: model-c"   -d '{ "model": "qwen3:0.6b", "messages": [ { "role": "user", "content": "Hello." } ] }'

ルート設定に合わせて、リクエストを"x-demo-model:model-c"、"model":"qwen3:0.6b"として、Ollamaへ送ることが想定されているリクエストを送信します。

先程同様にOllamaが返答してくれます。

{"choices": [{
  "index": 0,
  "message": {
    "role": "assistant",
    "content": "You're gonna need a bigger boat."},
    "finish_reason": "stop"
    }],
    "usage": {"prompt_tokens": 1,"completion_tokens": 100,"total_tokens": 300}
}

ここでOllamaを停止します。

sudo systemctl stop ollama

全く同じリクエストを再送します。
※"model":"qwen3:0.6b"のままです。

{"choices": [{
  "index": 0,
  "message": {
    "role": "assistant",
    "content": "The quick brown fox jumps over the lazy dog."
    },
    "finish_reason": "stop"
  }],
    "usage": {"prompt_tokens": 1,"completion_tokens": 100,"total_tokens": 300}
}

上記のようにMock LLMからランダムな固定文が返ってきて、
自動でフォールバックしてくれたことが分かります。

これにより、アプリケーション側の実装を変更することなく、
モデル障害時の可用性を向上させることができました。

sudo systemctl start ollama

最後にOllamaを再度起動しておきます。

検証③:トークン情報を可視化してみる

Envoy AI Gateway では、Envoy Gateway と同様に Prometheus との連携が可能です。これにより、AI/LLM の利用状況をメトリクスとして収集し、可視化できます。

今回は、ローカルPCにPrometheus をデプロイし、Envoy AI Gateway が公開するメトリクスを実際に確認してみます。

Prometheusとは?
メトリクス収集・監視のためのOSSです。アプリケーションが公開するメトリクスを定期的に収集し、時系列データとして保存・分析できます。

公式リポジトリには、Prometheus などの監視環境をデプロイするためのマニフェストが用意されているため、以下のコマンドを実行して、Kubernetes クラスタに適用します。

kubectl apply -f https://raw.githubusercontent.com/envoyproxy/ai-gateway/main/examples/monitoring/monitoring.yaml

これにより、Prometheus を使って Envoy AI Gateway のメトリクスを収集できるようになります。

収集できるメトリクスの例

たとえば、以下のような情報を可視化できます。

  • トークン使用量
  • リクエスト処理時間
  • 最初のトークンが返るまでの時間(TTFT: Time To First Token)
  • リクエスト数
  • エラー数
  • モデル別・バックエンド別の利用状況

Prometheus の画面にアクセスして、実際にどのようなメトリクスが取得できているのか見ていきます。
以下のコマンド実行後に、http://localhost:9090 を開くとPrometheus のWeb UIにローカルからアクセスできます。

kubectl port-forward -n monitoring svc/prometheus 9090:9090

例えば、リクエスト処理時間の合計(gen_ai_server_request_duration_seconds_sum)を見てみます。

image.png

「How are you?」のような簡単な質問をした時と、「Envoy AI Gatewayについて教えて。」といった少し難しい質問をした時を比較し、処理時間の違いを可視化できていることが確認できました。

次に使用したトークン数の合計(gen_ai_client_token_usage_sum)も見てみます。

image.png

image.png

リクエスト処理時間と同様に、リクエスト内容によって使用トークン数に差があることが確認できました。また、入力と出力でも使用トークン数に大きな差があることが分かりました。

【おまけ】Grafanaで可視化する

Prometheusで取得したメトリクスをGrafanaにも簡単に取り込むことができます。
ダッシュボード

grafana.yamlを作成してmonitoring namespaceに適用します。

grafana.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
        - name: grafana
          image: grafana/grafana:latest
          ports:
            - containerPort: 3000
          env:
            - name: GF_SECURITY_ADMIN_USER
              value: admin
            - name: GF_SECURITY_ADMIN_PASSWORD
              value: admin
---
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: monitoring
spec:
  type: ClusterIP
  selector:
    app: grafana
  ports:
    - name: http
      port: 3000
      targetPort: 3000
kubectl apply -f grafana.yaml
kubectl port-forward -n monitoring svc/grafana 3000:3000

ブラウザで http://localhost:3000 を開き、ダッシュボードを作成することができます。
本記事では詳細な作成方法は割愛しますが、作成例は以下です。

image.png

トークン使用量やリクエスト処理時間などが1つのダッシュボードで一目でわかりやすく管理できることが確認できました。

まとめ

本記事では、前回に引き続き「Envoy AI Gateway」の検証を行いました。今回はより実運用を意識した構成で、主に以下の内容を確認することができました。

  • Ollama連携
    • アプリ側のコードを一切書き換えることなく、バックエンドを実用的なローカルLLMへと柔軟に切り替えられる。
  • フォールバック機能
    • 特定のモデルが停止しても自動で別モデルへ切り替わり、サービスを継続できる高い信頼性を確保できる。
  • トークン情報の可視化
    • Prometheus形式のメトリクスが提供されているため、簡単にトークン情報の可視化が行える。
    • トークン使用量や処理時間をモデルごとに把握でき、コスト管理やパフォーマンス改善ができる。

Envoy AI Gatewayを活用することで、AI基盤の運用をより柔軟に行える可能性を感じました。

今後について

全3回にわたり調査・検証してきた「Envoy AI Gateway」ですが、本シリーズとしては今回でひとまず一区切りにしたいと思います。
今後は「まずは動かして試してみる」というフェーズから一歩進んで、実際にどのようなユースケースで活用できるのかを探索していく予定です。

Envoyに限らず、AI Gatewayまわりの調査は引き続き行い、具体的な活用例や追加で検証したいテーマが見えてきた際には、また記事としてまとめたいと思います!

本記事に興味を持っていただけた方、今後の取り組みにも興味を持っていただけた方は、
ぜひ【フォロー】や【いいね】をいただけると嬉しいです!

11
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?