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 Agent Router を使用した本文ベースのルーティングのユーザーガイドでは、モデル名でリクエストをルーティングする方法について説明しています。

アーキテクチャ

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

GDC エアギャップでの Envoy Agent Router を使用した AI Gateway のリファレンス アーキテクチャ。

Envoy Gateway

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

Envoy Agent Router

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

始める前に

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

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

環境の構成

環境構成には、ID と権限、ワークステーション、GDC 環境とクラスタへのアクセスが含まれます。

Identity and Access Management

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

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

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

標準クラスタに対する GDC ユーザーロール: 前述のプロジェクト ロールでは、クラスタ内の権限は付与されません。プロジェクト IAM 管理者は、管理 API サーバーのプロジェクト名前空間で 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 標準クラスタの名前。
  • 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 イメージ pull ロボット アカウントの認証トークン。

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

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

    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 標準クラスタ名。
    • 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
    

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

  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 チャートも crane でコピーされます。プラットフォームの選択はなく、コンテナ イメージ リポジトリに使用される create タグもありません。

    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. 必要なコンテナ イメージを Artifact Registry にシードします。

    ${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 チャートを Artifact Registry にシードします。

    ${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 を作成します。すべての Gateway の Envoy プロキシ Deployment も、この Namespace に作成されます。

    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 は、プロキシ イメージ、イメージ pull シークレット、プロキシ 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 がプログラムされるまで待ちます。

    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 の 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 Agent Router

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

名前空間

  1. Envoy Agent Router コントローラの 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 Agent Router 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 Inference Extension 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 Agent Router をインストールします。

    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 コントローラを再起動して、新しい構成と権限を取得し、使用可能になるまで待ちます。

    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 がプログラムされるまで待ちます。

    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. Gateway の Envoy プロキシ Pod が、Envoy Agent Router によって挿入された外部プロセッサ サイドカーを実行していることを確認します。

    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 シークレットがない 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 を修正して、再度アップグレードします。

その他の教材