はじめに
生成AI / LLM を活用したサービスは、ここ最近ますます増えてきています。そのため、複数のLLM APIを安全かつ効率的に扱うための仕組みが求められるようになってきました。そこで注目されているのが AI Gateway です。
前回の記事「Envoy AI Gatewayとは?AI時代のAPIゲートウェイについて調査してみた」では、Envoy AI Gatewayの概要や特徴を整理しました。
今回はその続編として、ローカルKubernetes環境にEnvoy AI Gatewayをデプロイし、モックLLMのモデル切り替えを試す手順と結果について紹介します。
Envoy AI Gatewayとは?
AI Gatewayとは、生成AI / LLM 向けのリクエストを中継・制御するためのAI特化型 API Gateway です。
Envoy AI Gatewayもその1つであり、CNCF プロジェクトのOSSである Envoy Proxy / Envoy Gateway をベースに構築されています。
Kubernetesネイティブに設定・運用できる点も大きな特徴です。
詳しい概要やアーキテクチャパターンなどの3つの特徴については、前回の記事をご覧ください。
今回検証したいこと
今回は Envoy AI Gateway の AI 特化機能の一つである 「複数 LLM モデルの切り替え」 をローカル環境で試します。
ローカル Kubernetes 上に 2 種類のモックLLM(モデル)を配置し、HTTP ヘッダによってモデルを切り替える検証を行います。
本検証では、クライアントからは、同じ API エンドポイントにリクエストを送り、Gateway 側の設定によって「どのモデルにルーティングされるか」が変わることを確認します。
構築した環境
最終的に構築した検証環境とHTTPリクエストの流れは以下の通りです。
詳しい構築手順については次章で解説します。
モックLLMとは、Envoyプロジェクトが公開しているテスト用(ダミー)のLLMサーバーになります。
本検証では実LLM(OpenAI など)は使用していません。
検証環境構築手順
Envoy AI Gateway を、公式ドキュメントに沿ってローカル Kubernetes 環境へデプロイしていきます。
今回の検証では、以下の手順で環境を構築しました。
- 前提条件の確認
- kindによるローカルKubernetesクラスタ構築
- Envoy Gateway のインストール
- Envoy AI Gateway のインストール
- HTTPリクエストの疎通確認
- LLMサーバーをもう1台たてて、モデルのルーティングを設定する
kind(Kubernetes IN Docker)とは?
DockerコンテナとしてKubernetesノードを立ち上げて、ローカルPC上にKubernetesクラスタを作るツール
1. 前提条件の確認
公式ドキュメントのPrerequisitesによると、以下が必要です。
- Kubernetes: バージョン 1.32 以上
- Helm: v3.12 以上
- kubectl: 利用可能であること
- インターネット接続: Helm chartやコンテナイメージ取得に必要
- CRD追加権限: cluster-admin推奨
以下のコマンドでバージョンをご確認ください。
kubectl version --client
helm version
また、今回私が使用した検証環境やツールは以下になります。
- OS:Linux(Ubuntu Desktop 24.04.3 LTS)
- Kubernetesクラスタ構築方法:kind(v0.31.0)
- 実行基盤:Docker Engine(Version: 28.5.1)
- ツール:kubectl, helm, jq
$ kubectl version
Client Version: v1.34.1
$ helm version
v3.19.2
$ kind version
kind v0.31.0 go1.25.5 linux/amd64
2. kindによるローカルKubernetesクラスタ構築
今回は、ローカル環境で完結させるために kindを使用してクラスタを構築します。
kind create cluster
3. Envoy Gateway のインストール
Envoy AI Gateway は Envoy Gateway の上に構築される ため、先に Envoy Gateway をインストールします。
helm upgrade -i eg oci://docker.io/envoyproxy/gateway-helm \
--version v0.0.0-latest \
--namespace envoy-gateway-system \
--create-namespace \
-f https://raw.githubusercontent.com/envoyproxy/ai-gateway/main/manifests/envoy-gateway-values.yaml
kubectl wait --timeout=2m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available
4. Envoy AI Gateway のインストール
次に、Envoy AI Gateway の CRD(Custom Resource Definitions) および Controller を Helm chartを使ってインストールします。
Helm chartとは?
Kubernetes用のパッケージマネージャー「Helm」で扱うリソース定義のひとまとまり。
複数のYAMLファイルをまとめてインストール・管理できます。
CRDとは?
Custom Resource Definitionsの略で、Kubernetes APIを拡張して独自のリソースを定義する仕組みです。
例:DeploymentやPodなどの標準リソースに加え、独自の設定項目を追加できます。
CRDのインストール
Kubernetes APIに独自リソースを追加するため、先にCRDを適用します。
本体のインストール前に行わないとEnvoy AI Gateway用のリソースが認識されず作成できないので、注意が必要です。
helm upgrade -i aieg-crd oci://docker.io/envoyproxy/ai-gateway-crds-helm \
--version v0.0.0-latest \
--namespace envoy-ai-gateway-system \
--create-namespace
Controllerのインストール
次に、Envoy AI Gateway本体をインストールします。
helm upgrade -i aieg oci://docker.io/envoyproxy/ai-gateway-helm \
--version v0.0.0-latest \
--namespace envoy-ai-gateway-system \
--create-namespace
kubectl wait --timeout=2m -n envoy-ai-gateway-system deployment/ai-gateway-controller --for=condition=Available
以下のコマンドでコントローラーがインストール出来たことを確認します。
kubectl get pods -n envoy-ai-gateway-system
出力例
NAME READY STATUS RESTARTS AGE
ai-gateway-controller-776c978d65-bpc9t 1/1 Running 0 100m
ai-gateway-controller が Running (1/1) になっていれば、Envoy AI Gatewayのコントローラーが正常に起動しています。
この時点でクラスタに入っているものは以下の表の通りです。
| Namespace | 入っているもの |
|---|---|
| envoy-gateway-system | Envoy Gateway Controller |
| envoy-ai-gateway-system |
Envoy AI Gateway CRDs Envoy AI Gateway Controller |
5. HTTPリクエストの疎通確認
公式サイトのBasic Usageに則って、basic.yamlを適用し、HTTPリクエストが通ることを確認します。
kubectl apply -f https://raw.githubusercontent.com/envoyproxy/ai-gateway/main/examples/basic/basic.yaml
basic.yamlを適用すると作られるリソースは以下になります。
| リソース種別 | APIグループ・説明 |
|---|---|
| GatewayClass | Kubernetes Gateway API(標準)。 どの Gateway コントローラ実装が処理するかを定義するクラス。 |
| Gateway | Kubernetes Gateway API(標準)。
GatewayClass を参照し、ポート・プロトコルなどを定義する。 実際の外部トラフィックの入口を表すリソース。 |
| ClientTrafficPolicy | Envoy Gateway 独自 CRD。 クライアント接続に対する制御(バッファ制限、タイムアウトなど)。 |
| AIGatewayRoute | Envoy AI Gateway 独自 CRD。 AI リクエストのルーティングルール(モデル名・ヘッダ等による振り分け)。 |
| AIServiceBackend | Envoy AI Gateway 独自 CRD。 AI 向けバックエンドサービス(LLM やモックサーバー)の定義。 |
| Backend | Envoy Gateway 独自 CRD。 実際の転送先(Service など)を抽象化したバックエンド定義。 |
| Deployment | テスト用 LLM サーバーの Pod を起動する Kubernetes 標準リソース。 |
| Service | upstream Pod の 8080 番ポートを Cluster 内で公開する Kubernetes 標準リソース。 |
| EnvoyProxy | Envoy Gateway が生成するデータプレーン定義リソース。 (実体は Envoy Proxy Pod) |
今回は kubectl port-forward を使ってローカルからアクセスします。
kubectl port-forward <pod名 / Service名> <転送先ポート番号>:<転送元ポート番号>
ローカルマシンのポートを Kubernetes クラスタ内の Pod や Service のポートに一時的に転送し、直接アクセスできるようにする機能。
まず、GatewayのEnvoy Service名を取得します。
export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system \
--selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=envoy-ai-gateway-basic \
-o jsonpath='{.items[0].metadata.name}')
echo $ENVOY_SERVICE
出力例:
envoy-default-envoy-ai-gateway-basic-21a9f8f8
port-forward を実行します。
kubectl port-forward -n envoy-gateway-system svc/$ENVOY_SERVICE 8080:80
別ターミナルから http://localhost:8080 に対してリクエストを送ります。
curl -sS -H "Content-Type: application/json" \
-d '{"model":"some-cool-self-hosted-model","messages":[{"role":"user","content":"Hi."}]}' \
http://localhost:8080/v1/chat/completions | jq .
出力例:
{
"choices": [
{
"message": {
"content": "I'll be back."
}
}
]
}
"I'll be back." のようなレスポンスが返ってくれば、Gateway経由での疎通ができたことになります。
6. LLMサーバーをもう1台たてて、モデルのルーティング設定をする
ここまでで Envoy AI Gateway を動かす準備が完了し、Gateway経由で応答が返ることまでを確認できました。先程のアーキテクチャ図でいう、Test Upstream A のServiceまでHTTPリクエストが到達し、Podが処理をして、「I'll be back.」などのレスポンスが返ってきました。
最後にテスト用 LLM サーバーをもう1つ用意し、HTTPヘッダでモデルが切り替えられるように設定します。
6-1. モデルB を作成する
テスト用 LLM サーバーBを立てるために必要なリソースは以下の4つです。
basic.yamlを参考にLLM サーバーAを複製していきます。
- AIServiceBackend
- Backend
- Service
- Deployment
実際に basic.yaml から必要な箇所を抜粋し、作成したYAMLファイルは以下になります。
model-b.yaml
# Test Upstream B 用のモデル定義
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: AIServiceBackend
metadata:
name: envoy-ai-gateway-basic-testupstream-b
namespace: default
spec:
schema:
name: OpenAI
backendRef:
name: envoy-ai-gateway-basic-testupstream-b
kind: Backend
group: gateway.envoyproxy.io
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
name: envoy-ai-gateway-basic-testupstream-b
namespace: default
spec:
endpoints:
- fqdn:
hostname: envoy-ai-gateway-basic-testupstream-b.default.svc.cluster.local
port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: envoy-ai-gateway-basic-testupstream-b
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: envoy-ai-gateway-basic-testupstream-b
template:
metadata:
labels:
app: envoy-ai-gateway-basic-testupstream-b
spec:
containers:
- name: testupstream
image: docker.io/envoyproxy/ai-gateway-testupstream:latest
ports:
- containerPort: 8080
env:
- name: TESTUPSTREAM_ID
value: test-b
---
apiVersion: v1
kind: Service
metadata:
name: envoy-ai-gateway-basic-testupstream-b
namespace: default
spec:
selector:
app: envoy-ai-gateway-basic-testupstream-b
ports:
- port: 80
targetPort: 8080
type: ClusterIP
作成した YAML ファイルを適用します。
kubectl apply -f model-b.yaml
6-2. AIGatewayRoute にルールを追加し、適用する
次に、既存の AIGatewayRoute(basic.yaml で作成済み)に モデルB のルールを追加します。AIGatewayRoute はルーティングルールの集合なので、モデル追加時はモデル毎に新規にリソースを作成するのではなく、 rulesを増やします。
以下のコマンドで既存のリソースを編集できます。
kubectl edit <リソース> <リソースの名前>
kubectl edit aigatewayroute envoy-ai-gateway-basic
以下のようにrulesの部分を編集します。
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
今追加したルールは、この設定をしているGatewayに来たリクエストのうち、x-demo-model: model-bというヘッダを持つ場合、envoy-ai-gateway-basic-testupstream-bというバックエンド(テスト用LLMサーバー)に送るというルールです。
この時 headers.name も x-ai-eg-model から x-demo-model に変更してください。
Envoy AI Gateway では、OpenAI 互換リクエストの body の model 値 を元に、内部的にモデル識別用ヘッダー(x-ai-eg-model)を 自動で付与・上書きしてルーティングする挙動になります。今回の検証ではヘッダーでモデルを切り替えることが目的のため、任意の値として x-demo-modelを設定しました。
これでアーキテクチャ図と同じ環境の構築が完了しました!
モデル切り替えを試してみる
環境が整ったので、早速モデル切り替えを試してみようと思います。
モデルA/Bのリクエストログを表示することで、どちらにリクエストが届いたのかを確認します。
リクエストを送信するコマンドは以下になります。
curl -H 'Content-Type: application/json' -H 'x-demo-model: model-a' --data-binary '{"model":"some-cool-self-hosted-model","messages":[{"role":"system","content":"Hi."}]}' "http://localhost:8080/v1/chat/completions"
初期状態は以下のような状態です。
一番左からリクエストを送信するターミナル、モデルAのログを表示するターミナル、モデルBのログを表示するターミナルの写真です。
ログは以下のコマンドで表示できます。
kubectl logs -n default deploy/envoy-ai-gateway-basic-testupstream -f --tail=5
kubectl logs -n default deploy/envoy-ai-gateway-basic-testupstream-b -f --tail=5
リクエストのヘッダーを-H 'x-demo-model: model-a'としてHTTPリクエストを送信してみます。
モデルA のログのみ増えていることが分かります。
続いて、リクエストのヘッダーを-H 'x-demo-model: model-b'と、ヘッダーのみ変更してHTTPリクエストを送信してみます。
モデルB のログのみ増え、モデル切り替えできたことが確認できました!
まとめ
本記事では、Envoy AI Gateway をローカル Kubernetes クラスタにデプロイし、HTTP ヘッダーによる複数 LLM モデルの振り分けを検証しました。
検証の流れとポイントは以下の通りです。
- Envoy Gateway → Envoy AI Gateway(CRD と Controller)の順にインストール
- basic.yaml を適用して Gateway と AIGatewayRoute を作成
- 追加のテスト用 LLM を Deployment/Service/Backend/AIServiceBackend としてデプロイ
- AIGatewayRoute の rules を編集し、ヘッダーによるルーティングを実現
結果として、同一エンドポイントでも、HTTP ヘッダーを切り替えるだけでモデルA / モデルBのどちらにリクエストを送るか制御できることを確認できました!
感想
Envoy AI Gateway は Kubernetes ネイティブな OSS であり、ローカル環境でも手軽に検証できる点が魅力的だと感じました。特に、公式が提供しているテスト用 LLM サーバーを利用することで、実際の LLM API を使わずに気軽に試せる点が良かったです。
公式ドキュメントの Getting Started ページも、Prerequisites(前提条件)→ Installation → Basic Usage という章立てで整理されており、初学者でも迷いにくい構成になっていました。kind などの前提ツールの準備ができていれば、環境構築自体は 1 時間もかからず完了できると思います!
今回は HTTP ヘッダーによるモデル切り替えという基本的な機能を検証しましたが、 Gateway 側の設定だけで複数モデルを扱える点は、AI Gateway ならではの強みだと感じました。
今後は、認証・メトリクス収集・レート制限・ルーティング比率の変更など、AI 特化機能を組み合わせて、より本番運用に近い構成についても検証していきたいと考えています。
次回予告
次回以降、以下のような検証を予定しています。
- モデル毎にリクエスト比率を変更する「Weighted Routing」を試してみる
- 実 LLM(OpenAIなど)をバックエンドに組み込んでみる
続編に興味のある方、本記事に興味をもっていただけた方は是非「フォロー」や「いいね」をいただけると嬉しいです!






