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

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

模型服務後端 (Ollama、vLLM) 會隨附一組指南部署,請參閱 GDC 氣隙環境中的開放權重模型;Envoy 代理程式路由器使用者指南中的主體式路由說明如何依模型名稱將要求轉送至這些後端。

架構

這項解決方案會在 GDC 標準叢集中執行。管理員工作站會將映像檔和 Helm 圖表植入專案的 Harbor 登錄檔,並安裝兩個控制平面:Envoy Gateway 控制器 (可從 Gateway API 資源 (GatewayClass、Gateway、HTTPRoute) 程式化 Envoy 代理程式資料平面),以及 Envoy 代理程式路由器控制器 (可透過 AI 流量的外部處理器 (ExtProc) 擴充該資料平面 (AIGatewayRoute、AIServiceBackend、InferencePool))。應用程式用戶端會將與 OpenAI 相容的要求傳送至 Envoy 代理程式,後者會將要求路由至模型服務後端或 InferencePool。選用的 Redis 執行個體會儲存 Envoy 速率限制服務的計數器,用於以權杖為基礎的速率限制。

在 GDC 實體隔離方案上,使用 Envoy 代理路由器參考架構的 AI Gateway。

Envoy Gateway

Envoy Gateway 是以 Envoy Proxy 為基礎建構的開放原始碼專案,可簡化 Envoy Proxy 的採用、使用和管理作業,做為 Kubernetes API 閘道。這項功能實作並擴充了 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 Inference Extension (InferencePool、Endpoint Picker) 整合,根據指標選取端點。控制器會監控 aigateway.envoyproxy.io/v1beta1 資源,並在 Envoy 代理伺服器旁插入外部處理器;外部處理器會剖析要求主體 (例如 OpenAI 聊天完成要求中的 model 欄位)、設定 x-ai-eg-model 等路由標頭,並視需要轉換 API 結構定義。

事前準備

繼續部署前,請確認您的環境符合所有必要條件,且已正確設定必要的命令列公用程式。在工作站上設定這些工具,是管理容器登錄檔、與叢集互動,以及自動化部署程序的重要步驟。

  • GDC air-gapped 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 伺服器的專案命名空間中,將使用者繫結至 StandardClusterRole cluster-admin (使用 StandardClusterRoleBinding,繫結會在一秒內傳播至專案的標準叢集 (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. 建立根解決方案目錄和祕密資料夾:

    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
    
  3. 確認每個節點執行的 Kubernetes 版本符合本指南「開始前」一節的要求:

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

準備遷移構件

  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 代理程式 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 控制器進入「Available」狀態:

    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 和 Gateway 類別

  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 變成「Available」:

    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 代理程式路由器會安裝在自己的命名空間中,然後重新設定 Envoy Gateway,將其做為擴充伺服器呼叫。

命名空間

  1. 為 Envoy 代理程式路由器控制器建立命名空間:

    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 變成「Available」:

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

    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 代理程式路由器控制器變成「Available」:

    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 控制器,讓新的設定和權限生效,並等待控制器顯示「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. 確認已部署速率限制服務,且該服務處於「Available」(可用) 狀態:

    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 代理程式路由器基本範例 (AIGatewayRoute 後方與 OpenAI 相容的模擬上游) 部署到 Envoy 代理程式路由器命名空間,然後移除該範例。

  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 變成「Available」(可用):

    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 Proxy Pod 的 Gateway 執行 Envoy Agent Router 插入的外部處理器 Sidecar:

    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 代理程式路由器相容性矩陣,瞭解目標版本支援的 Envoy Gateway 和 Gateway API 版本;Envoy 代理程式路由器 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 Pods 停留在 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 控制器無法連線至擴充功能伺服器,或是在升級後未重新啟動 確認 service/ai-gateway-controller 是否存在於 ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} 中,且列出 1063 連接埠;重複推出作業重新啟動。kubectl logs deployment/envoy-gateway --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
AIGatewayRoute參照InferencePool不接受 Envoy Gateway 缺少讀取 inferencepools 的權限,或缺少 InferencePool CRD 驗證 ClusterRoleBinding envoy-gateway-inferencepool-reader 和 inferencepools.inference.networking.k8s.io CRD;檢查控制器的 forbidden 記錄。
聊天完成要求會傳回 413,或系統會重設大型提示的連線 預設 Envoy 緩衝區大小 (32 KiB) 不足以容納 AI 酬載 將 ClientTrafficPolicy 附加至 connection.bufferLimit (驗證使用 50Mi) 的 Gateway。
服務 Pod 的速率限制為 CrashLoopBackOff 無法透過設定的網址連上 Redis kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}",修正整合值檔案中的 rateLimit.backend.redis.url,然後再次升級。

其他資料