En este documento, se proporcionan instrucciones paso a paso para implementar una puerta de enlace de IA en entornos aislados de Google Distributed Cloud (GDC). La puerta de enlace se compila a partir de Envoy Gateway, la implementación de la API de Kubernetes Gateway basada en el proxy de Envoy, y Envoy Agent Router (anteriormente, Envoy AI Gateway), la extensión que convierte Envoy Gateway en un punto de entrada unificado y compatible con OpenAI para el tráfico de modelos de lenguaje grandes (LLM). Se explica cómo propagar las imágenes de contenedor y los gráficos de Helm en el registro local de Harbor, instalar ambos planos de control en un clúster estándar, preparar el backend opcional de límite de frecuencia basada en tokens y validar la instalación con cargas de trabajo de muestra.
Los backends de entrega de modelos (Ollama, vLLM) se implementan con el conjunto complementario de guías Modelos de peso abierto en GDC aislado. La guía del usuario de Body-based routing with Envoy Agent Router muestra cómo enrutar solicitudes a ellos por nombre de modelo.
Arquitectura
La solución se ejecuta en un clúster estándar de GDC. Una estación de trabajo del administrador inicializa las imágenes y los gráficos de Helm en el registro de Harbor del proyecto, y luego instala los dos planos de control: el controlador de Envoy Gateway, que programa el plano de datos del proxy de Envoy a partir de los recursos de la API de Gateway (GatewayClass, Gateway, HTTPRoute), y el controlador del enrutador del agente de Envoy, que extiende ese plano de datos con un procesador externo (ExtProc) para el tráfico de IA (AIGatewayRoute, AIServiceBackend, InferencePool). Los clientes de la aplicación envían solicitudes compatibles con OpenAI al proxy de Envoy, que las enruta a los backends de entrega de modelos o a los InferencePools. Una instancia de Redis opcional almacena los contadores del servicio de límite de frecuencia de Envoy para la limitación de frecuencia basada en tokens.

