🦀 技術調査 - agentgateway / kgateway による AI Gateway 拡張
目次

⚠️ 非公開(zenn 未公開)

🦀 技術調査 - agentgateway / kgateway による AI Gateway 拡張

調査日: 2026-05-17 / 起点記事: CNCF Blog 2026-05-15: Extending AI Gateways with Rust Custom Transformations

概要

プロジェクトの位置づけ

agentgateway は Solo.io が主導する「AI エージェント向け次世代プロキシ」です。単なる LLM プロキシではなく、LLM Gateway・MCP Gateway・Agent-to-Agent Gateway の 3 役を一体で担います。2025-03-18 に設立され、Apache 2.0 ライセンスで公開されています。

kgateway は 2018 年に Gloo として登場した Kubernetes Gateway API + Envoy ベースの汎用 API Gateway です。2026-03-04 に CNCF Sandbox プロジェクトとして受理されており、成熟したエコシステムを持ちます。v2.3.0 以降は AI Gateway のコントロールプレーン機能を agentgateway 本体に移管し、汎用 API Gateway の役割に戻っています。

役割分担の変遷

v2_2_1以前 v2_3_0以降 kgatewayコントロールプレーン兼 AI Gateway 制御 agentgatewayデータプレーン kgateway汎用 API Gateway agentgatewayコントロール + データプレーン

v2.3.0 を境に agentgateway は自律的なコントロールプレーンを内製化しました。kgateway は汎用 API Gateway としての独立性を回復しています。

関連技術との関係

Envoy Proxyデータプレーン基盤 KubernetesGateway API MCPModel Context Protocol A2AAgent-to-Agent Rust cdylib動的拡張モジュール kgateway agentgateway

agentgateway のデータプレーンは Envoy をベースに Rust 製動的ライブラリ (cdylib) で拡張します。kgateway は Kubernetes Gateway API に準拠し、Envoy を標準データプレーンとして利用します。MCP と A2A は agentgateway の一級市民プロトコルとして組み込まれています。


特徴

特徴 1: AI / MCP / A2A ネイティブプロトコル対応

機能カテゴリ 内容
LLM Gateway OpenAI 互換 API で 14+ プロバイダを統一管理。per-team token budget / semantic cache / failover 内蔵
MCP Gateway Model Context Protocol 経由の外部ツール接続。OAuth / tool discovery / scope 管理に対応
A2A Gateway Agent-to-Agent プロトコルで capability discovery とタスク連携を実現
Inference Routing GPU 利用率ベースの自ホストモデル振り分け

対応 LLM プロバイダは OpenAI / Anthropic / Gemini / Bedrock / Azure OpenAI / Mistral / DeepSeek / Ollama / Vertex AI / Llama / xAI / Perplexity / Replicate / Snowflake の 14 種以上です。

特徴 2: Rust cdylib による高性能な動的拡張

CNCF Blog (2026-05-15) で公開されたアーキテクチャの核心は、Rust で書いた .so ファイルを Envoy が起動時に動的ロードする仕組みです。WASM のような VM コストがなく、オーバーヘッドは 0.1ms 未満を実現します。

処理フェーズ 操作
リクエスト header add / set / remove、JSON body parse & modify、raw bytes アクセス
レスポンス header add / set / remove、JSON body parse & modify

特徴 3: Kubernetes Gateway API との標準準拠

kgateway は Kubernetes Gateway API に完全準拠しており、Ingress Controller の後継として機能します。CNCF Sandbox 受理 (2026-03-04) により、中立的なガバナンス体制が整備されています。基本的な K8s リソースセットは Gateway / HTTPRoute / AgentgatewayBackend の 3 種類です。

特徴 4: セキュリティと観測可能性の内蔵

カテゴリ 内容
認証・認可 JWT + API key + RBAC + CEL policy + OPA
Guardrails Regex / OpenAI Moderation / AWS Guardrails / custom webhook
観測可能性 OpenTelemetry デフォルト有効、改ざん検証可能 (tamper-evident) 監査ログ

特徴 5: プロジェクトの成熟度と注意点

項目 agentgateway kgateway
設立 2025-03-18 2018 年 (Gloo として)
GitHub Stars 2,714 5,516
主言語 Rust 59% / Go 28% / TS 10% Go 93%
CNCF ステータス Linux Foundation プロジェクト (CNCF 個別記載未確認) CNCF Sandbox (2026-03-04)
成熟度 若い (大規模本番事例少) 成熟 (8 年の実績)

