本文档提供了有关在 Google Distributed Cloud (GDC) 气隙环境中部署 AI 网关的分步说明。该网关基于 Envoy Gateway(基于 Envoy 代理的 Kubernetes Gateway API 实现)和 Envoy Agent Router(以前称为 Envoy AI Gateway)构建,后者是一种扩展程序,可将 Envoy Gateway 转换为统一的、与 OpenAI 兼容的大语言模型 (LLM) 流量入口点。它涵盖了将容器映像和 Helm 图表植入本地 Harbor 注册表、在标准集群上安装两个控制平面、准备可选的基于令牌的速率限制后端,以及使用示例工作负载验证安装。
模型服务后端(Ollama、vLLM)已通过配套指南 GDC 气隙中的开放权重模型进行部署;使用 Envoy 代理路由器实现基于正文的路由用户指南介绍了如何按模型名称将请求路由到这些后端。
架构
该解决方案在 GDC 标准集群中运行。管理员工作站将映像和 Helm 图表植入项目的 Harbor 注册表中,并安装两个控制平面:Envoy Gateway 控制器(用于根据 Gateway API 资源 [GatewayClass、Gateway、HTTPRoute] 对 Envoy 代理数据平面进行编程)和 Envoy Agent Router 控制器(用于通过外部处理器 [ExtProc] 扩展该数据平面,以处理 AI 流量 [AIGatewayRoute、AIServiceBackend、InferencePool])。应用客户端向 Envoy 代理发送与 OpenAI 兼容的请求,Envoy 代理会将这些请求路由到模型服务后端或 InferencePool。一个可选的 Redis 实例,用于存储 Envoy 速率限制服务的计数器,以实现基于令牌的速率限制。

