GDC エアギャップでの Envoy エージェント ルーターの参照実装を使用した AI Gateway

このドキュメントでは、Google Distributed Cloud(GDC)のエアギャップ環境に AI Gateway をデプロイする手順について説明します。このゲートウェイは、Envoy プロキシに基づく Kubernetes Gateway API 実装である Envoy Gateway と、Envoy Gateway を大規模言語モデル(LLM)トラフィック用の OpenAI 互換の統合エントリ ポイントにする拡張機能である Envoy Agent Router(以前の Envoy AI Gateway)から構築されています。コンテナ イメージと Helm チャートをローカルの Harbor レジストリにシードする、標準クラスタに両方のコントロール プレーンをインストールする、オプションのトークンベースのレート制限バックエンドを準備する、サンプル ワークロードでインストールを検証する手順について説明します。

モデル提供バックエンド(Ollama、vLLM)は、コンパニオン ガイドのセット GDC エアギャップでのオープン ウェイト モデルでデプロイされます。Envoy エージェント ルーターを使用した本文ベースのルーティングのユーザーガイドでは、モデル名でリクエストをルーティングする方法について説明しています。

アーキテクチャ

このソリューションは GDC 標準クラスタで実行されます。管理者ワークステーションは、イメージと Helm チャートをプロジェクトの Harbor レジストリにシードし、2 つのコントロール プレーン(Envoy プロキシ データプレーンを Gateway API リソース(GatewayClass、Gateway、HTTPRoute)からプログラムする Envoy Gateway コントローラと、AI トラフィック用の外部プロセッサ(ExtProc)でデータプレーンを拡張する Envoy Agent Router コントローラ(AIGatewayRoute、AIServiceBackend、InferencePool))をインストールします。アプリケーション クライアントは、OpenAI 互換のリクエストを Envoy プロキシに送信します。Envoy プロキシは、リクエストをモデル提供バックエンドまたは InferencePool にルーティングします。オプションの Redis インスタンスは、トークンベースのレート制限用の Envoy レート制限サービスのカウンタを保存します。

GDC エアギャップ上の Envoy エージェント ルーターを使用した AI Gateway のリファレンス アーキテクチャ。

Envoy Gateway

Envoy Gateway は、Envoy プロキシ上に構築されたオープンソース プロジェクトで、Kubernetes API ゲートウェイとしての Envoy プロキシの導入、使用、管理を簡素化します。これは、Ingress API の後継である Kubernetes Gateway API を実装して拡張します。GatewayClass リソースと Gateway リソースはエントリ ポイントを記述し、HTTPRoute などのルート リソースはトラフィックのマッチングと転送の方法を記述します。また、ロール指向の設計により、インフラストラクチャ チームとアプリケーション チームの責任が分離されます。Envoy Gateway は、独自の拡張機能 API(EnvoyProxy(データプレーン設定)、Backend(クラスタ外のエンドポイントまたは FQDN で参照されるエンドポイント)、ClientTrafficPolicy(バッファ上限などの接続設定)など)を追加します。

Envoy エージェント ルーター

Envoy Agent Router(以前の Envoy AI Gateway)は、Envoy Gateway を使用してアプリケーション クライアントから生成 AI サービスへのリクエスト トラフィックを処理するオープンソース プロジェクトです。モデル認識ルーティング、アップストリーム認証、トークンベースのレート制限とオブザーバビリティを使用して LLM トラフィックをルーティングおよび管理するための統合レイヤを提供し、指標認識エンドポイント選択のために Gateway API 推論拡張機能(InferencePool、エンドポイント ピッカー)と統合します。コントローラは aigateway.envoyproxy.io/v1beta1 リソースを監視し、Envoy プロキシの横に外部プロセッサを挿入します。外部プロセッサはリクエスト本文(OpenAI チャット完了リクエストの model フィールドなど)を解析し、x-ai-eg-model などのルーティング ヘッダーを設定し、必要に応じて API スキーマ間で変換します。

始める前に

デプロイを続行する前に、環境がすべての必要な前提条件を満たし、必要なコマンドライン ユーティリティが適切に構成されていることを確認してください。ワークステーションにこれらのツールを設定することは、コンテナ レジストリの管理、クラスタとのやり取り、デプロイ プロセスの自動化に不可欠です。

  • GDC エアーギャップ 1.16.2-hf1 以降の環境は、Kubernetes v1.32.13-gke.400 以降を実行する標準クラスタで使用できます。
  • 十分なリソースを使用して作成された Standard クラスタ。ゲートウェイ コンポーネントは CPU でのみ実行されます。モデル提供バックエンドには独自アクセラレータ要件があります(GDC エアギャップ環境でのオープン ウェイト モデルのガイドをご覧ください)。
  • Harbor インスタンスが利用可能でアクセス可能である。
  • 必要な IAM が適用されています。
  • 環境とインターネットへの接続に必要なワークステーション

環境の構成

環境構成では、ID と権限、ワークステーション、GDC 環境とクラスタへのアクセスについて説明します。

Identity and Access Management

必要な IAM アカウント、ロール、権限が正しく構成されていることを確認します。

プロジェクトに対する GDC ユーザーロール(プロジェクト Namespace の RoleBinding、プロジェクト IAM 管理者によって付与):

  • Harbor インスタンス閲覧者(harbor-instance-viewer)
  • Harbor プロジェクト作成者(harbor-project-creator、Harbor プロジェクトがまだ存在しない場合のみ)
  • 標準クラスタ管理者(standard-cluster-admin、gdcloud clusters get-credentials に必要)

標準クラスタの GDC ユーザーロール: 前述のプロジェクト ロールでは、クラスタ内の権限は付与されません。また、プロジェクト IAM 管理者は、管理 API サーバーのプロジェクト Namespace で StandardClusterRoleBinding を使用して、ユーザーを StandardClusterRole cluster-admin にバインドする必要があります。バインディングは、数秒以内にプロジェクトの標準クラスタに伝播されます(status.clusters[].conditions は Propagated=True を示します)。このガイドでは、カスタム リソース定義、ClusterRole、GatewayClass をインストールするため、クラスタ全体の権限が必要です。

cat <<EOF | kubectl --kubeconfig MANAGEMENT_API_SERVER apply -f -
apiVersion: iam.gdc.goog/v1
kind: StandardClusterRoleBinding
metadata:
  name: user-USER-cluster-admin
  namespace: PROJECT