agentgateway は API Key Auth / TrafficPolicy ratelimit / Policy merge が未実装の段階です。v2.3.0 でのコントロールプレーン移管という architectural change が進行中であり、本番採用には慎重な評価が必要です。

他の AI Gateway OSS との比較

製品 拡張機構 拡張言語 オーバーヘッド MCP 対応 A2A 対応 立ち位置 GitHub Stars
agentgateway Rust cdylib (Envoy 動的モジュール) Rust <0.1ms ✅ 一級市民 ✅ 一級市民 AI/MCP/A2A ネイティブ、若い 2,714
kgateway Envoy Filter (+ agentgateway 連携) Go / Rust <0.1ms ✅ agentgateway 経由 ✅ agentgateway 経由 Kubernetes 汎用 API GW、CNCF Sandbox 5,516
Envoy AI Gateway WASM filter (proxy-wasm) C++ / Go / WASM 1–3ms - K8s 向け Envoy 由来、Apache 2.0 1,618
LiteLLM Python callback Python プロセス内 Python オーバーヘッド ✅ (MCP tool listing) - 100+ provider、企業利用最多 47,235
Kong AI Gateway Lua / Go / JS plugin Lua / Go / JS 数百μs–数ms - Plugin Hub 60+、汎用 GW 機能 43,398
Portkey TypeScript hooks TypeScript / JS JS hook レベル - 50+ guardrails、SaaS+OSS 11,749
Cloudflare AI Gateway Workers JS JavaScript / TS edge compute - - SaaS 専用、グローバル分散 非 OSS

ユースケース別の推奨

ユースケース 推奨製品 理由
AI エージェント間通信 (A2A) の統制 agentgateway A2A を一級市民で扱う唯一の OSS
MCP サーバーの集中管理・認可 agentgateway MCP Gateway が OAuth / scope 管理まで内蔵
Kubernetes 汎用 API GW + AI 拡張 kgateway CNCF Sandbox、Kubernetes Gateway API 準拠
性能クリティカルな body 変換 agentgateway (Rust cdylib) <0.1ms オーバーヘッド、WASM の 10–30 倍速
100+ LLM プロバイダへの統一アクセス LiteLLM 対応プロバイダ数が最多
LLM コスト管理・spend tracking LiteLLM spend tracking / virtual keys が充実
豊富な既製プラグインが必要 Kong AI Gateway Plugin Hub 60+
LLM 信頼性 (retry / fallback) 優先 Portkey 自動 retry / fallback が標準
グローバルエッジでの低レイテンシ Cloudflare AI Gateway SaaS だが世界規模のエッジ分散
サンドボックス分離が必要な変換 Envoy AI Gateway WASM フィルターで OS 級分離

構造

システムコンテキスト図

agentgateway CRD / Helm で設定 POST /v1/chat/completionsMCP / A2A プロトコル LLM リクエスト転送 ポリシー評価 トレース / メトリクス 設定を反映 Dev / SREインフラ・拡張開発者 AI Applicationエージェント / チャットクライアント LLM プロバイダOpenAI / Anthropic /Gemini / Bedrock 他 Kubernetes API ServerGateway API / CRD 管理 OPAポリシーエンジン ObservabilityOpenTelemetry / 監査ログ agentgatewayAI ネイティブプロキシ
要素 説明
Dev / SRE Kubernetes CRD・Helm で Gateway 設定・Rust モジュールをデプロイする開発者・運用者
AI Application LLM を呼び出すエージェント・チャットクライアント。agentgateway に対して OpenAI 互換 API / MCP / A2A で通信
agentgateway AI ネイティブプロキシ本体。LLM Gateway / MCP Gateway / A2A Gateway の 3 役を担う
LLM プロバイダ OpenAI / Anthropic / Gemini / Bedrock / Azure OpenAI / Mistral など 14+ プロバイダ
Kubernetes API Server Gateway API CRD と AgentgatewayBackend CRD の管理。Dev が設定を投入する窓口
OPA CEL policy / RBAC のポリシー評価エンジン
Observability OpenTelemetry レシーバー・監査ログストア。改ざん検証可能ログをエクスポート

コンテナ図

Control Plane Data Plane kubectl apply kubectl apply xDS 設定配信 xDS 設定配信 参照 参照 参照 dlopen / C ABI Dev / SRE kgateway汎用 API GWコントロールプレーン agentgatewayコントロールプレーンv2.3.0 で内製化 Gateway API CRDsGateway / HTTPRoute AgentgatewayBackend CRDLLM endpoint 設定 Envoy Proxykgateway 配下汎用 API トラフィック agentgatewayデータプレーンEnvoy + Rust .so Rust Dynamic Modulescdylib (.so)変換フィルター群

