Ce document fournit des instructions détaillées pour déployer une passerelle d'IA sur des environnements Google Distributed Cloud (GDC) air gap. La passerelle est basée sur Envoy Gateway, l'implémentation de l'API Kubernetes Gateway basée sur le proxy Envoy, et sur Envoy Agent Router (anciennement Envoy AI Gateway), l'extension qui transforme Envoy Gateway en un point d'entrée unifié et compatible avec OpenAI pour le trafic des grands modèles de langage (LLM). Il explique comment amorcer les images de conteneurs et les charts Helm dans le registre Harbor local, installer les deux plans de contrôle sur un cluster standard, préparer le backend de limitation du débit basé sur des jetons (facultatif) et valider l'installation avec des exemples de charges de travail.
Les backends de mise en service de modèles (Ollama, vLLM) sont déployés avec l'ensemble de guides Modèles Open Weights sur GDC avec air gap. Le guide de l'utilisateur sur le routage basé sur le corps avec Envoy Agent Router explique comment acheminer les requêtes vers ces backends par nom de modèle.
Architecture
La solution s'exécute dans un cluster GDC standard. Un poste de travail administrateur injecte les images et les charts Helm dans le registre Harbor du projet, puis installe les deux plans de contrôle : le contrôleur Envoy Gateway, qui programme le plan de données du proxy Envoy à partir des ressources de l'API Gateway (GatewayClass, Gateway, HTTPRoute), et le contrôleur Envoy Agent Router, qui étend ce plan de données avec un processeur externe (ExtProc) pour le trafic d'IA (AIGatewayRoute, AIServiceBackend, InferencePool). Les clients d'application envoient des requêtes compatibles avec OpenAI au proxy Envoy, qui les achemine vers les backends de mise en service du modèle ou les InferencePool. Une instance Redis facultative stocke les compteurs du service de limitation du débit Envoy pour la limitation du débit basée sur des jetons.

