在 GDC 實體隔離方案上,使用 Envoy 代理程式路由器參考實作項目,搭配 AI Gateway

本文件提供逐步操作說明,協助您在 Google Distributed Cloud (GDC) 實體隔離環境中部署 AI Gateway。這個閘道是以 Envoy Gateway (以 Envoy Proxy 為基礎的 Kubernetes Gateway API 實作) 和 Envoy Agent Router (舊稱 Envoy AI Gateway) 建構而成。Envoy Agent Router 是擴充功能,可將 Envoy Gateway 轉換為與 OpenAI 相容的統一進入點,用於大型語言模型 (LLM) 流量。包括將容器映像檔和 Helm 圖表植入本機 Harbor 登錄檔、在標準叢集上安裝兩個控制層、準備選用的權杖型頻率限制後端,以及使用範例工作負載驗證安裝。

模型提供後端 (Ollama、vLLM) 是透過隨附的指南「GDC 實體隔離方案中的開放權重模型」部署;使用 Envoy Agent Router 進行主體式轉送的使用手冊,則說明如何依模型名稱將要求轉送至這些後端。

架構

這項解決方案會在 GDC 標準叢集中執行。管理員工作站會將映像檔和 Helm 資訊套件植入專案的 Harbor 註冊資料庫,並安裝兩個控制層:Envoy Gateway 控制器,可透過 Gateway API 資源 (GatewayClass、Gateway、HTTPRoute) 程式設計 Envoy Proxy 資料層;以及 Envoy Agent Router 控制器,可透過 AI 流量的外部處理器 (ExtProc) 擴充該資料層 (AIGatewayRoute、AIServiceBackend、InferencePool)。應用程式用戶端會將與 OpenAI 相容的要求傳送至 Envoy Proxy,後者會將要求轉送至提供模型後端或 InferencePool。選用的 Redis 執行個體會儲存 Envoy 頻率限制服務的計數器,用於權杖型頻率限制。

GDC 實體隔離方案的 AI Gateway 與 Envoy 代理路由參考架構。

Envoy Gateway

Envoy Gateway 是以 Envoy Proxy 為基礎的開放原始碼專案,可簡化 Envoy Proxy 做為 Kubernetes API Gateway 的採用、使用和管理。它實作並擴充了 Kubernetes Gateway API (Ingress 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 Proxy 旁插入外部處理器。外部處理器會剖析要求主體 (例如 OpenAI 聊天完成要求的 model 欄位)、設定 x-ai-eg-model 等轉送標頭,並視需要轉換 API 架構。

事前準備

在繼續部署之前,請確認您的環境符合所有必要條件,且已正確設定必要的指令列公用程式。在工作站設定這些工具,對於管理 Container Registry、與叢集互動,以及自動化部署程序至關重要。

  • GDC 實體隔離方案 1.16.2-hf1 以上版本環境,可與執行 Kubernetes v1.32.13-gke.400 以上版本的標準叢集搭配使用。
  • 已建立資源充足的標準叢集。閘道元件僅在 CPU 上執行;提供模型後端有自己的加速晶片需求 (請參閱「GDC 實體隔離方案中的開放權重模型」指南)。
  • Harbor 執行個體可用且可存取。
  • 已套用必要的 IAM。
  • 工作站,且具備環境和網際網路的必要連線能力

環境設定

環境設定涵蓋身分和權限、工作站,以及 GDC 環境和叢集的存取權。

Identity and Access Management

請確認已正確設定必要的 IAM 帳戶、角色和權限。

專案的 GDC 使用者角色 (由 IAM 專案管理員授予,位於專案命名空間中的 RoleBinding):

  • 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) 機器人帳戶權限:

  • 列出存放區
  • 提取存放區
  • 推送存放區
  • 讀取構件
  • 列出構件
  • 建立標記
  • 清單標記

Harbor Kubernetes 映像檔提取 (kubernetes-image-puller) 機器人帳戶權限:

  • 列出存放區
  • 提取存放區
  • 讀取構件
  • 列出構件
  • 清單標記

工作站

除非步驟另有說明,否則請在工作站執行本指南中的所有指令,並確保工作站具備必要工具,且可連線至環境和網際網路。

需求條件

工作站必須安裝下列工具:

  • crane:在登錄檔之間管理及複製容器映像檔和 OCI 構件 (說明文件)。
  • gdcloud:用於管理 GDC 資源的指令列介面 (CLI) (說明文件)。
  • kubectl:用於與 Kubernetes 叢集通訊及管理叢集的指令列介面 (CLI)。
  • helm:Kubernetes 的套件管理工具,3.8 以上版本 (支援 OCI 登錄檔) (說明文件)。
  • curl:使用網址傳輸資料的指令列工具。
  • 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 映像檔提取機器人帳戶的名稱。

  • GDCS_HARBOR_K8S_ROBOT_TOKEN:Harbor Kubernetes 映像檔提取機器人帳戶的驗證權杖。

收集完所有必要變數的值後,請繼續產生環境變數檔案。建立後,您隨時可以手動編輯檔案。

  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
    

Artifact 遷移準備

  1. 為 crane 建立 Docker 設定檔。機器人帳戶用於推送大型映像檔層,避免在使用代管 Harbor 服務 (MHS) 憑證輔助程式 (docker-credential-mhs) 搭配使用者帳戶時,發生驗證權杖逾時的情況:

    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 映像檔提取機器人帳戶,以 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 推論擴充功能資訊清單。這些資料會以版本資產的形式發布,而非圖表:

    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 建立命名空間。每個 Gateway 的 Envoy Proxy 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 值檔案。映像檔會透過映像檔提取密鑰從 Harbor 提取;crds.enabled=false,因為 CRD 是分開安裝:

    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 Proxy 和閘道類別

  1. 為 EnvoyProxy 資料層範本和 GatewayClass 建立資訊清單。EnvoyProxy 會設定 Proxy 映像檔、映像檔提取密鑰,以及 Proxy 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 是否已接受:

    kubectl get gatewayclass "${GDCS_GATEWAY_CLASS_NAME}"
    

    輸出結果會與下列內容相似:

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

驗證

驗證作業會將 Envoy Gateway 快速入門導覽課程 (HTTPRoute 後方的 echo 後端) 部署至 Envoy Gateway 命名空間,然後移除。

  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 代理路由器

Envoy Agent Router 會安裝在自己的命名空間中,Envoy Gateway 則會重新設定,以呼叫 Envoy Agent Router 做為擴充功能伺服器。

命名空間

  1. 為 Envoy Agent Router 控制器建立命名空間:

    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. 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 代理路由器 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 代理程式路由器控制器變為「可用」狀態:

    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. 為 ClusterRole 建立資訊清單,讓 Envoy Gateway 控制器監控 InferencePool 資源。圖表不會授予這項權限;與圖表管理的 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 命名空間,然後移除。

  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 Proxy 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 Agent Router 相容性矩陣,瞭解目標版本支援的 Envoy Gateway 和 Gateway API 版本;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 映像檔提取機器人帳戶,再次執行 helm registry login 步驟。
Envoy Gateway 或 Envoy Agent Router Pod 位於 ImagePullBackOff 未植入映像檔,或命名空間中缺少映像檔提取密鑰 檢查 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 的 ClientTrafficPolicy (驗證作業會使用 50Mi) 附加至 Gateway。
頻率限制服務「Pod」為CrashLoopBackOff 無法透過設定的網址連上 Redis kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}";請修正整合值檔案中的 rateLimit.backend.redis.url,然後再次升級。

其他資料