Control Plane

要素 説明
kgateway コントロールプレーン Go 製。Kubernetes Gateway API を解釈し、Envoy に xDS で設定配信。CNCF Sandbox (2026-03-04 受理)
agentgateway コントロールプレーン v2.3.0 で kgateway から分離・内製化。AI 専用ポリシー (token budget / guardrails / RBAC) を管理
Gateway API CRDs Gateway・HTTPRoute など Kubernetes Gateway API 標準リソース
AgentgatewayBackend CRD LLM プロバイダの endpoint・認証情報・ルーティング設定を保持する独自 CRD

Data Plane

要素 説明
Envoy Proxy (kgateway 配下) kgateway が管理する Envoy インスタンス。汎用 API / HTTP トラフィックを処理
agentgateway データプレーン Envoy をベースに AI プロトコル (MCP / A2A) 対応を追加したプロキシ
Rust Dynamic Modules (.so) cdylib 形式の共有ライブラリ。Envoy プロセス内に直接ロードされ、HTTP filter chain を拡張

コンポーネント図

Envoy プロセス (agentgateway DP) Envoy リスナー port 80 HTTP filter chain Rust .so モジュール (cdylib) Envoy 内部 POST /v1/chat/completions CEL policy HTTP / HTTPS OTel trace / audit C ABI call C ABI call C ABI call C ABI call クライアントAI Application LLM プロバイダ OPA Observability TLS 終端filter JWT / API Key認証 filter Rate Limitfilter HTTP Connection Manager on_request_headersヘッダー操作 / 認可付与 on_request_bodyJSON parse & 変換PII マスキング on_response_headersヘッダー操作 on_response_bodyJSON parse & 変換コスト計測 on_exchange_complete監査ログ書き出し TransformationOps traitheader add/set/removebody get / replace minijinja テンプレ動的変換式 serde_jsonJSON parse / serialize catch_unwindpanic ハンドラ Router filterアップストリーム選択 Cluster ManagerLLM endpoint 管理 Access LoggerOTel export

Envoy リスナー

要素 説明
TLS 終端 filter クライアントとの TLS を終端。証明書は K8s Secret から取得
JWT / API Key 認証 filter Bearer トークン・API Key を検証。CEL policy を OPA に委譲
Rate Limit filter per-team / per-model のトークン予算・レート制限を適用
HTTP Connection Manager (HCM) HTTP/1.1 と HTTP/2 を処理し、filter chain を起動するコアコンポーネント

HTTP filter chain (Rust モジュール呼び出しポイント)

要素 説明
on_request_headers リクエストヘッダーを受信した時点で呼ばれる。カスタムヘッダー付与・認可情報注入を行う
on_request_body リクエストボディ全体受信後に呼ばれる。JSON パース・PII マスキング・プロンプト編集を実行
on_response_headers LLM レスポンスのヘッダーを受信した時点で呼ばれる。ヘッダー追加・削除を行う
on_response_body LLM レスポンスボディ全体受信後に呼ばれる。JSON 変換・トークン計測・コスト記録を実行
on_exchange_complete リクエスト/レスポンスのやり取り完了後に呼ばれる。改ざん検証可能な監査ログを書き出す

Rust .so モジュール内部

要素 説明
TransformationOps trait HttpFilter trait を実装したコア変換インタフェース。header add/set/remove・body get/replace を提供
minijinja テンプレ 動的テンプレートエンジン。per-route config でテンプレート AST をキャッシュして再利用
serde_json JSON シリアライズ・デシリアライズライブラリ。end_of_stream=true のタイミングで遅延パース
catch_unwind パニックハンドラ Rust のパニックを捕捉し、Envoy プロセスのクラッシュを防ぐ安全境界。fail-closed でレスポンスを停止

Envoy 内部コンポーネント

要素 説明
Router filter HTTPRoute の一致条件に基づいてアップストリーム Cluster を選択
Cluster Manager AgentgatewayBackend CRD で定義された LLM エンドポイントを管理。load balancing / failover を担当
Access Logger on_exchange_complete 後に OTel トレース・改ざん検証可能監査ログを Observability へエクスポート

データ

概念モデル