Envoy Gateway
Envoy Gateway est un projet Open Source basé sur le proxy Envoy, qui simplifie l'adoption, l'utilisation et la gestion du proxy Envoy en tant qu'API Gateway Kubernetes. Il implémente et étend l'API Kubernetes Gateway, qui succède à l'API Ingress : les ressources GatewayClass et Gateway décrivent les points d'entrée, les ressources de routage telles que HTTPRoute décrivent la façon dont le trafic est mis en correspondance et transféré, et la conception orientée rôles sépare les responsabilités des équipes d'infrastructure et d'application. Envoy Gateway ajoute ses propres API d'extension, par exemple EnvoyProxy (paramètres du plan de données), Backend (points de terminaison en dehors du cluster ou référencés par un nom de domaine complet) et ClientTrafficPolicy (paramètres de connexion tels que les limites de tampon).
Routeur de l'agent Envoy
Envoy Agent Router (anciennement Envoy AI Gateway) est un projet Open Source qui utilise Envoy Gateway pour gérer le trafic des requêtes des clients d'application vers les services d'IA générative. Il fournit une couche unifiée pour le routage et la gestion du trafic LLM avec un routage tenant compte du modèle, une authentification en amont, une limitation du débit basée sur les jetons et l'observabilité. Il s'intègre également à l'extension d'inférence de l'API Gateway (InferencePool, Endpoint Picker) pour la sélection de points de terminaison tenant compte des métriques. Le contrôleur surveille les ressources aigateway.envoyproxy.io/v1beta1 et injecte un processeur externe à côté du proxy Envoy. Le processeur externe analyse le corps de la requête (par exemple, le champ model d'une requête de complétion de chat OpenAI), définit des en-têtes de routage tels que x-ai-eg-model et traduit les schémas de l'API si nécessaire.
Avant de commencer
Avant de procéder au déploiement, assurez-vous que votre environnement remplit toutes les conditions préalables nécessaires et que les utilitaires de ligne de commande requis sont correctement configurés. La configuration de ces outils sur votre poste de travail est essentielle pour gérer les registres de conteneurs, interagir avec les clusters et automatiser le processus de déploiement.
- L'environnement GDC sous air gap 1.16.2-hf1 ou version ultérieure est disponible avec un cluster standard qui exécute Kubernetes v1.32.13-gke.400 ou version ultérieure.
- Le cluster standard a été créé avec suffisamment de ressources. Les composants de la passerelle s'exécutent uniquement sur le processeur. Les backends de mise en service du modèle ont leurs propres exigences d'accélérateur (consultez les guides Modèles à pondération ouverte sur GDC avec air gap).
- Instance Harbor disponible et accessible.
- Les autorisations IAM nécessaires ont été appliquées.
- Poste de travail disposant de la connectivité nécessaire à l'environnement et à Internet
Configuration de l'environnement
La configuration de l'environnement couvre les identités et les autorisations, le poste de travail et l'accès à l'environnement GDC et au cluster.
Identity and Access Management
Assurez-vous que les comptes, rôles et autorisations IAM nécessaires sont correctement configurés.
Rôles d'utilisateur GDC sur le projet (RoleBinding dans l'espace de noms du projet, accordés par un administrateur de projet IAM) :
- Lecteur d'instance Harbor (
harbor-instance-viewer) - Créateur de projet Harbor (
harbor-project-creator, uniquement si le projet Harbor n'existe pas encore) - Administrateur de cluster standard (
standard-cluster-admin, requis pourgdcloud clusters get-credentials)
Rôle Utilisateur GDC sur le cluster standard : les rôles de projet précédents n'accordent aucune autorisation dans le cluster. Un administrateur IAM du projet doit également lier l'utilisateur au cluster-admin StandardClusterRole avec un StandardClusterRoleBinding dans l'espace de noms du projet sur le serveur de l'API de gestion. La liaison est propagée aux clusters standards du projet en quelques secondes (status.clusters[].conditions affiche Propagated=True). Des autorisations au niveau du cluster sont requises, car ce guide installe des définitions de ressources personnalisées, des ClusterRole et 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
Remplacez les éléments suivants :
MANAGEMENT_API_SERVER: chemin d'accès au fichier kubeconfig du serveur d'API de gestion.USER: utilisateur.PROJECT: projet.
Autorisations du compte robot Harbor crane (crane) :
- Lister le dépôt
- Extraire le dépôt
- Dépôt push
- Lire l'artefact
- Lister l'artefact
- Créer un tag
- Balise de liste
Autorisations du compte de robot d'extraction d'images Kubernetes Harbor (kubernetes-image-puller) :
- Lister le dépôt
- Extraire le dépôt
- Lire l'artefact
- Lister l'artefact
- Balise de liste
Station de travail
Sauf indication contraire, exécutez toutes les commandes de ce guide à partir d'un poste de travail disposant des outils requis et d'une connectivité à l'environnement et à Internet.
Conditions requises
Les outils suivants doivent être installés sur le poste de travail :
crane: gérez et copiez des images de conteneurs et des artefacts OCI entre les registres (documentation).gdcloud: interface de ligne de commande (CLI) permettant de gérer les ressources GDC (documentation).kubectl: interface de ligne de commande (CLI) utilisée pour communiquer avec un cluster Kubernetes et le gérer.helm: gestionnaire de packages pour Kubernetes, version 3.8 ou ultérieure (compatibilité avec le registre OCI) (documentation).curl: outil de ligne de commande permettant de transférer des données avec des URL.jq: processeur JSON de ligne de commande léger et flexible.yq: processeur YAML portable en ligne de commande.
Exécutez toutes les commandes de ce guide à partir du poste de travail, sauf indication contraire.
Configuration de la station de travail
Les informations suivantes sur l'environnement sont requises pour la configuration de la station de travail :
GDC_STANDARD_CLUSTER_NAME: nom du cluster GDC Standard.GDC_DOMAIN_SUFFIX: suffixe de domaine de l'environnement GDC (par exemple,gdc.example.com).GDC_ORG: nom de l'organisation GDC.GDC_PROJECT: nom du projet GDC.GDC_ZONE: nom de la zone de déploiement GDC.GDC_HARBOR_INSTANCE_NAME: nom de l'instance Harbor dans le projet.GDCS_HARBOR_PROJECT_NAME: nom du projet Harbor à utiliser pour l'image (par défaut :solutions)GDCS_HARBOR_CRANE_ROBOT_NAME: nom du compte de robot Harborcrane.GDCS_HARBOR_CRANE_ROBOT_TOKEN: jeton d'authentification du compte de robot Harborcrane.GDCS_HARBOR_K8S_ROBOT_NAME: nom du compte robot d'extraction d'images Kubernetes Harbor.GDCS_HARBOR_K8S_ROBOT_TOKEN: jeton d'authentification du compte de robot d'extraction d'images Kubernetes Harbor.
Une fois que vous avez collecté les valeurs de toutes les variables requises, générez le fichier de variables d'environnement. Une fois le fichier créé, vous pouvez le modifier manuellement à tout moment.
Créez les répertoires de la solution racine et le dossier des secrets :
mkdir -p ${HOME}/gdcag-solutions/env.d mkdir -p ${HOME}/gdcag-solutions/secrets touch ${HOME}/gdcag-solutions/secrets/harbor_crane_robot_token touch ${HOME}/gdcag-solutions/secrets/harbor_k8s_robot_token chmod u=rwx,go= ${HOME}/gdcag-solutions/secrets chmod -R u=rw,go= ${HOME}/gdcag-solutions/secrets/*Créez le fichier de configuration de l'environnement de la plate-forme :
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}" EOFRemplacez les éléments suivants :
STANDARD_CLUSTER_NAME: nom du cluster GDC standard.DOMAIN_SUFFIX: suffixe de domaine GDC.ORG: organisation GDC.PROJECT: projet GDC.ZONE: zone GDC.HARBOR_INSTANCE_NAME: nom de l'instance GDC Harbor.
Créez le fichier de configuration de l'environnement du registre :
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}" EOFRemplacez les éléments suivants :
HARBOR_CRANE_ROBOT_NAME: nom du compte robot GDC Harbor.HARBOR_K8S_ROBOT_NAME: nom du compte robot GDC Harbor.
Ajoutez vos jetons aux fichiers de secrets :
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 historyRemplacez les éléments suivants :
CRANE_ROBOT_TOKEN: jeton du robot Crane.KUBERNETES_ROBOT_TOKEN: jeton de robot Kubernetes.
Créez le fichier de chargement de l'environnement racine :
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
Configurer les variables de solution
Créez le répertoire d'implémentation de la solution :
mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.dCréez le fichier de configuration de l'environnement de la solution :
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" EOFCréez le fichier de chargement de l'environnement d'implémentation :
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" EOFModifiez et examinez les fichiers d'environnement avec l'éditeur de votre choix :
${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.shSourcez le fichier d'environnement :
source ${HOME}/gdcag-solutions/ai-gateway/envoy/env.shLe résultat ressemble à ce qui suit :
GDCS_ROOT_HOME=HOME_DIRECTORY_PATH/gdcag-solutions GDCS_IMPLEMENTATION_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/ai-gateway/envoy
GDC
Ce guide suppose que votre poste de travail est configuré pour faire confiance aux certificats TLS de votre environnement GDC et de votre instance Harbor.
Configurez
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}"Authentifiez-vous auprès de l'environnement GDC :
gdcloud auth login
Cluster
Récupérez les identifiants du cluster :
gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \ --project="${GDC_PROJECT}" \ --standard \ --zone="${GDC_ZONE}"Vérifiez la connectivité au cluster :
kubectl get nodes -L node.cluster.private.gdc.goog/machine-class
Préparation de la migration des artefacts
- Vérifiez la connectivité et la configuration d'Artifact Registry.
Créez un fichier de configuration Docker pour Crane. Un compte de robot est utilisé pour transférer des couches d'images volumineuses afin d'éviter les délais d'expiration des jetons d'authentification lors de l'utilisation de l'assistant d'identification Managed Harbor Service (MHS) (docker-credential-mhs) avec un compte utilisateur :
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 historyCréez un fichier de configuration Docker pour 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 historyConnectez-vous au registre OCI Harbor avec
helmà l'aide du compte robot d'extraction d'images Kubernetes.helmconserve ses propres identifiants de registre et en a besoin pour récupérer les charts depuis Harbor :set +o history helm registry login "${GDC_HARBOR_HOST}" \ --password="${GDCS_HARBOR_K8S_ROBOT_TOKEN}" \ --username="${GDCS_HARBOR_K8S_ROBOT_NAME}" set -o historyLe résultat ressemble à ce qui suit :
Login SucceededCréez le script
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"Créez le script
seed_charts.sh. Les charts Helm publiés en tant qu'artefacts OCI sont également copiés aveccrane, sans sélection de plate-forme et sans le tagcreateutilisé pour les dépôts d'images de conteneurs :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"Remplacez les éléments suivants :
REGISTRY_HOST: hôte du registre.REPOSITORY: dépôt.CHART_VERSION: version du chart.
Définissez la liste des images de conteneurs requises pour la solution :
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)Amorcez les images de conteneurs requises dans Artifact Registry :
${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
Définissez la liste des charts Helm requis pour la solution :
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)Transférez les charts Helm requis vers Artifact Registry :
${GDCS_IMPLEMENTATION_HOME}/seed_charts.shVérifiez que les charts peuvent être lus à partir de 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):'Le résultat ressemble à ce qui suit :
name: gateway-helm version: v1.8.5 name: ai-gateway-helm version: v1.1.0Téléchargez les fichiers manifestes de l'extension d'inférence de l'API Gateway. Ils sont publiés en tant qu'élément de version, et non en tant que chart :
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"Le résultat ressemble à ce qui suit :
4
Envoy Gateway
Envoy Gateway est d'abord installé et validé seul avec le guide de démarrage rapide en amont. L'intégration d'Envoy Agent Router est abordée dans la section suivante.
Espace de noms
Créez l'espace de noms pour Envoy Gateway. Les
Deploymentdu proxy Envoy de chaqueGatewaysont également créés dans cet espace de noms :kubectl create namespace "${GDCS_ENVOY_GATEWAY_NAMESPACE}"Ajoutez le
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 -
Définitions de ressources personnalisées
Installez l'API Gateway (canal standard) et les définitions de ressources personnalisées (CRD) Envoy Gateway à partir du chart d'amorçage :
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=-Vérifiez que les CRD sont enregistrées :
kubectl get crd | grep -E 'gateway.networking.k8s.io|gateway.envoyproxy.io'
Contrôleur
Créez le fichier de valeurs Helm pour Envoy Gateway. Les images sont extraites de Harbor avec le secret d'extraction d'image ;
crds.enabled=false, car les CRD ont été installés séparément :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} EOFInstallez 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}"Attendez que le contrôleur Envoy Gateway soit 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'"Vérifiez que les images du contrôleur et de son job de génération de certificat proviennent de Harbor :
kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \ --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
Proxy Envoy et classe Gateway
Créez le fichier manifeste pour le modèle de plan de données
EnvoyProxyet leGatewayClass.EnvoyProxydéfinit l'image du proxy, le secret d'extraction d'image et les requêtes de ressources desPods du proxy.GatewayClassest partagé par les guides de l'utilisateur :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} EOFAppliquez le fichier manifeste pour
EnvoyProxyetGatewayClass:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"Vérifiez que la
GatewayClassest acceptée :kubectl get gatewayclass "${GDCS_GATEWAY_CLASS_NAME}"Le résultat ressemble à ce qui suit :
NAME CONTROLLER ACCEPTED AGE envoy-ai-gateway gateway.envoyproxy.io/gatewayclass-controller True 5s
Validation
La validation déploie le guide de démarrage rapide d'Envoy Gateway (un backend d'écho derrière un HTTPRoute) dans l'espace de noms Envoy Gateway, puis le supprime.
Créez le fichier manifeste pour la charge de travail du guide de démarrage rapide :
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: / EOFAppliquez le fichier manifeste pour la charge de travail du guide de démarrage rapide :
kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"Attendez que le
Gatewaysoit programmé :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'"Attendez que le backend
Deploymentsoit 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'"Envoyez une requête de test via la passerelle à l'aide du transfert de port. Le
ServiceEnvoy d'unGatewayest identifié par ses libellés de passerelle propriétaire :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}Le résultat ressemble à ce qui suit :
{ "path": "/get", "host": "www.example.com", "method": "GET", ... "namespace": "envoy-gateway-system", "pod": "eg-quickstart-backend-...", ... }Supprimez la charge de travail du guide de démarrage rapide :
kubectl delete \ --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
Routeur de l'agent Envoy
Le routeur de l'agent Envoy est installé dans son propre espace de noms. Envoy Gateway est ensuite reconfiguré pour l'appeler en tant que serveur d'extension.
Espace de noms
Créez l'espace de noms pour le contrôleur de routeur de l'agent Envoy :
kubectl create namespace "${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"Ajoutez le
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 -
Définitions de ressources personnalisées
Installez les CRD du routeur de l'agent Envoy à partir du chart d'amorçage :
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=-Installez les CRD de l'extension d'inférence de l'API Gateway (
InferencePool,InferenceObjective) à partir des fichiers manifestes téléchargés :kubectl apply --server-side \ --filename="${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml"Vérifiez que les CRD sont enregistrées :
kubectl get crd | grep -E 'aigateway.envoyproxy.io|inference.networking'Le résultat ressemble à ce qui suit :
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
La limitation du débit basée sur les jetons est appliquée par le service de limitation du débit Envoy, qui stocke ses compteurs dans Redis. Ce guide déploie une instance répliquée Redis unique sans persistance. Un service Redis existant peut être utilisé à la place en modifiant la valeur rateLimit.backend.redis.url dans la section suivante.
Créez le fichier manifeste pour le
DeploymentRedis :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 EOFAppliquez le fichier manifeste pour le
DeploymentRedis :kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \ --namespace="${GDCS_REDIS_NAMESPACE}"Attendez que l'instance Redis
Deploymentsoit 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'"
Contrôleur
Créez le fichier de valeurs Helm pour le routeur d'agent Envoy :
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} EOFInstallez le routeur de l'agent 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}"Attendez que le contrôleur du routeur de l'agent Envoy soit 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'"
Intégration d'Envoy Gateway
Envoy Gateway doit être reconfiguré pour appeler le contrôleur Envoy Agent Router en tant que serveur d'extension, pour accepter les ressources InferencePool en tant que backends et pour utiliser le service de limitation du débit basé sur Redis.
Créez le fichier de valeurs Helm pour l'intégration :
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 EOFMettez à niveau Envoy Gateway avec les deux fichiers de valeurs :
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}"Créez le fichier manifeste pour le
ClusterRolequi permet au contrôleur Envoy Gateway de surveiller les ressourcesInferencePool. Le graphique n'accorde pas cette autorisation. UnClusterRoleBindingdistinct survit aux mises à niveau du graphique, contrairement à un correctif duClusterRolegéré par le graphique :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} EOFAppliquez le fichier manifeste pour
ClusterRole:kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"Redémarrez le contrôleur Envoy Gateway pour qu'il prenne en compte la nouvelle configuration et les nouvelles autorisations, puis attendez qu'il soit disponible :
kubectl rollout restart deployment/envoy-gateway \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" kubectl rollout status deployment/envoy-gateway \ --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \ --timeout=5mVérifiez que le service de limitation du débit a été déployé et qu'il 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'"
Validation
La validation déploie l'exemple de base du routeur de l'agent Envoy (un amont fictif compatible avec OpenAI derrière un AIGatewayRoute) dans l'espace de noms du routeur de l'agent Envoy, puis le supprime.
Créez le fichier manifeste pour la charge de travail de validation :
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 EOFAppliquez le fichier manifeste pour la charge de travail de validation :
kubectl apply \ --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \ --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"Attendez que le
Gatewaysoit programmé :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'"Attendez que le service en amont fictif
Deploymentsoit 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'"Vérifiez que le
Poddu proxy Envoy deGatewayexécute le side-car du processeur externe injecté par Envoy Agent Router :kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \ --selector="gateway.envoyproxy.io/owning-gateway-name=aieg-basic" \ --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].name}{"\n"}{end}'Le résultat ressemble à ce qui suit :
envoy-envoy-ai-gateway-system-aieg-basic-... envoy shutdown-manager ai-gateway-extprocEnvoyez une requête de complétion de chat via la passerelle à l'aide du transfert de port. Le processeur externe lit le champ
modeldu corps de la requête et l'achemine vers l'amont fictif :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}Le résultat ressemble à ce qui suit :
{ "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { ... } }Supprimez la charge de travail de validation :
kubectl delete \ --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \ --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
Opérations
Tâches du deuxième jour pour les plans de contrôle de la passerelle.
Mettre à niveau
- Amorcez les images et les charts des nouvelles versions (mettez à jour les variables de version dans
env.sh, réexécutezseed_registry.shetseed_charts.sh), appliquez les nouveaux charts CRD aveckubectl apply --server-side, puis exécutez les mêmes commandeshelm upgrade --installavec le nouveau--version. Consultez la matrice de compatibilité d'Envoy Agent Router pour connaître les versions d'Envoy Gateway et de l'API Gateway compatibles avec la version cible. Envoy Agent Router 1.1.0 est conçu pour Envoy Gateway 1.8.
Désinstaller
- Supprimez d'abord les ressources
Gateway,AIGatewayRouteetInferencePooldes guides de l'utilisateur, puishelm uninstall aieg --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}",helm uninstall eg --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}",ClusterRoleenvoy-gateway-inferencepool-reader,GatewayClass,DeploymentRedis et enfin les CRD.
Dépannage
| Problème constaté | Cause probable | Action |
|---|---|---|
Échec de helm show chart ou helm upgrade avec unauthorized ou FetchReference |
helm ne dispose pas d'identifiants pour Harbor (il n'utilise pas la configuration Docker crane). |
Exécutez à nouveau l'étape helm registry login avec le compte robot d'extraction d'images Kubernetes. |
Les routeurs Envoy Gateway ou Envoy Agent Pod restent dans l'état ImagePullBackOff. |
L'image n'est pas amorcée ou le secret d'extraction d'image est manquant dans l'espace de noms | Vérifiez kubectl describe pod, comparez le chemin d'accès à l'image avec crane ls "${GDCS_HARBOR_PROJECT_URI}/envoyproxy/gateway", et vérifiez que le secret existe dans ${GDCS_ENVOY_GATEWAY_NAMESPACE} et ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}. |
Gateway reste Programmed=False après l'intégration |
Le contrôleur Envoy Gateway ne peut pas joindre le serveur d'extension ou n'a pas été redémarré après la mise à niveau. | kubectl logs deployment/envoy-gateway --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" ; vérifiez que service/ai-gateway-controller existe dans ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} et que le port 1063 est listé ; répétez le redémarrage du déploiement. |
AIGatewayRoute faisant référence à un InferencePool n'est pas accepté |
Envoy Gateway ne dispose pas de l'autorisation de lire inferencepools, ou les CRD InferencePool sont manquants |
Vérifiez les CRD ClusterRoleBinding envoy-gateway-inferencepool-reader et inferencepools.inference.networking.k8s.io, puis consultez les journaux du contrôleur pour forbidden. |
La requête de complétion de chat renvoie 413 ou la connexion est réinitialisée pour les requêtes volumineuses |
La limite de tampon Envoy par défaut (32 Kio) est trop faible pour les charges utiles d'IA | Associez un ClientTrafficPolicy avec connection.bufferLimit (la validation utilise 50 Mio) au Gateway. |
Le service de limitation du débit Pod est CrashLoopBackOff |
Redis n'est pas accessible à l'URL configurée | kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}" ; corrigez rateLimit.backend.redis.url dans le fichier de valeurs d'intégration et effectuez à nouveau la mise à niveau. |
Autres ressources
- Documentation sur Envoy Agent Router
- Notes de version et matrice de compatibilité du routeur de l'agent Envoy
- Documentation Envoy Gateway
- API Kubernetes Gateway
- Extension d'inférence de l'API Gateway
- Créer un cluster standard | Google Distributed Cloud sous air gap
Créer des projets Harbor | Google Distributed Cloud sous air gap
Routage basé sur le corps avec le guide de l'utilisateur d'Envoy Agent Router