spec:
  roleRef:
    apiGroup: iam.gdc.goog
    kind: StandardClusterRole
    name: cluster-admin
  subjects:
    - apiGroup: rbac.authorization.k8s.io
      kind: User
      name: USER
EOF

次のように置き換えます。

  • MANAGEMENT_API_SERVER: 管理 API サーバーの kubeconfig ファイルのパス。
  • USER: ユーザー。
  • PROJECT: プロジェクト。

Harbor crane(crane)ロボット アカウントの権限:

  • リポジトリを一覧表示する
  • リポジトリを pull する
  • リポジトリを push する
  • アーティファクトの読み取り
  • アーティファクトを一覧表示する
  • タグを作成
  • リストタグ

Harbor Kubernetes イメージ pull(kubernetes-image-puller)ロボット アカウントの権限:

  • リポジトリを一覧表示する
  • リポジトリを pull する
  • アーティファクトの読み取り
  • アーティファクトを一覧表示する
  • リストタグ

ワークステーション

このガイドでは、環境とインターネットに接続できるワークステーションが必要です。

要件

ワークステーションに次のツールをインストールする必要があります。

  • crane: レジストリ間でコンテナ イメージと OCI アーティファクトを管理してコピーします(ドキュメント)。
  • gdcloud: GDC リソースを管理するためのコマンドライン インターフェース(CLI)(ドキュメント)。
  • kubectl: Kubernetes クラスタとの通信と管理に使用されるコマンドライン インターフェース(CLI)。
  • helm: Kubernetes 用パッケージ マネージャー(バージョン 3.8 以降、OCI レジストリのサポートあり)(ドキュメント)。
  • curl: URL を使用してデータを転送するためのコマンドライン ツール。
  • jq: 軽量で柔軟なコマンドライン JSON プロセッサ。
  • yq: ポータブル コマンドライン YAML プロセッサ。

このガイドのすべてのコマンドは、手順に別の指示がない限り、ワークステーションから実行します。

ワークステーションの構成

ワークステーションの構成には、環境に関する次の情報が必要です。

  • GDC_STANDARD_CLUSTER_NAME: GDC Standard クラスタの名前。
  • GDC_DOMAIN_SUFFIX: GDC 環境のドメイン サフィックス(例: gdc.example.com)。
  • GDC_ORG: GDC 組織の名前。
  • GDC_PROJECT: GDC プロジェクトの名前。
  • GDC_ZONE: GDC デプロイ ゾーンの名前。
  • GDC_HARBOR_INSTANCE_NAME: プロジェクト内の Harbor インスタンスの名前。

  • GDCS_HARBOR_PROJECT_NAME: イメージに使用する Harbor プロジェクトの名前(デフォルト: solutions)

  • GDCS_HARBOR_CRANE_ROBOT_NAME: Harbor crane ロボット アカウントの名前。

  • GDCS_HARBOR_CRANE_ROBOT_TOKEN: Harbor crane ロボット アカウントの認証トークン。

  • GDCS_HARBOR_K8S_ROBOT_NAME: Harbor Kubernetes イメージ pull ロボット アカウントの名前。

  • GDCS_HARBOR_K8S_ROBOT_TOKEN: Harbor Kubernetes イメージ プル ロボット アカウントの認証トークン。