Kubernetes Gateway API kgateway リソース agentgateway AI エンティティ Rust 拡張 GatewayClass Gateway HTTPRoute TrafficPolicy AgentgatewayBackend MCPServer A2AAgent TokenBudget Guardrail AuditLog RustModule TransformationConfig Request Response
要素名 説明
GatewayClass ゲートウェイの実装クラスを定義する Kubernetes Gateway API リソース。kgateway または agentgateway を指定する
Gateway リスナー (ポート/TLS) を保持する Kubernetes Gateway API リソース。GatewayClass に紐づく
HTTPRoute URL パスとバックエンドのマッピングを定義する Gateway API リソース。Gateway に属する
TrafficPolicy HTTPRoute に適用するトラフィック制御ポリシー (変換・レート制限等) を定義する kgateway CRD
AgentgatewayBackend LLM / MCP / A2A のエンドポイント設定を保持する kgateway CRD
TransformationConfig request/response のヘッダー・ボディ変換ルールを記述する設定オブジェクト
RustModule Envoy に動的ロードされる cdylib 形式の Rust 変換モジュール
Request ゲートウェイが受け取る HTTP リクエスト。headers・body・trailers を持つ
Response アップストリームから返る HTTP レスポンス。headers・body・trailers を持つ
MCPServer agentgateway が管理する Model Context Protocol サーバーのエンドポイント
A2AAgent agentgateway が管理する Agent-to-Agent 通信の対向エージェント
TokenBudget チームまたはルートごとのトークン消費上限を管理するエンティティ
Guardrail プロンプトや応答に対するガードレール設定 (Regex / Moderation / Webhook 等)
AuditLog 改ざん検証可能な監査ログのエントリ

情報モデル

GatewayClass string: name: string: controllerName: string: parametersRef: Gateway string: name: string: namespace: string: gatewayClassName: list: listeners: string: address: HTTPRoute string: name: string: namespace: list: parentRefs: list: hostnames: list: rules: TrafficPolicy string: name: string: namespace: string: targetRef: list: requestTransformations: list: responseTransformations: map: rateLimitConfig: AgentgatewayBackend string: name: string: namespace: string: llmProvider: string: endpoint: string: authSecretRef: string: model: string: tokenBudgetRef: list: guardrailRefs: TransformationConfig map: headersAdd: map: headersSet: list: headersRemove: string: bodyTemplate: list: conditionals: RustModule string: moduleName: string: searchPath: string: soFileName: string: envoyVersion: string: rustVersion: string: filterConfig: Request map: headers: string: body: map: trailers: int: endOfStream: Response int: statusCode: map: headers: string: body: map: trailers: int: endOfStream: TokenBudget string: teamId: int: maxTokensPerPeriod: int: periodSeconds: int: usedTokens: AuditLog string: requestId: string: timestamp: string: teamId: string: model: int: inputTokens: int: outputTokens: string: hash: Guardrail string: type: string: pattern: string: webhookUrl: string: action: MCPServer string: name: string: endpoint: map: oauthConfig: list: scopes: A2AAgent string: agentId: string: endpoint: list: capabilities: map: authConfig: instantiates 1 many routes 1 many policy 1 0..1 backend 1 many transforms 1 many executes 1 1 processes 1 many processes 1 many budget 1 0..1 guards 1 many logs 1 many mcpServers 1 many a2aAgents 1 many
要素名 説明
GatewayClass ゲートウェイ実装クラス。controllerName でコントローラー (kgateway / agentgateway) を特定する
Gateway エントリポイント。listeners でポート・プロトコル・TLS 設定を持つ
HTTPRoute ルーティングルール。rules に path マッチと backendRefs を記述する
TrafficPolicy kgateway CRD。requestTransformations / responseTransformations で変換パイプラインを定義する
AgentgatewayBackend LLM プロバイダ情報を集約。llmProvider に OpenAI / Anthropic 等を指定し model でモデル名を保持する
TransformationConfig ヘッダー追加・設定・削除と body テンプレート (Jinja / CEL) を保持する変換定義
RustModule cdylib の所在 (searchPath/soFileName) と Envoy ABI バージョン (envoyVersion) を保持する
Request Rust フィルターが受け取る入力。endOfStream フラグでストリーミング終端を判定する
Response Rust フィルターが書き換える出力。statusCodebody が主要変換対象となる
TokenBudget チーム単位のトークン上限管理。usedTokens を累積して予算超過を検知する
AuditLog 1リクエスト1エントリ。hash フィールドが改ざん検証 (tamper-evident) を担う
Guardrail type で Regex / OpenAI Moderation / AWS Guardrails / Webhook を区別し、action でブロック or マスクを指定する
MCPServer Model Context Protocol サーバー。scopes でツールアクセス範囲を制限する
A2AAgent Agent-to-Agent 対向エージェント。capabilities でタスク種別を宣言する