Puerta de enlace de Envoy
Envoy Gateway es un proyecto de código abierto creado en el proxy de Envoy que simplifica la adopción, el uso y la administración del proxy de Envoy como una puerta de enlace de la API de Kubernetes. Implementa y extiende la API de Kubernetes Gateway, sucesora de la API de Ingress: Los recursos GatewayClass y Gateway describen los puntos de entrada, los recursos de ruta, como HTTPRoute, describen cómo se hace coincidir y se reenvía el tráfico, y el diseño orientado a roles separa las responsabilidades de los equipos de infraestructura y de aplicaciones. Envoy Gateway agrega sus propias APIs de extensión, por ejemplo, EnvoyProxy (configuración del plano de datos), Backend (extremos fuera del clúster o a los que se hace referencia por FQDN) y ClientTrafficPolicy (configuración de conexión, como límites de búfer).
Enrutador de agentes de Envoy
Envoy Agent Router (anteriormente, Envoy AI Gateway) es un proyecto de código abierto que usa Envoy Gateway para controlar el tráfico de solicitudes de los clientes de aplicaciones a los servicios de IA generativa. Proporciona una capa unificada para enrutar y administrar el tráfico de LLM con enrutamiento compatible con el modelo, autenticación upstream, límite de frecuencia basada en tokens y observabilidad, y se integra con la extensión de Gateway API Inference (InferencePool, Endpoint Picker) para la selección de extremos basada en métricas. El controlador supervisa los recursos de aigateway.envoyproxy.io/v1beta1 y, luego, inserta un procesador externo junto al proxy de Envoy. El procesador externo analiza el cuerpo de la solicitud (por ejemplo, el campo model de una solicitud de finalización de chat de OpenAI), establece encabezados de enrutamiento, como x-ai-eg-model, y traduce entre esquemas de API cuando es necesario.
Antes de comenzar
Antes de continuar con la implementación, asegúrate de que tu entorno cumpla con todos los requisitos previos necesarios y de que las utilidades de línea de comandos requeridas estén configuradas correctamente. Configurar estas herramientas en tu estación de trabajo es fundamental para administrar registros de contenedores, interactuar con clústeres y automatizar el proceso de implementación.
- El entorno aislado de GDC 1.16.2-hf1 o posterior está disponible con un clúster estándar que ejecuta Kubernetes v1.32.13-gke.400 o posterior.
- Se creó un clúster estándar con recursos suficientes. Los componentes de la puerta de enlace solo se ejecutan en la CPU. Los backends de entrega de modelos tienen sus propios requisitos de acelerador (consulta las guías de Modelos de código abierto en GDC con aislamiento de aire).
- La instancia de Harbor está disponible y se puede acceder a ella.
- Se aplicó el IAM necesario.
- Estación de trabajo con la conectividad necesaria para el entorno y la Internet
Configuración del entorno
La configuración del entorno abarca las identidades y los permisos, la estación de trabajo y el acceso al entorno de GDC y al clúster.
Identity and Access Management
Asegúrate de que las cuentas, los roles y los permisos de IAM necesarios estén configurados correctamente.
Roles de usuario de GDC en project (RoleBinding en el espacio de nombres del proyecto, otorgado por un administrador de IAM del proyecto):
- Visualizador de instancias de Harbor (
harbor-instance-viewer) - Creador del proyecto de Harbor (
harbor-project-creator, solo si el proyecto de Harbor aún no existe) - Administrador de clúster estándar (
standard-cluster-admin, obligatorio paragdcloud clusters get-credentials)
Rol de Usuario de GDC en el clúster estándar: Los roles de proyecto anteriores no otorgan permisos dentro del clúster. Además, un administrador de IAM del proyecto debe vincular al usuario a StandardClusterRole cluster-admin con un StandardClusterRoleBinding en el espacio de nombres del proyecto en el servidor de la API de administración. La vinculación se propaga a los clústeres estándar del proyecto en cuestión de segundos (status.clusters[].conditions muestra Propagated=True). Se requieren permisos para todo el clúster porque en esta guía se instalan definiciones de recursos personalizados, ClusterRole y un 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
Reemplaza lo siguiente:
MANAGEMENT_API_SERVER: Es la ruta al archivo kubeconfig del servidor de la API de administración.USER: Usuario.PROJECT: proyecto.
Permisos de la cuenta de robot de Harbor crane (crane):
- List Repository
- Extraer repositorio
- Repositorio de envío
- Leer artefacto
- List Artifact
- Crear etiqueta
- Etiqueta de lista
Permisos de la cuenta de robot de extracción de imágenes de Kubernetes de Harbor (kubernetes-image-puller):
- List Repository
- Extraer repositorio
- Leer artefacto
- Enumera artefactos
- Etiqueta de lista
Estación de trabajo
Esta guía requiere una estación de trabajo con la conectividad necesaria para el entorno y la Internet.
Requisitos
Las siguientes herramientas deben instalarse en la estación de trabajo:
crane: Administra y copia imágenes de contenedores y artefactos de OCI entre registros (documentación).gdcloud: Es la interfaz de línea de comandos (CLI) para administrar recursos de GDC (documentación).kubectl: Es la interfaz de línea de comandos (CLI) que se usa para comunicarse con un clúster de Kubernetes y administrarlo.helm: Administrador de paquetes para Kubernetes, versión 3.8 o posterior (compatibilidad con el registro de OCI) (documentación).curl: Herramienta de línea de comandos para transferir datos con URLs.jq: Es un procesador de JSON de línea de comandos ligero y flexible.yq: Es un procesador de YAML portátil de línea de comandos.
Ejecuta todos los comandos de esta guía desde la estación de trabajo, a menos que se indique lo contrario en un paso.
Configuración de la estación de trabajo
Se requiere la siguiente información sobre el entorno para la configuración de la estación de trabajo:
GDC_STANDARD_CLUSTER_NAME: Es el nombre del clúster estándar de GDC.GDC_DOMAIN_SUFFIX: Es el sufijo de dominio para el entorno de GDC (por ejemplo,gdc.example.com).GDC_ORG: Es el nombre de la organización de GDC.GDC_PROJECT: Es el nombre del proyecto de GDC.GDC_ZONE: Es el nombre de la zona de implementación de GDC.GDC_HARBOR_INSTANCE_NAME: Es el nombre de la instancia de Harbor en el proyecto.GDCS_HARBOR_PROJECT_NAME: Es el nombre del proyecto de Harbor que se usará para la imagen (el valor predeterminado essolutions).GDCS_HARBOR_CRANE_ROBOT_NAME: Es el nombre de la cuenta de robot decranede Harbor.GDCS_HARBOR_CRANE_ROBOT_TOKEN: Es el token de autenticación para la cuenta de robot decranede Harbor.GDCS_HARBOR_K8S_ROBOT_NAME: Es el nombre de la cuenta de robot de extracción de imágenes de Kubernetes de Harbor.GDCS_HARBOR_K8S_ROBOT_TOKEN: Es el token de autenticación para la cuenta de robot de extracción de imágenes de Kubernetes de Harbor.
Una vez que hayas recopilado los valores de todas las variables obligatorias, continúa con la generación del archivo de variables de entorno. Después de crearlo, puedes editar el archivo manualmente en cualquier momento.
Crea los directorios raíz de la solución y la carpeta de secretos:
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/*Crea el archivo de configuración del entorno de la plataforma:
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}" EOFReemplaza lo siguiente:
STANDARD_CLUSTER_NAME: Es el nombre del clúster estándar de GDC.DOMAIN_SUFFIX: Sufijo del dominio de GDC.ORG: Organización de la GDC.PROJECT: Proyecto de GDC.ZONE: Es la zona de GDC.HARBOR_INSTANCE_NAME: Es el nombre de la instancia de GDC Harbor.
Crea el archivo de configuración del entorno de registro:
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}" EOFReemplaza lo siguiente:
HARBOR_CRANE_ROBOT_NAME: Es el nombre de la cuenta del robot de GDC Harbor.HARBOR_K8S_ROBOT_NAME: Es el nombre de la cuenta del robot de GDC Harbor.
Agrega tus tokens a los archivos de 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 historyReemplaza lo siguiente:
CRANE_ROBOT_TOKEN: Es el token del robot grúa.KUBERNETES_ROBOT_TOKEN: Es el token de robot de Kubernetes.
Crea el archivo de carga del entorno raíz:
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
Configura las variables de solución
Crea el directorio de implementación de la solución:
mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.dCrea el archivo de configuración del entorno de solución:
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" EOFCrea el archivo de carga del entorno de implementación:
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" EOFEdita y revisa los archivos del entorno con tu editor preferido:
${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.shEjecuta el archivo de entorno:
source ${HOME}/gdcag-solutions/ai-gateway/envoy/env.shEl resultado es similar a lo siguiente:
GDCS_ROOT_HOME=HOME_DIRECTORY_PATH/gdcag-solutions GDCS_IMPLEMENTATION_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/ai-gateway/envoy
GDC
En esta guía, se supone que tu estación de trabajo está configurada para confiar en los certificados TLS de tu entorno de GDC y tu instancia de Harbor.
Configura
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}"Autentícate en el entorno de GDC:
gdcloud auth login
Clúster
Recupera las credenciales del clúster:
gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \ --project="${GDC_PROJECT}" \ --standard \ --zone="${GDC_ZONE}"Verifica la conectividad con el clúster:
kubectl get nodes -L node.cluster.private.gdc.goog/machine-classVerifica que cada nodo ejecute la versión de Kubernetes que se requiere en la sección Antes de comenzar de esta guía:
kubectl get nodes -o custom-columns='NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion'
Preparación de la migración de artefactos
- Verifica la conectividad y la configuración del registro de artefactos.
Crea un archivo de configuración de Docker para crane. Se usa una cuenta de robot para enviar capas de imágenes grandes y evitar los tiempos de espera del token de autenticación cuando se usa el asistente de credenciales de Managed Harbor Service (MHS) (docker-credential-mhs) con una cuenta de usuario:
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 historyCrea un archivo de configuración de Docker para Kubernetes:
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 historyAccede al registro de OCI de Harbor con
helmusando la cuenta de robot de extracción de imágenes de Kubernetes.helmmantiene sus propias credenciales de registro y las necesita para recuperar los gráficos de Harbor:set +o history helm registry login "${GDC_HARBOR_HOST}" \ --password="${GDCS_HARBOR_K8S_ROBOT_TOKEN}" \ --username="${GDCS_HARBOR_K8S_ROBOT_NAME}" set -o historyEl resultado es similar a lo siguiente:
Login SucceededCrea la secuencia de comandos
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"Crea la secuencia de comandos
seed_charts.shLos gráficos de Helm publicados como artefactos de OCI también se copian concrane, sin selección de plataforma y sin la etiquetacreateque se usa para los repositorios de imágenes de contenedor: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"Reemplaza lo siguiente:
REGISTRY_HOST: Host del registro.REPOSITORY: repositorio.CHART_VERSION: Es la versión del gráfico.
Define la lista de imágenes de contenedor requeridas para la solución:
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)Propaga las imágenes de contenedor necesarias en Artifact Registry:
${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
Define la lista de gráficos de Helm necesarios para la solución:
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)Propaga los gráficos de Helm necesarios en el registro de artefactos:
${GDCS_IMPLEMENTATION_HOME}/seed_charts.shVerifica que los gráficos se puedan leer desde 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):'El resultado es similar a lo siguiente:
name: gateway-helm version: v1.8.5 name: ai-gateway-helm version: v1.1.0Descarga los manifiestos de la extensión de inferencia de la API de Gateway. Se publican como un recurso de versión, no como un gráfico:
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"El resultado es similar a lo siguiente:
4
Puerta de enlace de Envoy
Primero, se instala Envoy Gateway y se valida por sí solo con la guía de inicio rápido de upstream. La integración del enrutador de Envoy Agent se explica en la siguiente sección.
Espacio de nombres
Crea el espacio de nombres para Envoy Gateway. Los proxies de Envoy
Deploymentde cadaGatewaytambién se crean en este espacio de nombres:kubectl create namespace "${GDCS_ENVOY_GATEWAY_NAMESPACE}"Agrega el
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 -
Definiciones de recursos personalizados
Instala la API de Gateway (canal estándar) y las definiciones de recursos personalizados (CRD) de Envoy Gateway desde el gráfico inicial:
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=-Verifica que las CRD estén registradas:
kubectl get crd | grep -E 'gateway.networking.k8s.io|gateway.envoyproxy.io'
Controlador
Crea el archivo de valores de Helm para Envoy Gateway. Las imágenes se extraen de Harbor con el secreto de extracción de imágenes;
crds.enabled=falseporque los CRD se instalaron por separado: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} EOFInstala 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}"Espera a que el controlador de Envoy Gateway esté disponible:
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'"Verifica que las imágenes del controlador y su trabajo de generación de certificados provengan de Harbor:
kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \ --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
Proxy de Envoy y clase Gateway
Crea el manifiesto para la plantilla del plano de datos
EnvoyProxyy elGatewayClass. ElEnvoyProxyestablece la imagen del proxy, el secreto de extracción de la imagen y las solicitudes de recursos de losPoddel proxy; elGatewayClassse comparte en las guías del usuario: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} EOFAplica el manifiesto para
EnvoyProxyyGatewayClass:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"Verifica que el
GatewayClassesté aceptado:kubectl get gatewayclass "${GDCS_GATEWAY_CLASS_NAME}"El resultado es similar a lo siguiente:
NAME CONTROLLER ACCEPTED AGE envoy-ai-gateway gateway.envoyproxy.io/gatewayclass-controller True 5s
Validación
La validación implementa la guía de inicio rápido de Envoy Gateway (un backend de eco detrás de un HTTPRoute) en el espacio de nombres de Envoy Gateway y, luego, lo quita.
Crea el manifiesto para la carga de trabajo de inicio rápido:
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: / EOFAplica el manifiesto para la carga de trabajo de inicio rápido:
kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"Espera a que se programe el
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'"Espera a que el backend
Deploymentesté disponible: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'"Envía una solicitud de prueba a través de la puerta de enlace con el reenvío de puertos. El Envoy
Servicede unGatewayse encuentra por las etiquetas de la puerta de enlace propietaria: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}El resultado es similar a lo siguiente:
{ "path": "/get", "host": "www.example.com", "method": "GET", ... "namespace": "envoy-gateway-system", "pod": "eg-quickstart-backend-...", ... }Quita la carga de trabajo de inicio rápido:
kubectl delete \ --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
Enrutador de agentes de Envoy
El enrutador del agente de Envoy se instala en su propio espacio de nombres. Luego, se vuelve a configurar la puerta de enlace de Envoy para que la llame como su servidor de extensión.
Espacio de nombres
Crea el espacio de nombres para el controlador del enrutador del agente de Envoy:
kubectl create namespace "${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"Agrega el
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 -
Definiciones de recursos personalizados
Instala las CRD del Envoy Agent Router desde el gráfico inicial:
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=-Instala las CRD de la extensión de inferencia de la API de Gateway (
InferencePool,InferenceObjective) desde los manifiestos descargados:kubectl apply --server-side \ --filename="${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml"Verifica que las CRD estén registradas:
kubectl get crd | grep -E 'aigateway.envoyproxy.io|inference.networking'El resultado es similar a lo siguiente:
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
El servicio de límite de frecuencia de Envoy, que almacena sus contadores en Redis, aplica el límite de frecuencia basado en tokens. En esta guía, se implementa un servidor Redis de una sola réplica sin persistencia. En su lugar, se puede usar un servicio Redis existente cambiando el valor de rateLimit.backend.redis.url en la siguiente sección.
Crea el manifiesto para el
Deploymentde Redis: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 EOFAplica el manifiesto para el
Deploymentde Redis:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \ --namespace="${GDCS_REDIS_NAMESPACE}"Espera a que el
Deploymentde Redis esté disponible: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'"
Controlador
Crea el archivo de valores de Helm para Envoy Agent Router:
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} EOFInstala el enrutador del agente de 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}"Espera a que el controlador del router del agente de Envoy esté disponible:
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'"
Integración de Envoy Gateway
La puerta de enlace de Envoy debe reconfigurarse para llamar al controlador del enrutador del agente de Envoy como su servidor de extensión, aceptar recursos InferencePool como backends y usar el servicio de límite de frecuencia respaldado por Redis.
Crea el archivo de valores de Helm para la integración:
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 EOFActualiza Envoy Gateway con ambos archivos de valores:
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}"Crea el manifiesto para el
ClusterRoleque permite que el controlador de Envoy Gateway observe los recursosInferencePool. El gráfico no otorga este permiso; unClusterRoleBindingindependiente sobrevive a las actualizaciones del gráfico, a diferencia de un parche delClusterRoleadministrado por el gráfico: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} EOFAplica el manifiesto para
ClusterRole:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"Reinicia el controlador de Envoy Gateway para que adopte la nueva configuración y los permisos, y espera a que esté disponible:
kubectl rollout restart deployment/envoy-gateway \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" kubectl rollout status deployment/envoy-gateway \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \ --timeout=5mVerifica que el servicio de límite de frecuencia se haya implementado y esté disponible:
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'"
Validación
La validación implementa el ejemplo básico del router de Envoy Agent (un upstream simulado compatible con OpenAI detrás de un AIGatewayRoute) en el espacio de nombres del router de Envoy Agent y lo quita después.
Crea el manifiesto para la carga de trabajo de validación:
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 EOFAplica el manifiesto para la carga de trabajo de validación:
kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \ --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"Espera a que se programe el
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'"Espera a que el upstream simulado
Deploymentesté disponible: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'"Verifica que el proxy de Envoy
PoddelGatewayejecute el sidecar del procesador externo insertado por el enrutador del agente de Envoy:kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \ --selector="gateway.envoyproxy.io/owning-gateway-name=aieg-basic" \ --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].name}{"\n"}{end}'El resultado es similar a lo siguiente:
envoy-envoy-ai-gateway-system-aieg-basic-... envoy shutdown-manager ai-gateway-extprocEnvía una solicitud de finalización de chat a través de la puerta de enlace con el reenvío de puertos. El procesador externo lee el campo
modeldel cuerpo de la solicitud y lo enruta al upstream simulado: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}El resultado es similar a lo siguiente:
{ "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { ... } }Quita la carga de trabajo de validación:
kubectl delete \ --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \ --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
Operaciones
Tareas del segundo día para los planos de control de la puerta de enlace.
Actualizar
- Propaga las imágenes y los gráficos de las versiones nuevas (actualiza las variables de versión en
env.sh, vuelve a ejecutarseed_registry.shyseed_charts.sh), aplica los nuevos gráficos de CRD conkubectl apply --server-sidey, luego, ejecuta los mismos comandos dehelm upgrade --installcon el nuevo--version. Consulta la matriz de compatibilidad del enrutador de Envoy Agent para conocer las versiones de Envoy Gateway y de la API de Gateway que admite la versión de destino. El enrutador de Envoy Agent 1.1.0 se compila en Envoy Gateway 1.8.
Desinstalar
- Primero, borra los recursos
Gateway,AIGatewayRouteyInferencePoolde las guías del usuario y, luego,helm uninstall aieg --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}",helm uninstall eg --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}", elClusterRoleenvoy-gateway-inferencepool-reader, elGatewayClass, elDeploymentde Redis y, por último, las CRD.
Soluciona problemas
| Síntoma | Causa probable | Acción |
|---|---|---|
helm show chart o helm upgrade falla con unauthorized o FetchReference |
helm no tiene credenciales para Harbor (no usa la configuración de Docker crane). |
Vuelve a ejecutar el paso helm registry login con la cuenta de robot de extracción de imágenes de Kubernetes. |
Envoy Gateway o Envoy Agent Router Pods permanecen en ImagePullBackOff |
No se propagó la imagen o falta el secreto de extracción de la imagen en el espacio de nombres | Verifica kubectl describe pod, compara la ruta de acceso a la imagen con crane ls "${GDCS_HARBOR_PROJECT_URI}/envoyproxy/gateway" y verifica que el secreto exista en ${GDCS_ENVOY_GATEWAY_NAMESPACE} y ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}. |
Gateway permanece Programmed=False después de la integración |
El controlador de Envoy Gateway no puede acceder al servidor de extensión o no se reinició después de la actualización. | kubectl logs deployment/envoy-gateway --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"; confirma que service/ai-gateway-controller existe en ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} y que el puerto 1063 aparece en la lista; repite el reinicio de la implementación. |
No se acepta la referencia AIGatewayRoute a un InferencePool |
Envoy Gateway no tiene permiso para leer inferencepools, o faltan los CRD de InferencePool |
Verifica el CRD ClusterRoleBinding envoy-gateway-inferencepool-reader y el CRD inferencepools.inference.networking.k8s.io; revisa los registros del controlador para forbidden. |
La solicitud de finalización de chat devuelve 413 o se restablece la conexión para instrucciones grandes |
El límite predeterminado del búfer de Envoy (32 KiB) es demasiado pequeño para las cargas útiles de IA. | Adjunta un ClientTrafficPolicy con connection.bufferLimit (la validación usa 50 Mi) al Gateway. |
El servicio de límite de frecuencia Pod es CrashLoopBackOff |
No se puede acceder a Redis en la URL configurada | kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}"; corrige rateLimit.backend.redis.url en el archivo de valores de integración y vuelve a actualizar. |
Materiales adicionales
- Documentación de Envoy Agent Router
- Notas de la versión y matriz de compatibilidad del agente de Envoy Router
- Documentación de Envoy Gateway
- API de puerta de enlace de Kubernetes
- Extensión de Gateway API Inference
- Crea un clúster estándar | Google Distributed Cloud aislado
Guía del usuario del enrutador de Envoy Agent para el enrutamiento basado en el cuerpo