必要なすべての変数の値を収集したら、環境変数ファイルの生成に進みます。作成後、いつでも手動でファイルを編集できます。

  1. ルート ソリューション ディレクトリとシークレット フォルダを作成します。

    mkdir -p ${HOME}/gdcag-solutions/env.d
    mkdir -p ${HOME}/gdcag-solutions/secrets
    
    touch ${HOME}/gdcag-solutions/secrets/harbor_crane_robot_token
    touch ${HOME}/gdcag-solutions/secrets/harbor_k8s_robot_token
    
    chmod u=rwx,go= ${HOME}/gdcag-solutions/secrets
    chmod -R u=rw,go= ${HOME}/gdcag-solutions/secrets/*
    
  2. プラットフォーム環境構成ファイルを作成します。

    cat << 'EOF' > ${HOME}/gdcag-solutions/env.d/platform.sh && echo "Successfully created." || echo "Failed to create!"
    # Infrastructure (Platform Native)
    export GDC_STANDARD_CLUSTER_NAME="STANDARD_CLUSTER_NAME"
    export GDC_DOMAIN_SUFFIX="DOMAIN_SUFFIX"
    export GDC_ORG="ORG"
    export GDC_PROJECT="PROJECT"
    export GDC_ZONE="ZONE"
    export GDC_HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME"
    
    # Derived platform values
    export GDC_ZONAL_HOSTNAME="${GDC_ORG}.${GDC_ZONE}.${GDC_DOMAIN_SUFFIX}"
    export GDC_ZONAL_CONSOLE_URL="https://console.${GDC_ZONAL_HOSTNAME}"
    export GDC_HARBOR_HOST="${GDC_HARBOR_INSTANCE_NAME}-${GDC_PROJECT}.${GDC_ORG}.${GDC_ZONE}.${GDC_DOMAIN_SUFFIX}"
    EOF
    

    次のように置き換えます。

    • STANDARD_CLUSTER_NAME: GDC Standard クラスタ名。
    • DOMAIN_SUFFIX: GDC ドメイン接尾辞。
    • ORG: GDC 組織。
    • PROJECT: GDC プロジェクト。
    • ZONE: GDC ゾーン。
    • HARBOR_INSTANCE_NAME: GDC Harbor インスタンス名。
  3. レジストリ環境構成ファイルを作成します。

    cat << 'EOF' > ${HOME}/gdcag-solutions/env.d/registry.sh && echo "Successfully created." || echo "Failed to create!"
    # GDC Solutions Registry & Secrets
    export GDCS_HARBOR_PROJECT_NAME="solutions"
    export GDCS_HARBOR_CRANE_ROBOT_NAME="HARBOR_CRANE_ROBOT_NAME"
    export GDCS_HARBOR_CRANE_ROBOT_TOKEN="$(cat ${GDCS_ROOT_HOME}/secrets/harbor_crane_robot_token)"
    export GDCS_HARBOR_K8S_ROBOT_NAME="HARBOR_K8S_ROBOT_NAME"
    export GDCS_HARBOR_K8S_ROBOT_TOKEN="$(cat ${GDCS_ROOT_HOME}/secrets/harbor_k8s_robot_token)"
    export GDCS_HARBOR_K8S_PULL_SECRET="gdcs-image-pull-secret"
    
    # Derived registry values
    export GDCS_HARBOR_PROJECT_URI="${GDC_HARBOR_HOST}/${GDCS_HARBOR_PROJECT_NAME}"
    export GDCS_HARBOR_CHART_OCI_URI="oci://${GDCS_HARBOR_PROJECT_URI}"
    EOF
    

    次のように置き換えます。

    • HARBOR_CRANE_ROBOT_NAME: GDC Harbor ロボット アカウント名。
    • HARBOR_K8S_ROBOT_NAME: GDC Harbor ロボット アカウント名。
  4. トークンをシークレット ファイルに追加します。

    set +o history
    
    echo "CRANE_ROBOT_TOKEN" > ${HOME}/gdcag-solutions/secrets/harbor_crane_robot_token
    echo "KUBERNETES_ROBOT_TOKEN" > ${HOME}/gdcag-solutions/secrets/harbor_k8s_robot_token
    
    set -o history
    

    次のように置き換えます。

    • CRANE_ROBOT_TOKEN: クレーンロボットのトークン。
    • KUBERNETES_ROBOT_TOKEN: Kubernetes ロボット トークン。
  5. ルート環境ローダー ファイルを作成します。

    cat << 'EOF' > ${HOME}/gdcag-solutions/env.sh && echo "Successfully created." || echo "Failed to create!"
    export GDCS_ROOT_HOME="${HOME}/gdcag-solutions"
    echo "GDCS_ROOT_HOME=${GDCS_ROOT_HOME}"
    
    # Sourced in dependency order
    source "${GDCS_ROOT_HOME}/env.d/platform.sh"
    source "${GDCS_ROOT_HOME}/env.d/registry.sh"
    EOF
    

ソリューション変数を構成する

  1. ソリューション実装ディレクトリを作成します。

    mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d
    
  2. ソリューション環境構成ファイルを作成します。

    cat << 'EOF' > ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d/envoy.sh && echo "Successfully created." || echo "Failed to create!"
    # Envoy Gateway
    export GDCS_ENVOY_GATEWAY_NAMESPACE="envoy-gateway-system"
    export GDCS_ENVOY_GATEWAY_VERSION="v1.8.5"
    export GDCS_ENVOY_PROXY_IMAGE_TAG="distroless-v1.38.4"
    export GDCS_ENVOY_RATELIMIT_IMAGE_TAG="8fe6ea42"
    export GDCS_GATEWAY_API_ECHO_IMAGE_TAG="v1.5.1"
    
    # Envoy Agent Router (formerly Envoy AI Gateway; the images and charts keep the ai-gateway names)
    export GDCS_ENVOY_AGENT_ROUTER_NAMESPACE="envoy-ai-gateway-system"
    export GDCS_ENVOY_AGENT_ROUTER_VERSION="v1.1.0"
    
    # Gateway API Inference Extension (InferencePool, Endpoint Picker)
    export GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION="v1.5.0"
    
    # Redis (token-based rate limiting backend)
    export GDCS_REDIS_IMAGE_TAG="8.10.2-alpine3.23"
    export GDCS_REDIS_NAMESPACE="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
    # Gateway class shared by the user guides
    export GDCS_GATEWAY_CLASS_NAME="envoy-ai-gateway"
    
    # Docker configuration directories for crane and Kubernetes
    export GDCS_HARBOR_CRANE_DOCKER_CONFIG="${GDCS_IMPLEMENTATION_HOME}/docker/crane"
    export GDCS_HARBOR_K8S_DOCKER_CONFIG="${GDCS_IMPLEMENTATION_HOME}/docker/k8s"
    EOF
    
  3. 実装環境ローダー ファイルを作成します。

    cat << 'EOF' > ${HOME}/gdcag-solutions/ai-gateway/envoy/env.sh && echo "Successfully created." || echo "Failed to create!"
    source "${HOME}/gdcag-solutions/env.sh"
    
    export GDCS_IMPLEMENTATION_HOME="${HOME}/gdcag-solutions/ai-gateway/envoy"
    echo "GDCS_IMPLEMENTATION_HOME=${GDCS_IMPLEMENTATION_HOME}"
    
    # Sourced in dependency order
    source "${GDCS_IMPLEMENTATION_HOME}/env.d/envoy.sh"
    EOF
    
  4. 任意のエディタで環境ファイルを編集して確認します。

    ${EDITOR:-vi} ${HOME}/gdcag-solutions/env.d/platform.sh
    ${EDITOR:-vi} ${HOME}/gdcag-solutions/env.d/registry.sh
    ${EDITOR:-vi} ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d/envoy.sh
    
  5. 環境ファイルをソースにします。

    source ${HOME}/gdcag-solutions/ai-gateway/envoy/env.sh
    

    出力は次のようになります。

    GDCS_ROOT_HOME=HOME_DIRECTORY_PATH/gdcag-solutions
    GDCS_IMPLEMENTATION_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/ai-gateway/envoy
    

GDC

このガイドでは、ワークステーションが GDC 環境と Harbor インスタンスの TLS 証明書を信頼するように構成されていることを前提としています。

  1. gdcloud を構成します。

    gdcloud config set core/account "default-user"
    gdcloud config set core/organization_console_url "${GDC_ZONAL_CONSOLE_URL}"
    gdcloud config set core/project "${GDC_PROJECT}"
    gdcloud config set core/zone "${GDC_ZONE}"
    
  2. GDC 環境に対して認証します。

    gdcloud auth login
    

クラスタ

  1. クラスタの認証情報を取得します。

    gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \
    --project="${GDC_PROJECT}" \
    --standard \
    --zone="${GDC_ZONE}"
    
  2. クラスタへの接続を確認します。

    kubectl get nodes -L node.cluster.private.gdc.goog/machine-class
    
  3. すべてのノードが、このガイドの始める前にのセクションで求められている Kubernetes バージョンを実行していることを確認します。

    kubectl get nodes -o custom-columns='NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion'
    

アーティファクトの移行の準備

  1. crane の Docker 構成ファイルを作成します。ロボット アカウントは、ユーザー アカウントで Managed Harbor Service(MHS)認証情報ヘルパー(docker-credential-mhs)を使用するときに、認証トークンのタイムアウトを回避するために、大きなイメージレイヤを push するために使用されます。

    set +o history
    
    export DOCKER_CONFIG="${GDCS_HARBOR_CRANE_DOCKER_CONFIG}"
    
    crane auth login "${GDC_HARBOR_HOST}" \
    --password="${GDCS_HARBOR_CRANE_ROBOT_TOKEN}" \
    --username="${GDCS_HARBOR_CRANE_ROBOT_NAME}"
    
    set -o history
    
  2. Kubernetes 用の Docker 構成ファイルを作成します。

    set +o history
    
    export DOCKER_CONFIG="${GDCS_HARBOR_K8S_DOCKER_CONFIG}"
    
    crane auth login "${GDC_HARBOR_HOST}" \
    --password="${GDCS_HARBOR_K8S_ROBOT_TOKEN}" \
    --username="${GDCS_HARBOR_K8S_ROBOT_NAME}"
    
    set -o history
    
  3. Kubernetes イメージ pull ロボット アカウントを使用して、helm で Harbor OCI レジストリにログインします。helm は独自のレジストリ認証情報を保持しており、Harbor からチャートを取得するためにそれらの認証情報を必要とします。

    set +o history
    helm registry login "${GDC_HARBOR_HOST}" \
    --password="${GDCS_HARBOR_K8S_ROBOT_TOKEN}" \
    --username="${GDCS_HARBOR_K8S_ROBOT_NAME}"
    set -o history
    

    出力は次のようになります。

    Login Succeeded
    
  4. seed_registry.sh スクリプトを作成します。

    cat << 'EOF' > ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh && echo "Successfully created." || echo "Failed to create!"
    #!/bin/bash
    
    # seed_registry.sh: Modular artifact migration for GDC Solutions
    
    # Requires the env.sh file to be sourced first.
    SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    set -o nounset
    source "${SCRIPT_DIR}/env.sh"
    
    # Set the Docker config
    export DOCKER_CONFIG="${GDCS_HARBOR_CRANE_DOCKER_CONFIG}"
    eval "${SERIALIZED_IMAGES}"
    
    # Ensure GDCS_REGISTRY_IMAGES is set
    if [[ ${#GDCS_REGISTRY_IMAGES[@]} -eq 0 ]]; then
      echo "GDCS_REGISTRY_IMAGES must be set, exiting..."
      exit 1
    fi
    
    # Migrate the images
    for source_image in "${GDCS_REGISTRY_IMAGES[@]}"; do
      # Strip the registry host only when the first path segment is a host (contains a dot or a port)
      first_segment="${source_image%%/*}"
      if [[ "${first_segment}" == *.* || "${first_segment}" == *:* ]]; then
        image_path="${source_image#*/}"
      else
        image_path="${source_image}"
      fi
      destination_image="${GDCS_HARBOR_PROJECT_URI}/${image_path}"
      # Ensure the folder structure is created
      crane append \
        --new_layer=<(tar czf - -T /dev/null) \
        --new_tag="${destination_image%:*}:create" \
        --oci-empty-base 2> /dev/null || true
      # Copy the linux/amd64 platform only to avoid transferring multi-arch layers over air-gapped links
      crane copy --platform linux/amd64 "${source_image}" "${destination_image}" 2> /dev/null
    done
    echo "Migration complete: Images are available at ${GDCS_HARBOR_PROJECT_URI}"
    EOF
    chmod u+x "${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh"
    
  5. seed_charts.sh スクリプトを作成します。OCI アーティファクトとして公開された Helm チャートも、プラットフォームの選択やコンテナ イメージ リポジトリに使用される create タグなしで crane を使用してコピーされます。

    cat << 'EOF' > ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh && echo "Successfully created." || echo "Failed to create!"
    #!/bin/bash
    
    # seed_charts.sh: OCI Helm chart migration for GDC Solutions
    
    # Requires the env.sh file to be sourced first.
    SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    set -o nounset
    source "${SCRIPT_DIR}/env.sh"
    
    # Set the Docker config
    export DOCKER_CONFIG="${GDCS_HARBOR_CRANE_DOCKER_CONFIG}"
    eval "${SERIALIZED_CHARTS}"
    
    # Ensure GDCS_REGISTRY_CHARTS is set
    if [[ ${#GDCS_REGISTRY_CHARTS[@]} -eq 0 ]]; then
      echo "GDCS_REGISTRY_CHARTS must be set, exiting..."
      exit 1
    fi
    
    # Migrate the charts (source format: REGISTRY_HOST/REPOSITORY:CHART_VERSION)
    for source_chart in "${GDCS_REGISTRY_CHARTS[@]}"; do
      chart_path="${source_chart#*/}"
      destination_chart="${GDCS_HARBOR_PROJECT_URI}/${chart_path}"
      crane copy "${source_chart}" "${destination_chart}" || { echo "Failed to copy ${source_chart} to ${destination_chart}"; exit 1; }
    done
    echo "Migration complete: Charts are available at ${GDCS_HARBOR_CHART_OCI_URI}"
    EOF
    chmod u+x "${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh"
    

    次のように置き換えます。

    • REGISTRY_HOST: レジストリ ホスト。
    • REPOSITORY: リポジトリ。
    • CHART_VERSION: チャートのバージョン。
  6. ソリューションに必要なコンテナ イメージのリストを定義します。

    declare -a GDCS_REGISTRY_IMAGES=(
      "docker.io/envoyproxy/gateway:${GDCS_ENVOY_GATEWAY_VERSION}"
      "docker.io/envoyproxy/envoy:${GDCS_ENVOY_PROXY_IMAGE_TAG}"
      "docker.io/envoyproxy/ratelimit:${GDCS_ENVOY_RATELIMIT_IMAGE_TAG}"
      "docker.io/envoyproxy/ai-gateway-controller:${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
      "docker.io/envoyproxy/ai-gateway-extproc:${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
      "docker.io/envoyproxy/ai-gateway-testupstream:${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
      "docker.io/library/redis:${GDCS_REDIS_IMAGE_TAG}"
      "registry.k8s.io/gateway-api/echo-basic:${GDCS_GATEWAY_API_ECHO_IMAGE_TAG}"
    )
    export SERIALIZED_IMAGES=$(declare -p GDCS_REGISTRY_IMAGES)
    
  7. 必要なコンテナ イメージをアーティファクト レジストリにシードします。

    ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
    
  1. ソリューションに必要な Helm チャートのリストを定義します。

    declare -a GDCS_REGISTRY_CHARTS=(
      "docker.io/envoyproxy/gateway-crds-helm:${GDCS_ENVOY_GATEWAY_VERSION}"
      "docker.io/envoyproxy/gateway-helm:${GDCS_ENVOY_GATEWAY_VERSION}"
      "docker.io/envoyproxy/ai-gateway-crds-helm:${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
      "docker.io/envoyproxy/ai-gateway-helm:${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
    )
    export SERIALIZED_CHARTS=$(declare -p GDCS_REGISTRY_CHARTS)
    
  2. 必要な Helm チャートをアーティファクト レジストリにシードします。

    ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh
    
  3. Harbor からチャートを読み取れることを確認します。

    helm show chart "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/gateway-helm" --version "${GDCS_ENVOY_GATEWAY_VERSION}" | grep -E '^(name|version):'
    helm show chart "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/ai-gateway-helm" --version "${GDCS_ENVOY_AGENT_ROUTER_VERSION}" | grep -E '^(name|version):'
    

    出力は次のようになります。

    name: gateway-helm
    version: v1.8.5
    name: ai-gateway-helm
    version: v1.1.0
    
  4. Gateway API Inference Extension マニフェストをダウンロードします。これらは、チャートではなくリリース アセットとして公開されます。

    mkdir -p "${GDCS_IMPLEMENTATION_HOME}/manifests"
    
    curl --fail --location --show-error --silent \
    --output "${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml" \
    "https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}/manifests.yaml"
    
    grep --count '^kind: CustomResourceDefinition' "${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml"
    

    出力は次のようになります。

    4
    

Envoy Gateway

Envoy Gateway は最初にインストールされ、アップストリーム クイックスタートで単独で検証されます。Envoy Agent Router の統合については、次のセクションで説明します。

名前空間

  1. Envoy Gateway の Namespace を作成します。この Namespace には、すべての Gateway の Envoy プロキシ Deployment も作成されます。

    kubectl create namespace "${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  2. imagePullSecret を追加します。

    kubectl create secret docker-registry "${GDCS_HARBOR_K8S_PULL_SECRET}" \
    --dry-run=client \
    --from-file=.dockerconfigjson=${GDCS_HARBOR_K8S_DOCKER_CONFIG}/config.json \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --output=yaml | kubectl apply -f -
    

カスタム リソース定義

  1. シードされたチャートから Gateway API(標準チャネル)と Envoy Gateway カスタム リソース定義(CRD)をインストールします。

    helm template eg-crds "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/gateway-crds-helm" \
    --set crds.gatewayAPI.channel=standard \
    --set crds.gatewayAPI.enabled=true \
    --set crds.envoyGateway.enabled=true \
    --version "${GDCS_ENVOY_GATEWAY_VERSION}" | kubectl apply --server-side --filename=-
    
  2. CRD が登録されていることを確認します。

    kubectl get crd | grep -E 'gateway.networking.k8s.io|gateway.envoyproxy.io'
    

コントローラ

  1. Envoy Gateway の Helm 値ファイルを作成します。イメージは、イメージ pull シークレットを使用して Harbor から pull されます。これは、CRD が個別にインストールされたためです。crds.enabled=false

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-values.yaml" && echo "Successfully created." || echo "Failed to create!"
    config:
      envoyGateway:
        extensionApis:
          enableBackend: true
          enableEnvoyPatchPolicy: true
        gateway:
          controllerName: gateway.envoyproxy.io/gatewayclass-controller
        logging:
          level:
            default: info
        provider:
          type: Kubernetes
    crds:
      enabled: false
    global:
      imagePullSecrets:
        - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
      imageRegistry: ${GDCS_HARBOR_PROJECT_URI}
      images:
        envoyProxy:
          image: ${GDCS_HARBOR_PROJECT_URI}/envoyproxy/envoy:${GDCS_ENVOY_PROXY_IMAGE_TAG}
          pullSecrets:
            - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    EOF
    
  2. Envoy Gateway をインストールします。

    helm upgrade --install eg "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/gateway-helm" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --values="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-values.yaml" \
    --version="${GDCS_ENVOY_GATEWAY_VERSION}"
    
  3. Envoy Gateway コントローラが使用可能になるまで待ちます。

    watch --color --interval 5 --no-title \
    "kubectl get deployment/envoy-gateway \
    --namespace=${GDCS_ENVOY_GATEWAY_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1     1            1'"
    
  4. コントローラのイメージとその証明書生成ジョブが Harbor から取得されていることを確認します。

    kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
    

Envoy プロキシと Gateway クラス

  1. EnvoyProxy データプレーン テンプレートと GatewayClass のマニフェストを作成します。EnvoyProxy は、プロキシ イメージ、イメージ プル シークレット、プロキシ Pod のリソース リクエストを設定します。GatewayClass はユーザーガイドで共有されます。

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: EnvoyProxy
    metadata:
      name: ${GDCS_GATEWAY_CLASS_NAME}
      namespace: ${GDCS_ENVOY_GATEWAY_NAMESPACE}
    spec:
      provider:
        type: Kubernetes
        kubernetes:
          envoyDeployment:
            container:
              image: ${GDCS_HARBOR_PROJECT_URI}/envoyproxy/envoy:${GDCS_ENVOY_PROXY_IMAGE_TAG}
              resources:
                limits:
                  memory: 2Gi
                requests:
                  cpu: 250m
                  memory: 512Mi
            pod:
              imagePullSecrets:
                - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: GatewayClass
    metadata:
      name: ${GDCS_GATEWAY_CLASS_NAME}
    spec:
      controllerName: gateway.envoyproxy.io/gatewayclass-controller
      parametersRef:
        group: gateway.envoyproxy.io
        kind: EnvoyProxy
        name: ${GDCS_GATEWAY_CLASS_NAME}
        namespace: ${GDCS_ENVOY_GATEWAY_NAMESPACE}
    EOF
    
  2. EnvoyProxy と GatewayClass のマニフェストを適用します。

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"
    
  3. GatewayClass が Accepted であることを確認します。

    kubectl get gatewayclass "${GDCS_GATEWAY_CLASS_NAME}"
    

    出力は次のようになります。

    NAME               CONTROLLER                                      ACCEPTED   AGE
    envoy-ai-gateway   gateway.envoyproxy.io/gatewayclass-controller   True       5s
    

検証

検証では、Envoy Gateway クイックスタート(HTTPRoute の背後にあるエコー バックエンド)を Envoy Gateway Namespace にデプロイし、その後削除します。

  1. クイックスタート ワークロードのマニフェストを作成します。

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: eg-quickstart
    spec:
      gatewayClassName: ${GDCS_GATEWAY_CLASS_NAME}
      listeners:
        - name: http
          protocol: HTTP
          port: 80
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: eg-quickstart-backend
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: eg-quickstart-backend
      labels:
        app: eg-quickstart-backend
    spec:
      ports:
        - name: http
          port: 3000
          targetPort: 3000
      selector:
        app: eg-quickstart-backend
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: eg-quickstart-backend
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: eg-quickstart-backend
      template:
        metadata:
          labels:
            app: eg-quickstart-backend
        spec:
          serviceAccountName: eg-quickstart-backend
          containers:
            - image: ${GDCS_HARBOR_PROJECT_URI}/gateway-api/echo-basic:${GDCS_GATEWAY_API_ECHO_IMAGE_TAG}
              imagePullPolicy: IfNotPresent
              name: backend
              ports:
                - containerPort: 3000
              env:
                - name: POD_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
          imagePullSecrets:
            - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: eg-quickstart-backend
    spec:
      parentRefs:
        - name: eg-quickstart
      hostnames:
        - "www.example.com"
      rules:
        - backendRefs:
            - group: ""
              kind: Service
              name: eg-quickstart-backend
              port: 3000
              weight: 1
          matches:
            - path:
                type: PathPrefix
                value: /
    EOF
    
  2. クイックスタート ワークロードのマニフェストを適用します。

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  3. Gateway が Programmed になるまで待ちます。

    watch --color --interval 5 --no-title \
    "kubectl get gateway/eg-quickstart \
    --namespace=${GDCS_ENVOY_GATEWAY_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e 'True'"
    
  4. バックエンド Deployment が使用可能になるまで待ちます。

    watch --color --interval 5 --no-title \
    "kubectl get deployment/eg-quickstart-backend \
    --namespace=${GDCS_ENVOY_GATEWAY_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1     1            1'"
    
  5. ポート転送を使用して、Gateway 経由でテスト リクエストを送信します。Gateway の Envoy Service は、所有ゲートウェイのラベルによって検出されます。

    export ENVOY_SERVICE=$(kubectl get service --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" --selector="gateway.envoyproxy.io/owning-gateway-namespace=${GDCS_ENVOY_GATEWAY_NAMESPACE},gateway.envoyproxy.io/owning-gateway-name=eg-quickstart" --output=jsonpath='{.items[0].metadata.name}')
    echo "ENVOY_SERVICE=${ENVOY_SERVICE}"
    
    kubectl port-forward "service/${ENVOY_SERVICE}" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" 8888:80 &
    PF_PID=$!
    
    sleep 2
    
    curl --header "Host: www.example.com" \
    --no-progress-meter \
    --show-error \
    http://127.0.0.1:8888/get | jq
    
    kill -9 ${PF_PID}
    

    出力は次のようになります。

    {
      "path": "/get",
      "host": "www.example.com",
      "method": "GET",
      ...
      "namespace": "envoy-gateway-system",
      "pod": "eg-quickstart-backend-...",
      ...
    }
    
  6. クイックスタート ワークロードを削除します。

    kubectl delete \
    --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    

Envoy エージェント ルーター

Envoy Agent Router は独自の Namespace にインストールされます。その後、Envoy Gateway が拡張サーバーとして呼び出すように再構成されます。

名前空間

  1. Envoy エージェント ルーター コントローラの Namespace を作成します。

    kubectl create namespace "${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  2. imagePullSecret を追加します。

    kubectl create secret docker-registry "${GDCS_HARBOR_K8S_PULL_SECRET}" \
    --dry-run=client \
    --from-file=.dockerconfigjson=${GDCS_HARBOR_K8S_DOCKER_CONFIG}/config.json \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}" \
    --output=yaml | kubectl apply -f -
    

カスタム リソース定義

  1. シードされたチャートから Envoy エージェント ルーター CRD をインストールします。

    helm template aieg-crds "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/ai-gateway-crds-helm" \
    --version "${GDCS_ENVOY_AGENT_ROUTER_VERSION}" | kubectl apply --server-side --filename=-
    
  2. ダウンロードしたマニフェストから Gateway API 推論拡張機能 CRD(InferencePool、InferenceObjective)をインストールします。

    kubectl apply --server-side \
    --filename="${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml"
    
  3. CRD が登録されていることを確認します。

    kubectl get crd | grep -E 'aigateway.envoyproxy.io|inference.networking'
    

    出力は次のようになります。

    aigatewayroutes.aigateway.envoyproxy.io                 ...
    aiservicebackends.aigateway.envoyproxy.io               ...
    backendsecuritypolicies.aigateway.envoyproxy.io         ...
    gatewayconfigs.aigateway.envoyproxy.io                  ...
    inferencemodelrewrites.inference.networking.x-k8s.io    ...
    inferenceobjectives.inference.networking.x-k8s.io       ...
    inferencepoolimports.inference.networking.x-k8s.io      ...
    inferencepools.inference.networking.k8s.io              ...
    mcproutes.aigateway.envoyproxy.io                       ...
    quotapolicies.aigateway.envoyproxy.io                   ...
    

Redis

トークンベースのレート制限は、Envoy レート制限サービスによって適用されます。このサービスは、カウンタを Redis に保存します。このガイドでは、永続性のない単一レプリカの Redis をデプロイします。次のセクションで rateLimit.backend.redis.url の値を変更すると、既存の Redis サービスを代わりに使用できます。

  1. Redis Deployment のマニフェストを作成します。

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/redis.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: v1
    kind: Service
    metadata:
      name: redis
      labels:
        app: redis
    spec:
      ports:
        - name: redis
          port: 6379
      selector:
        app: redis
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: redis
      template:
        metadata:
          labels:
            app: redis
        spec:
          containers:
            - image: ${GDCS_HARBOR_PROJECT_URI}/library/redis:${GDCS_REDIS_IMAGE_TAG}
              imagePullPolicy: IfNotPresent
              name: redis
              ports:
                - name: redis
                  containerPort: 6379
              resources:
                limits:
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 128Mi
          imagePullSecrets:
            - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
          restartPolicy: Always
    EOF
    
  2. Redis Deployment のマニフェストを適用します。

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \
    --namespace="${GDCS_REDIS_NAMESPACE}"
    
  3. Redis Deployment が使用可能になるまで待ちます。

    watch --color --interval 5 --no-title \
    "kubectl get deployment/redis \
    --namespace=${GDCS_REDIS_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1     1            1'"
    

コントローラ

  1. Envoy Agent Router の Helm 値ファイルを作成します。

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/envoy-agent-router-values.yaml" && echo "Successfully created." || echo "Failed to create!"
    controller:
      image:
        repository: ${GDCS_HARBOR_PROJECT_URI}/envoyproxy/ai-gateway-controller
      imagePullSecrets:
        - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    envoyGateway:
      namespace: ${GDCS_ENVOY_GATEWAY_NAMESPACE}
    extProc:
      image:
        repository: ${GDCS_HARBOR_PROJECT_URI}/envoyproxy/ai-gateway-extproc
      imagePullSecrets:
        - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    global:
      imagePullSecrets:
        - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    EOF
    
  2. Envoy エージェント ルーターをインストールします。

    helm upgrade --install aieg "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/ai-gateway-helm" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}" \
    --values="${GDCS_IMPLEMENTATION_HOME}/envoy-agent-router-values.yaml" \
    --version="${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
    
  3. Envoy Agent Router コントローラが使用可能になるまで待ちます。

    watch --color --interval 5 --no-title \
    "kubectl get deployment/ai-gateway-controller \
    --namespace=${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1     1            1'"
    

Envoy Gateway の統合

Envoy Gateway を再構成して、Envoy Agent Router コントローラを拡張サーバーとして呼び出し、InferencePool リソースをバックエンドとして受け入れ、Redis ベースのレート制限サービスを使用する必要があります。

  1. インテグレーションの Helm 値ファイルを作成します。

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-agent-router-values.yaml" && echo "Successfully created." || echo "Failed to create!"
    config:
      envoyGateway:
        extensionManager:
          backendResources:
            - group: inference.networking.k8s.io
              kind: InferencePool
              version: v1
          hooks:
            xdsTranslator:
              post:
                - Translation
                - Cluster
                - Route
              translation:
                cluster:
                  includeAll: true
                listener:
                  includeAll: true
                route:
                  includeAll: true
                secret:
                  includeAll: true
          service:
            fqdn:
              hostname: ai-gateway-controller.${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}.svc.cluster.local
              port: 1063
        rateLimit:
          backend:
            redis:
              url: redis.${GDCS_REDIS_NAMESPACE}.svc.cluster.local:6379
            type: Redis
    EOF
    
  2. 両方の値ファイルを使用して Envoy Gateway をアップグレードします。

    helm upgrade --install eg "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/gateway-helm" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --values="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-values.yaml" \
    --values="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-agent-router-values.yaml" \
    --version="${GDCS_ENVOY_GATEWAY_VERSION}"
    
  3. Envoy Gateway コントローラが InferencePool リソースを監視できるようにする ClusterRole のマニフェストを作成します。この権限はグラフによって付与されません。グラフで管理される ClusterRole のパッチとは異なり、個別の ClusterRoleBinding はグラフのアップグレード後も存続します。

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: envoy-gateway-inferencepool-reader
    rules:
      - apiGroups:
          - inference.networking.k8s.io
        resources:
          - inferencepools
        verbs:
          - get
          - list
          - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: envoy-gateway-inferencepool-reader
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: envoy-gateway-inferencepool-reader
    subjects:
      - kind: ServiceAccount
        name: envoy-gateway
        namespace: ${GDCS_ENVOY_GATEWAY_NAMESPACE}
    EOF
    
  4. ClusterRole のマニフェストを適用します。

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"
    
  5. 新しい構成と権限を読み込むように Envoy Gateway コントローラを再起動し、Available になるまで待ちます。

    kubectl rollout restart deployment/envoy-gateway \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
    kubectl rollout status deployment/envoy-gateway \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --timeout=5m
    
  6. レート制限サービスがデプロイされ、使用可能であることを確認します。

    watch --color --interval 5 --no-title \
    "kubectl get deployment/envoy-ratelimit \
    --namespace=${GDCS_ENVOY_GATEWAY_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1     1            1'"
    

検証

検証では、Envoy Agent Router の基本的な例(AIGatewayRoute の背後にある OpenAI 互換のモック アップストリーム)を Envoy Agent Router Namespace にデプロイし、その後削除します。

  1. 検証ワークロードのマニフェストを作成します。

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: aieg-basic
    spec:
      gatewayClassName: ${GDCS_GATEWAY_CLASS_NAME}
      listeners:
        - name: http
          protocol: HTTP
          port: 80
    ---
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: ClientTrafficPolicy
    metadata:
      name: aieg-basic-buffer-limit
    spec:
      targetRefs:
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: aieg-basic
      connection:
        bufferLimit: 50Mi
    ---
    apiVersion: aigateway.envoyproxy.io/v1beta1
    kind: AIGatewayRoute
    metadata:
      name: aieg-basic
    spec:
      parentRefs:
        - name: aieg-basic
          kind: Gateway
          group: gateway.networking.k8s.io
      rules:
        - matches:
            - headers:
                - type: Exact
                  name: x-ai-eg-model
                  value: some-cool-self-hosted-model
          backendRefs:
            - name: aieg-basic-testupstream
    ---
    apiVersion: aigateway.envoyproxy.io/v1beta1
    kind: AIServiceBackend
    metadata:
      name: aieg-basic-testupstream
    spec:
      schema:
        name: OpenAI
      backendRef:
        name: aieg-basic-testupstream
        kind: Backend
        group: gateway.envoyproxy.io
    ---
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: Backend
    metadata:
      name: aieg-basic-testupstream
    spec:
      endpoints:
        - fqdn:
            hostname: aieg-basic-testupstream.${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}.svc.cluster.local
            port: 80
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: aieg-basic-testupstream
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: aieg-basic-testupstream
      template:
        metadata:
          labels:
            app: aieg-basic-testupstream
        spec:
          containers:
            - name: testupstream
              image: ${GDCS_HARBOR_PROJECT_URI}/envoyproxy/ai-gateway-testupstream:${GDCS_ENVOY_AGENT_ROUTER_VERSION}
              imagePullPolicy: IfNotPresent
              ports:
                - containerPort: 8080
              env:
                - name: TESTUPSTREAM_ID
                  value: test
              readinessProbe:
                httpGet:
                  path: /health
                  port: 8080
                initialDelaySeconds: 5
                periodSeconds: 10
              livenessProbe:
                httpGet:
                  path: /health
                  port: 8080
                initialDelaySeconds: 10
                periodSeconds: 20
          imagePullSecrets:
            - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: aieg-basic-testupstream
    spec:
      selector:
        app: aieg-basic-testupstream
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
      type: ClusterIP
    EOF
    
  2. 検証ワークロードのマニフェストを適用します。

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  3. Gateway が Programmed になるまで待ちます。

    watch --color --interval 5 --no-title \
    "kubectl get gateway/aieg-basic \
    --namespace=${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e 'True'"
    
  4. モック アップストリーム Deployment が使用可能になるまで待ちます。

    watch --color --interval 5 --no-title \
    "kubectl get deployment/aieg-basic-testupstream \
    --namespace=${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1     1            1'"
    
  5. Envoy プロキシ Gateway の Pod が、Envoy エージェント ルーターによって挿入された外部プロセッサ サイドカーを実行していることを確認します。

    kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --selector="gateway.envoyproxy.io/owning-gateway-name=aieg-basic" \
    --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].name}{"\n"}{end}'
    

    出力は次のようになります。

    envoy-envoy-ai-gateway-system-aieg-basic-...   envoy shutdown-manager ai-gateway-extproc
    
  6. ポート転送を使用して、ゲートウェイ経由でチャット完了リクエストを送信します。外部プロセッサは、リクエスト本文の model フィールドを読み取り、モック アップストリームに転送します。

    export ENVOY_SERVICE=$(kubectl get service --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" --selector="gateway.envoyproxy.io/owning-gateway-namespace=${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE},gateway.envoyproxy.io/owning-gateway-name=aieg-basic" --output=jsonpath='{.items[0].metadata.name}')
    echo "ENVOY_SERVICE=${ENVOY_SERVICE}"
    
    kubectl port-forward "service/${ENVOY_SERVICE}" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" 8888:80 &
    PF_PID=$!
    
    sleep 2
    
    curl http://127.0.0.1:8888/v1/chat/completions \
    --data '{"model": "some-cool-self-hosted-model", "messages": [{"role": "user", "content": "Say this is a test."}]}' \
    --header "Content-Type: application/json" \
    --no-progress-meter \
    --show-error | jq
    
    kill -9 ${PF_PID}
    

    出力は次のようになります。

    {
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "..."
          },
          "finish_reason": "stop"
        }
      ],
      "usage": {
        ...
      }
    }
    
  7. 検証ワークロードを削除します。

    kubectl delete \
    --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    