構築方法

必要バージョン一覧

コンポーネント バージョン 注意事項
Rust 1.85+ 1.75 以下では SDK がコンパイルエラー
Envoy v1.36.4 SDK ABI が Envoy バージョンに密結合
kgateway v2.2.1 コントロールプレーン
agentgateway v1.1.0 データプレーン
kind / k3d v0.20+ ローカル K8s クラスタ

ABI 互換は X.Y → X.(Y+1) のみ保証。Envoy メジャー更新時は SDK と .so 両方の再ビルドが必須です。

K8s クラスタセットアップ (kind)

kind create cluster --name ai-gateway-lab
kubectl cluster-info --context kind-ai-gateway-lab

Gateway API CRDs インストール

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml
kubectl wait --for=condition=Established crd/gateways.gateway.networking.k8s.io --timeout=60s

kgateway デプロイ (v2.2.1)

helm upgrade -i kgateway-crds oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds \
  --namespace kgateway-system --create-namespace --version v2.2.1
helm upgrade -i kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \
  --namespace kgateway-system --version v2.2.1 \
  --set agentgateway.enabled=true
kubectl -n kgateway-system wait --for=condition=Ready pod -l app=kgateway --timeout=120s

agentgateway デプロイ (v1.1.0)

helm upgrade -i agentgateway-crds oci://cr.agentgateway.dev/charts/agentgateway-crds \
  --namespace agentgateway-system --create-namespace --version v1.1.0
helm upgrade -i agentgateway oci://cr.agentgateway.dev/charts/agentgateway \
  --namespace agentgateway-system --version v1.1.0
kubectl -n agentgateway-system wait --for=condition=Ready pod -l app=agentgateway --timeout=120s

Rust モジュールのビルド (cdylib)

Cargo.toml

[package]
name = "my-rustformation"
version = "0.1.0"
edition = "2021"

[lib]
name = "my_rustformation"
crate-type = ["cdylib"]

[dependencies]
envoy-proxy-dynamic-modules-rust-sdk = "0.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
minijinja = { version = "2.12.0", features = ["loader"] }
anyhow = "1.0"

lib.rs (TransformationOps 実装サンプル)

use envoy_proxy_dynamic_modules_rust_sdk::*;

pub struct MyTransformationFilter {
    request_id: Option<String>,
}

impl HttpFilter for MyTransformationFilter {
    fn on_request_headers(
        &mut self,
        _num_headers: usize,
        _end_of_stream: bool,
        ops: &dyn RequestHeadersOps,
    ) -> Result<FilterHeadersStatus> {
        ops.set_header("x-custom-team-id", "team-alpha")?;
        if let Ok(Some(id)) = ops.get_header("x-request-id") {
            self.request_id = Some(String::from_utf8_lossy(id).to_string());
        }
        Ok(FilterHeadersStatus::Continue)
    }

    fn on_request_body(
        &mut self,
        _data_size: usize,
        end_of_stream: bool,
        ops: &dyn RequestBodyOps,
    ) -> Result<FilterDataStatus> {
        if !end_of_stream {
            return Ok(FilterDataStatus::StopIterationAndBuffer);
        }
        let body = ops.get_body()?;
        let mut json: serde_json::Value = serde_json::from_slice(body)?;
        if let Some(messages) = json.get_mut("messages") {
            // PII マスキング
        }
        let transformed = serde_json::to_vec(&json)?;
        ops.replace_body(&transformed)?;
        Ok(FilterDataStatus::Continue)
    }

    fn on_response_headers(
        &mut self,
        _num_headers: usize,
        _end_of_stream: bool,
        ops: &dyn ResponseHeadersOps,
    ) -> Result<FilterHeadersStatus> {
        ops.add_header("x-gateway-version", "agentgateway-1.1.0")?;
        Ok(FilterHeadersStatus::Continue)
    }

    fn on_response_body(
        &mut self,
        _data_size: usize,
        end_of_stream: bool,
        ops: &dyn ResponseBodyOps,
    ) -> Result<FilterDataStatus> {
        if !end_of_stream {
            return Ok(FilterDataStatus::StopIterationAndBuffer);
        }
        let body = ops.get_body()?;
        if let Ok(json) = serde_json::from_slice::<serde_json::Value>(body) {
            if let Some(tokens) = json.pointer("/usage/total_tokens") {
                eprintln!("[rustformation] total_tokens={}", tokens);
            }
        }
        Ok(FilterDataStatus::Continue)
    }