Envoy Gateway
Envoy Gateway 是一个基于 Envoy 代理构建的开源项目,可简化 Envoy 代理作为 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、端点选择器)集成,以实现指标感知端点选择。控制器会监控 aigateway.envoyproxy.io/v1beta1 资源,并在 Envoy 代理旁边注入一个外部处理器;该外部处理器会解析请求正文(例如 OpenAI 聊天完成请求的 model 字段),设置路由标头(例如 x-ai-eg-model),并在需要时在 API 架构之间进行转换。
准备工作
在继续进行部署之前,请确保您的环境满足所有必要的前提条件,并且已正确配置所需的命令行实用程序。在工作站上设置这些工具对于管理容器注册表、与集群互动以及自动化部署流程至关重要。
- GDC 网闸隔离配置 1.16.2-hf1 或更高版本环境适用于运行 Kubernetes v1.32.13-gke.400 或更高版本的标准集群。
- 创建了具有充足资源的 Standard 集群。网关组件仅在 CPU 上运行;模型部署后端有自己的加速器要求(请参阅 GDC 空气隔离环境中的开放权重模型指南)。
- Harbor 实例可用且可访问。
- 已应用必要的 IAM。
- 工作站,可连接到环境和互联网
环境配置
环境配置涵盖身份和权限、工作站以及对 GDC 环境和集群的访问权限。
Identity and Access Management
确保已正确配置必要的 IAM 账号、角色和权限。
项目中的 GDC User 角色(项目命名空间中的 RoleBinding,由 Project IAM Admin 授予):
- Harbor Instance Viewer (
harbor-instance-viewer) - Harbor Project Creator(
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:Harborcrane机器人账号的名称。GDCS_HARBOR_CRANE_ROBOT_TOKEN:Harborcrane机器人账号的身份验证令牌。GDCS_HARBOR_K8S_ROBOT_NAME:Harbor Kubernetes 映像拉取机器人账号的名称。GDCS_HARBOR_K8S_ROBOT_TOKEN:Harbor Kubernetes 映像拉取机器人账号的身份验证令牌。
收集完所有必需变量的值后,继续生成环境变量文件。创建后,您可以随时手动修改该文件。
创建根解决方案目录和密钥文件夹:
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/*创建平台环境配置文件:
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 实例名称。
创建注册表环境配置文件:
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 机器人账号名称。
将令牌添加到 Secret 文件中:
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 机器人令牌。
创建根环境加载器文件:
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
配置解决方案变量
创建解决方案实现目录:
mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d创建解决方案环境配置文件:
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创建实现环境加载器文件:
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使用您偏好的编辑器修改和查看环境文件:
${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获取环境文件:
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 证书。
配置
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}"向 GDC 环境进行身份验证:
gdcloud auth login
集群
检索集群凭据:
gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \ --project="${GDC_PROJECT}" \ --standard \ --zone="${GDC_ZONE}"验证与集群的连接:
kubectl get nodes -L node.cluster.private.gdc.goog/machine-class验证每个节点是否运行本指南准备工作部分中要求的 Kubernetes 版本:
kubectl get nodes -o custom-columns='NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion'
制品迁移准备工作
为 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为 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使用 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创建
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"创建
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:图表版本。
为解决方案定义所需的容器映像列表:
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)将所需的容器映像植入到制品注册表中:
${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
为解决方案定义所需的 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)将所需的 Helm 图表植入到制品注册表中:
${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh验证是否可以从 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下载 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 代理路由器集成将在下一部分中介绍。
命名空间
为 Envoy Gateway 创建命名空间。每个
Gateway的 Envoy 代理Deployment也会在此命名空间中创建:kubectl create namespace "${GDCS_ENVOY_GATEWAY_NAMESPACE}"添加
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 -
自定义资源定义
从初始图表中安装 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=-验证 CRD 是否已注册:
kubectl get crd | grep -E 'gateway.networking.k8s.io|gateway.envoyproxy.io'
控制器
为 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安装 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}"等待 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'"验证控制器及其证书生成作业的映像是否来自 Harbor:
kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \ --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
Envoy 代理和网关类
为
EnvoyProxy数据平面模板和GatewayClass创建清单。EnvoyProxy设置代理映像、映像拉取 Secret 和代理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应用
EnvoyProxy和GatewayClass的清单:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"验证
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 后面的回显后端)部署到 Envoy Gateway 命名空间,并在之后将其移除。
为快速入门工作负载创建清单:
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应用快速入门工作负载的清单:
kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"等待
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'"等待后端
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'"使用端口转发功能通过网关发送测试请求。
Gateway的 EnvoyService通过其所属网关标签找到: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-...", ... }移除快速入门工作负载:
kubectl delete \ --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
Envoy 代理路由器
Envoy 代理路由器安装到其自己的命名空间中;然后重新配置 Envoy 网关,以将其作为扩展服务器进行调用。
命名空间
为 Envoy 代理路由器控制器创建命名空间:
kubectl create namespace "${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"添加
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 -
自定义资源定义
从初始图表中安装 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=-从下载的清单中安装 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"验证 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;您也可以使用现有的 Redis 服务,只需更改下一部分中的 rateLimit.backend.redis.url 值即可。
为 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应用 Redis 的清单
Deployment:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \ --namespace="${GDCS_REDIS_NAMESPACE}"等待 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'"
控制器
为 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安装 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}"等待 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 网关,使其调用 Envoy 代理路由器控制器作为其扩展服务器,接受 InferencePool 资源作为后端,并使用 Redis 支持的速率限制服务。
为集成创建 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使用两个值文件升级 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}"为
ClusterRole创建清单,以便 Envoy 网关控制器能够监控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应用
ClusterRole的清单:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"重启 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验证速率限制服务是否已部署且可用:
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 代理路由器命名空间,并在之后将其移除。
为验证工作负载创建清单:
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应用验证工作负载的清单:
kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \ --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"等待
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'"等待模拟上游
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'"验证
Gateway的 Envoy 代理Pod是否运行由 Envoy 代理路由器注入的外部处理器 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通过使用端口转发的网关发送对话补全请求。 外部处理器读取请求正文的
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": { ... } }移除验证工作负载:
kubectl delete \ --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \ --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
操作
网关控制平面的第二天任务。
升级
- 为新版本的映像和图表设定初始值(更新
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}"、ClusterRoleenvoy-gateway-inferencepool-reader、GatewayClass、RedisDeployment,最后删除 CRD。
问题排查
| 症状 | 可能的原因 | 操作 |
|---|---|---|
helm show chart 或 helm upgrade 失败,并显示 unauthorized 或 FetchReference |
helm 没有 Harbor 的凭据(它不使用 crane Docker 配置) |
使用 Kubernetes 映像拉取机器人账号再次运行 helm registry login 步骤。 |
Envoy Gateway 或 Envoy 代理路由器 Pod 保持在 ImagePullBackOff 状态 |
映像未播种,或者命名空间中缺少映像拉取 Secret | 检查 kubectl describe pod,将映像路径与 crane ls "${GDCS_HARBOR_PROJECT_URI}/envoyproxy/gateway" 进行比较,并验证 Secret 是否存在于 ${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。 |
Chat 完成请求返回 413 或连接因提示过大而被重置 |
默认 Envoy 缓冲区限制 (32 KiB) 对于 AI 载荷来说太小 | 将具有 connection.bufferLimit(验证使用 50Mi)的 ClientTrafficPolicy 附加到 Gateway。 |
速率限制服务 Pod 为 CrashLoopBackOff |
无法通过配置的网址访问 Redis | kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}";修复集成值文件中的 rateLimit.backend.redis.url,然后再次升级。 |