運用

ゲートウェイ コントロール プレーンの 2 日目のタスク。

アップグレード

  • 新しいバージョンのイメージとチャートをシードし(env.sh のバージョン変数を更新し、seed_registry.sh と seed_charts.sh を再実行)、kubectl apply --server-side で新しい CRD チャートを適用してから、新しい --version で同じ helm upgrade --install コマンドを実行します。ターゲット リリースでサポートされている Envoy Gateway と Gateway API のバージョンについては、Envoy Agent Router の互換性マトリックスをご覧ください。Envoy Agent Router 1.1.0 は Envoy Gateway 1.8 に対してビルドされています。

アンインストール

  • まず、ユーザーガイドの Gateway、AIGatewayRoute、InferencePool リソースを削除し、次に helm uninstall aieg --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"、helm uninstall eg --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"、ClusterRole envoy-gateway-inferencepool-reader、GatewayClass、Redis Deployment、最後に CRD を削除します。

トラブルシューティング

症状 考えられる原因 アクション
helm show chart または helm upgrade が unauthorized または FetchReference で失敗する helm に Harbor の認証情報がない(crane Docker 構成を使用していない) Kubernetes イメージ pull ロボット アカウントを使用して helm registry login ステップを再度実行します。
Envoy Gateway または Envoy Agent Router の Pod が ImagePullBackOff のままになる イメージがシードされていないか、イメージ pull シークレットが Namespace にない kubectl describe pod を確認し、イメージパスを crane ls "${GDCS_HARBOR_PROJECT_URI}/envoyproxy/gateway" と比較して、シークレットが ${GDCS_ENVOY_GATEWAY_NAMESPACE} と ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} に存在することを確認します。
統合後も Gateway は Programmed=False のまま Envoy Gateway コントローラが拡張機能サーバーに到達できないか、アップグレード後に再起動されていない kubectl logs deployment/envoy-gateway --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"。service/ai-gateway-controller が ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} に存在し、ポート 1063 がリストされていることを確認し、ロールアウトの再起動を繰り返します。
InferencePool を参照する AIGatewayRoute が承認されない Envoy Gateway に inferencepools を読み取る権限がないか、InferencePool CRD がありません ClusterRoleBinding envoy-gateway-inferencepool-reader と inferencepools.inference.networking.k8s.io CRD を確認し、コントローラのログで forbidden を確認します。
チャット完了リクエストが 413 を返すか、大きなプロンプトで接続がリセットされる デフォルトの Envoy バッファの上限(32 KiB)が AI ペイロードに対して小さすぎる connection.bufferLimit(検証では 50Mi を使用)を含む ClientTrafficPolicy を Gateway に関連付けます。
レート制限サービス Pod は CrashLoopBackOff です 構成された URL で Redis にアクセスできない kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}"。統合値ファイルで rateLimit.backend.redis.url を修正して、再度アップグレードします。

その他の教材