    fn on_exchange_complete(&mut self, _ops: &dyn ExchangeCompleteOps) -> Result<()> {
        Ok(())
    }
}

#[no_mangle]
pub extern "C" fn envoy_dynamic_module_on_program_init() -> *const std::os::raw::c_char {
    std::ptr::null()
}

マルチステージ Docker ビルド

FROM rust:1.85 AS builder
RUN apt-get update && apt-get install -y clang lld && rm -rf /var/lib/apt/lists/*
WORKDIR /build
COPY Cargo.toml Cargo.lock ./
COPY src ./src
RUN cargo build --release --target x86_64-unknown-linux-gnu

FROM envoyproxy/envoy:v1.36.4
COPY --from=builder \
  /build/target/x86_64-unknown-linux-gnu/release/libmy_rustformation.so \
  /usr/local/lib/
ENV ENVOY_DYNAMIC_MODULES_SEARCH_PATH=/usr/local/lib

最終イメージ目安: 319MB


利用方法

必須パラメータ一覧

リソース フィールド 説明
AgentgatewayBackend .spec.host LLM プロバイダのホスト名 (例: api.openai.com)
AgentgatewayBackend .spec.port ポート番号 (例: 443)
AgentgatewayBackend .spec.tls.enabled TLS 有効/無効
AgentgatewayBackend .spec.provider プロバイダ種別 (例: openai, anthropic, bedrock)
Gateway .spec.gatewayClassName kgateway を指定
Gateway .spec.listeners[].port リスナーポート (例: 80)
HTTPRoute .spec.parentRefs[].name 対象 Gateway 名
HTTPRoute .spec.rules[].matches[].path.value マッチパス (例: /v1/chat/completions)
HTTPRoute .spec.rules[].backendRefs[].name バックエンドサービス名

Gateway YAML

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: ai-gateway
  namespace: default
spec:
  gatewayClassName: kgateway
  listeners:
    - name: http
      protocol: HTTP
      port: 80

AgentgatewayBackend YAML

実際の CRD 構造は spec.ai.provider.<provider名> 配下にプロバイダ固有設定をネストします。CNCF Blog の例:

apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
metadata:
  name: openai-backend
  namespace: agentgateway-system
spec:
  ai:
    provider:
      openai:
        model: gpt-4
      host: api.openai.com
      port: 443
      path: "/v1/chat/completions"

API キーは Secret に保持し、TrafficPolicy など別リソースで参照させる構造を採用します (Blog 例は httpbun モック呼び出しのため認証部分は省略)。

HTTPRoute YAML

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: llm-route
  namespace: default
spec:
  parentRefs:
    - name: ai-gateway
      namespace: default
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v1/chat/completions
      backendRefs:
        - group: agentgateway.dev
          kind: AgentgatewayBackend
          name: openai-backend

Rust 動的モジュールの紐付け (TrafficPolicy)

kgateway の TrafficPolicy (apiVersion: gateway.kgateway.dev/v1alpha1) で Rust モジュールを HTTPRoute に紐付けます。フィルター設定は protobuf Any 型 (type.googleapis.com/google.protobuf.StringValue 等) でラップして渡します。具体的なフィールド名は kgateway バージョンで変動するため、最新の TrafficPolicy CRD リファレンスを確認してください。

apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: rust-transformation-policy
  namespace: default
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: llm-route
  # dynamicModules フィールドの正確な構文は kgateway リリースノートを参照

curl 呼び出し

GATEWAY_URL=$(kubectl get gateway ai-gateway -o jsonpath='{.status.addresses[0].value}')

curl -X POST "http://${GATEWAY_URL}/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "x-request-id: test-001" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello, world!"}],
    "stream": false
  }'

ストリーミングの場合:

curl -X POST "http://${GATEWAY_URL}/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Explain Rust in one sentence."}],
    "stream": true
  }'

SSE ストリーミング時は、中継レイヤで バッファリングを必ず無効化してください。


運用

起動・停止・状態確認

kubectl get pods -n agentgateway -l app=agentgateway
kubectl rollout restart deployment/agentgateway -n agentgateway
kubectl rollout status deployment/agentgateway -n agentgateway
kubectl scale deployment/agentgateway --replicas=0 -n agentgateway

Admin API (localhost:9095):

kubectl port-forward pod/<pod-name> 9095:9095 -n agentgateway
curl http://localhost:9095/config_dump | jq .
curl http://localhost:9095/stats | grep dynamic_module
curl http://localhost:9095/ready

ヘルスチェック設定例:

livenessProbe:
  httpGet:
    path: /ready
    port: 9095
  initialDelaySeconds: 10
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /ready
    port: 9095
  initialDelaySeconds: 5
  periodSeconds: 5

ログ — Envoy アクセスログ / OpenTelemetry

JSON アクセスログ設定:

access_log:
  - name: envoy.access_loggers.file
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
      path: /dev/stdout
      log_format:
        json_format:
          timestamp: "%START_TIME%"
          method: "%REQ(:METHOD)%"
          response_code: "%RESPONSE_CODE%"
          duration_ms: "%DURATION%"
          x_request_id: "%REQ(X-REQUEST-ID)%"

Rust モジュール内からは eprintln! で stderr へ出力します。OpenTelemetry はデフォルト有効で、OTLP エンドポイントを設定するだけで分散トレースが得られます。

telemetry:
  tracing:
    enabled: true
    exporter:
      otlp:
        endpoint: "http://otel-collector:4317"
  metrics:
    enabled: true
    exporter:
      prometheus:
        port: 9090

Rust モジュールの更新 (ホットリロード不可)

Envoy 動的モジュールは設計上ホットリロード不可です。Kubernetes のローリングリスタートで入れ替えます。

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    spec:
      terminationGracePeriodSeconds: 60

スケール

kubectl scale deployment/agentgateway --replicas=5 -n agentgateway
kubectl autoscale deployment/agentgateway \
  --cpu-percent=70 --min=2 --max=10 -n agentgateway

kgateway Issue #908 で HPA 作成が ServiceAccount の権限不足で失敗する事象が報告されています。RBAC を事前確認してください。

メトリクス

メトリクス名 説明
agentgateway_requests_total リクエスト総数
agentgateway_request_duration_seconds リクエストレイテンシ分布
agentgateway_token_usage_total LLM トークン使用量 (per-team budget 監視)
envoy_http_downstream_rq_total Envoy downstream リクエスト数
envoy_dynamic_module_* 動的モジュール固有統計

監査ログ (tamper-evident)

security:
  auditLog:
    enabled: true
    format: json
    tamperEvident: true
    destination: stdout
    fields:
      - request_id
      - user_id
      - model
      - token_usage
      - prompt_hash
      - response_latency_ms

ベストプラクティス

ストリーミング時の buffering 無効化 (TTFT 悪化対策)

誤解: 「ゲートウェイを経由してもストリーミングは透過的に動作する」

反証エビデンス:

  • LiteLLM 経由でトークンストリーミングを有効にした実測で p95 レイテンシが 4 秒 → 22 秒 に悪化
  • NGINX の proxy_buffering はデフォルト ON (32 KB 単位でバッファ)
  • Traefik も Buffering middleware で同様の問題が生じる (Issues #10337, #23007)
  • LiteLLM では BaseHTTPMiddleware を軽量実装に置換して約 30% のオーバーヘッド削減実績あり

推奨 (NGINX):

location /v1/chat/completions {
    proxy_pass http://agentgateway;
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 300s;
    tcp_nodelay on;
}

Rust モジュール側でも、変換不要なチャンクは即時 FilterDataStatus::Continue を返します。

ESB 再発防止 — ゲートウェイに業務ロジックを入れない境界設計

誤解: 「ゲートウェイ層の Rust モジュールにプロンプト生成・モデル選択を実装すれば、アプリを変更せず横断的に制御できる」

反証エビデンス:

  • Thoughtworks Technology Radar の "ESBs in API Gateway's clothing" 警告が LLM 文脈で再来
  • Kong の経験則: 「新しいプラグインは必要時のみ追加し、複雑ロジックは専用サービスに offload すべし」
  • LLM Mesh の Routing Agent をアプリ層に置くことで最大 75% のコスト削減事例 (RouteLLM 等)

推奨 — ゲートウェイ vs アプリ層の境界:

種別 ゲートウェイ層 (Rust モジュール) アプリ層
header 操作・認可付与
PII マスキング・プロンプト編集
トークン計測・コスト記録
改ざん検証可能監査ログ
モデル別フォーマット差吸収 ✅ (低レベル変換のみ)
プロンプト生成・プロンプト構成
モデル選択ロジック
ドメインロジック・RAG
ストリーミングチャンクの業務加工 △ (TTFT 注意)

実践ルール: ゲートウェイへの業務ロジック追加は ADR (Architecture Decision Record) を必須にします。

Rust モジュールのパニックハンドリング (catch_unwind)

cdylib はサンドボックスなしで Envoy プロセス内に直接ロードされます。panic が伝播すると Envoy プロセス全体がクラッシュします。

use std::panic::{catch_unwind, AssertUnwindSafe};

fn on_request_headers(...) -> Result<FilterHeadersStatus> {
    let result = catch_unwind(AssertUnwindSafe(|| {
        self.do_request_headers(num_headers, end_of_stream, ops)
    }));
    match result {
        Ok(Ok(status)) => Ok(status),
        Ok(Err(e)) => {
            eprintln!("[rustformation] ERROR err={}", e);
            Ok(FilterHeadersStatus::Continue)
        }
        Err(_) => {
            eprintln!("[rustformation] PANIC — fail-closed");
            Ok(FilterHeadersStatus::StopIteration)
        }
    }
}

fail-closed を原則とし、panic 時はリクエストを停止します。

バージョン整合性の CI 化

ABI 互換は X.Y → X.(Y+1) のみ保証。CI で Envoy バージョンを固定し、変更時の再ビルドを必須ゲートにします。

jobs:
  version-matrix:
    strategy:
      matrix:
        envoy_version: ["v1.36.4"]
        rust_version: ["1.85"]
    steps:
      - name: Build .so
        run: |
          docker build \
            --build-arg ENVOY_VERSION=${{ matrix.envoy_version }} \
            --build-arg RUST_VERSION=${{ matrix.rust_version }} \
            -t agentgateway-ext:ci .

cdylib のサンドボックスなしを前提とした権限分離

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL
    add:
      - NET_BIND_SERVICE
volumeMounts:
  - name: rust-module
    mountPath: /usr/local/lib
    readOnly: true
  • Rust モジュールのソースレビューは内部開発チームに限定
  • cargo-audit を CI に組み込み、既知 CVE 含む依存をブロック

トラブルシューティング

症状 原因 対処
起動時に symbol not found / undefined symbol Envoy バージョンと .so の ABI が不一致 対象 Envoy バージョンで .so を再ビルド。CI で Envoy バージョン固定
Rust SDK コンパイルエラー Rust 1.85 未満 rustup update stable 後に rust-toolchain.toml でバージョン固定
protobuf Any 型のデシリアライズエラー google.protobuf.Any をラップせず生の型を渡している @type: type.googleapis.com/google.protobuf.StringValue でラップ
SSE ストリーミングで TTFT が悪化 (p95 4s → 22s) NGINX/Traefik のデフォルト buffering proxy_buffering off; tcp_nodelay on;。Rust モジュールは即時 Continue
LocalReply との組合せで response body 変換が動作しない Envoy LocalReply がバッファをバイパス (kgateway Issue #13434) LocalReply を使わず別フィルタに分離、または bypass_buffering: true
ConfigMap 1MB 制限で .so を格納できない バイナリサイズ超過 lto = true / codegen-units = 1 / strip = true で縮小。超える場合は initContainer でレジストリ pull
認証エラー (401/403) API Key Auth 未実装 (Issue #12378) JWT 認証ベースに移行。Issues 追跡
HPA が作成できない (forbidden) ServiceAccount に autoscaling 権限なし (Issue #908) apiGroups: [autoscaling] の verbs を ServiceAccount に付与
TrafficPolicy ratelimit が効かない v2.2.x で未実装 (Issue #11844) Envoy RLS で代替、実装版を待つ
Rust モジュール panic で Envoy がクラッシュ catch_unwind 未実装 全フックを catch_unwind(AssertUnwindSafe(...)) でラップ、fail-closed
AgentgatewayPolicy が複数バックエンドに適用されない ポリシーマージ不完全 (Issue #13049) 各バックエンドに個別ポリシー定義
MCP tool listing 失敗 実装不完全 (LiteLLM Issue #14069) agentgateway 独自実装に切り替え検討

まとめ

agentgateway / kgateway は、Envoy の動的モジュール機構と Rust の cdylib を組み合わせることで、AI Gateway の拡張を <0.1ms のオーバーヘッドで実現する新しいパターンを提示しました。ただしホットリロード不可・サンドボックスなし・SSE バッファリングなど運用上の落とし穴があり、業務ロジックはアプリ層に残す境界設計が成功の鍵になります。

この記事が少しでも参考になった、あるいは改善点などがあれば、ぜひリアクションやコメント、SNS でのシェアをいただけると励みになります!

参考リンク

公式ドキュメント・リポジトリ

参考実装

ストリーミング・パフォーマンス

ESB・設計境界

競合 AI Gateway OSS

既知 Issues