Implémentation de référence d'AI Gateway avec Envoy Agent Router sur GDC sous air gap

Ce document fournit des instructions détaillées pour déployer une passerelle AI Gateway dans des environnements Google Distributed Cloud (GDC) air-gapped. La passerelle est basée sur Envoy Gateway, l'implémentation de l'API Kubernetes Gateway basée sur le proxy Envoy, et Envoy Agent Router (anciennement Envoy AI Gateway), l'extension qui transforme Envoy Gateway en 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 conteneur et les graphiques Helm dans le registre Harbor local, comment installer les deux plans de contrôle sur un cluster standard, comment préparer le backend facultatif de limitation du débit basée sur les jetons et comment valider l'installation avec des exemples de charges de travail.

Les backends de mise en service du modèle (Ollama, vLLM) sont déployés avec l'ensemble de guides associés Modèles Open Weight sur GDC sous air gap. Le Guide de l'utilisateur sur le routage basé sur le corps avec Envoy Agent Router montre comment acheminer les requêtes vers eux par nom de modèle.

Architecture

La solution s'exécute dans un cluster GDC standard. Une station de travail administrateur amorce les images et les graphiques Helm dans le registre Harbor du projet, et 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 les jetons.

Architecture de référence AI Gateway avec Envoy Agent Router sur GDC sous air gap.

Envoy Gateway

Envoy Gateway est un projet Open Source basé sur Envoy Proxy. Il simplifie l'adoption, l'utilisation et la gestion d'Envoy Proxy en tant que passerelle d'API Kubernetes. Elle 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 route telles que HTTPRoute décrivent comment le trafic est mis en correspondance et transféré, et la conception orientée rôle 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 mémoire tampon).

Routeur d'agent Envoy

Envoy Agent Router (anciennement Envoy AI Gateway) est un projet Open Source qui utilise Envoy Gateway pour gérer le trafic de requêtes des clients d'applications 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 adapté aux modèles, une authentification en amont, une limitation du débit basée sur les jetons et l'observabilité. Il s'intègre à l'extension Gateway API Inference (InferencePool, sélecteur de points de terminaison) 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 saisie semi-automatique de chat OpenAI), définit les en-têtes de routage tels que x-ai-eg-model et effectue la traduction entre les schémas d'API si nécessaire.

Avant de commencer

Avant de procéder au déploiement, assurez-vous que votre environnement répond à toutes les conditions préalables nécessaires et que les utilitaires de ligne de commande requis sont correctement configurés. Il est essentiel de configurer ces outils sur votre station de travail 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 exécutant Kubernetes v1.32.13-gke.400 ou version ultérieure.
  • Cluster standard créé avec des ressources suffisantes. 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 en matière d'accélérateur (consultez les guides Modèles Open Weight sur GDC sous air gap).
  • L'instance Harbor est disponible et accessible.
  • Autorisations IAM nécessaires appliquées.
  • Un 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 Utilisateur GDC sur le projet (RoleBinding dans l'espace de noms du projet, accordés par un administrateur IAM de projet) :

  • 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 pour gdcloud 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 de projet doit également associer l'utilisateur à StandardClusterRole cluster-admin avec un StandardClusterRoleBinding dans l'espace de noms du projet sur le serveur de l'API Management. L'association est propagée aux clusters standards du projet en quelques secondes (status.clusters[].conditions affiche Propagated=True). Des autorisations à l'échelle 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 crane (crane) Harbor :

  • Lister le dépôt
  • Extraire le dépôt
  • Dépôt Push
  • Lire un artefact
  • Lister les artefacts
  • Créer un tag
  • Balise de liste

Autorisations du compte robot Harbor Kubernetes image pull (kubernetes-image-puller) :

  • Lister le dépôt
  • Extraire le dépôt
  • Lire un artefact
  • Lister les artefacts
  • Balise de liste

Station de travail

Ce guide nécessite un poste de travail disposant de la connectivité nécessaire à l'environnement et à Internet.

Conditions requises

Les outils suivants doivent être installés sur le poste de travail :

  • crane : gérez et copiez les images de conteneurs et les artefacts OCI entre les registres (documentation).
  • gdcloud : interface de ligne de commande (CLI) pour 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 en 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 pour 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 robot Harbor crane.

  • GDCS_HARBOR_CRANE_ROBOT_TOKEN : jeton d'authentification pour le compte robot Harborcrane.

  • GDCS_HARBOR_K8S_ROBOT_NAME : nom du compte robot Harbor Kubernetes pour l'extraction d'images.

  • GDCS_HARBOR_K8S_ROBOT_TOKEN : jeton d'authentification pour le compte robot Harbor Kubernetes Image Pull.

Une fois que vous avez collecté les valeurs de toutes les variables requises, passez à la génération du fichier de variables d'environnement. Une fois le fichier créé, vous pouvez le modifier manuellement à tout moment.

  1. Créez les répertoires de 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/*
    
  2. Créez le fichier de configuration de l'environnement de 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}"
    EOF
    

    Remplacez les éléments suivants :

    • STANDARD_CLUSTER_NAME : nom de cluster standard GDC.
    • DOMAIN_SUFFIX : suffixe du domaine GDC.
    • ORG : organisation GDC.
    • PROJECT : projet GDC.
    • ZONE : zone GDC.
    • HARBOR_INSTANCE_NAME : nom de l'instance GDC Harbor.
  3. 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}"
    EOF
    

    Remplacez les éléments suivants :

    • HARBOR_CRANE_ROBOT_NAME : nom du compte robot GDC Harbor.
    • HARBOR_K8S_ROBOT_NAME : nom du compte robot GDC Harbor.
  4. Ajoutez vos jetons aux fichiers 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 history
    

    Remplacez les éléments suivants :

    • CRANE_ROBOT_TOKEN : jeton de robot de grue.
    • KUBERNETES_ROBOT_TOKEN : jeton de robot Kubernetes.
  5. Créez le fichier du chargeur d'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

  1. Créez le répertoire d'implémentation de la solution :

    mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d
    
  2. Créez le fichier de configuration de l'environnement de 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"
    EOF
    
  3. Créez le fichier du chargeur d'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"
    EOF
    
  4. Modifiez et examinez les fichiers d'environnement avec votre éditeur préféré :

    ${EDITOR:-vi} ${HOME}/gdcag-solutions/env.d/platform.sh
    ${EDITOR:-vi} ${HOME}/gdcag-solutions/env.d/registry.sh
    ${EDITOR:-vi} ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d/envoy.sh
    
  5. Sourcez le fichier d'environnement :

    source ${HOME}/gdcag-solutions/ai-gateway/envoy/env.sh
    

    Le 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 station de travail est configurée pour faire confiance aux certificats TLS de votre environnement GDC et de votre instance Harbor.

  1. 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}"
    
  2. Authentifiez-vous auprès de l'environnement GDC :

    gdcloud auth login
    

Cluster

  1. Récupérez les identifiants du cluster :

    gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \
    --project="${GDC_PROJECT}" \
    --standard \
    --zone="${GDC_ZONE}"
    
  2. Vérifiez la connectivité au cluster :

    kubectl get nodes -L node.cluster.private.gdc.goog/machine-class
    
  3. Vérifiez que chaque nœud exécute la version de Kubernetes requise dans la section Avant de commencer de ce guide :

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

Préparation de la migration des artefacts

  1. Créez un fichier de configuration Docker pour Crane. Un compte robot est utilisé pour envoyer des calques d'image volumineux afin d'éviter les délais d'expiration des jetons d'authentification lorsque vous utilisez le programme d'assistance pour les identifiants 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 history
    
  2. Cré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 history
    
  3. Connectez-vous au registre Harbor OCI avec helm à l'aide du compte robot de récupération d'image Kubernetes. helm conserve ses propres identifiants de registre et en a besoin pour extraire les graphiques 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 history
    

    Le résultat ressemble à ce qui suit :

    Login Succeeded
    
  4. Cré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"
    
  5. Créez le script seed_charts.sh. Les charts Helm publiés en tant qu'artefacts OCI sont également copiés avec crane, sans sélection de plate-forme et sans le tag create utilisé pour les dépôts d'images de conteneur :

    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 : repository.
    • CHART_VERSION : version du graphique.
  6. 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)
    
  7. Transférez les images de conteneurs requises vers Artifact Registry :

    ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
    
  1. 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)
    
  2. Ajoutez les charts Helm requis au registre d'artefacts :

    ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh
    
  3. Vérifiez que les graphiques peuvent être relus à 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.0
    
  4. Téléchargez les fichiers manifestes de l'extension d'inférence de l'API Gateway. Ils sont publiés en tant qu'éléments de version, et non en tant que graphiques :

    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 installé en premier et validé seul avec le guide de démarrage rapide en amont. L'intégration d'Envoy Agent Router suit dans la section suivante.

Espace de noms

  1. Créez l'espace de noms pour Envoy Gateway. Les Deployment de proxy Envoy de chaque Gateway sont également créés dans cet espace de noms :

    kubectl create namespace "${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  2. 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

  1. Installez l'API Gateway (canal standard) et les définitions de ressources personnalisées (CRD) Envoy Gateway à partir du graphique initialisé :

    helm template eg-crds "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/gateway-crds-helm" \
    --set crds.gatewayAPI.channel=standard \
    --set crds.gatewayAPI.enabled=true \
    --set crds.envoyGateway.enabled=true \
    --version "${GDCS_ENVOY_GATEWAY_VERSION}" | kubectl apply --server-side --filename=-
    
  2. Vérifiez que les CRD sont enregistrées :

    kubectl get crd | grep -E 'gateway.networking.k8s.io|gateway.envoyproxy.io'
    

Contrôleur

  1. 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}
    EOF
    
  2. Installez Envoy Gateway :

    helm upgrade --install eg "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/gateway-helm" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --values="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-values.yaml" \
    --version="${GDCS_ENVOY_GATEWAY_VERSION}"
    
  3. 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'"
    
  4. 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 de passerelle

  1. Créez le fichier manifeste pour le modèle de plan de données EnvoyProxy et GatewayClass. EnvoyProxy définit l'image de proxy, le secret d'extraction d'image et les demandes de ressources des Pod de proxy. GatewayClass est 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}
    EOF
    
  2. Appliquez le fichier manifeste pour EnvoyProxy et GatewayClass :

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"
    
  3. Vérifiez que la GatewayClass est 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 Envoy Gateway (un backend d'écho derrière un HTTPRoute) dans l'espace de noms Envoy Gateway, puis le supprime.

  1. 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: /
    EOF
    
  2. Appliquez 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}"
    
  3. Attendez que Gateway soit 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'"
    
  4. Attendez que le backend Deployment soit 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'"
    
  5. Envoyez une requête de test via la passerelle à l'aide du transfert de port. L'Envoy Service d'un Gateway est identifié par les libellés de sa 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-...",
      ...
    }
    
  6. 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 d'agent Envoy

Le routeur Envoy Agent 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

  1. Créez l'espace de noms pour le contrôleur Envoy Agent Router :

    kubectl create namespace "${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  2. 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

  1. Installez les CRD du routeur Envoy Agent à partir du graphique initialisé :

    helm template aieg-crds "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/ai-gateway-crds-helm" \
    --version "${GDCS_ENVOY_AGENT_ROUTER_VERSION}" | kubectl apply --server-side --filename=-
    
  2. 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"
    
  3. 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 un service Redis à réplique unique sans persistance. Vous pouvez utiliser un service Redis existant à la place en modifiant la valeur rateLimit.backend.redis.url dans la section suivante.

  1. Créez le fichier manifeste pour le Deployment 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
    EOF
    
  2. Appliquez le fichier manifeste pour le Deployment Redis :

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \
    --namespace="${GDCS_REDIS_NAMESPACE}"
    
  3. Attendez que le Deployment Redis soit 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

  1. Créez le fichier de valeurs Helm pour 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}
    EOF
    
  2. Installez le routeur Envoy Agent :

    helm upgrade --install aieg "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/ai-gateway-helm" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}" \
    --values="${GDCS_IMPLEMENTATION_HOME}/envoy-agent-router-values.yaml" \
    --version="${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
    
  3. Attendez que le contrôleur Envoy Agent Router 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.

  1. 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
    EOF
    
  2. Mettez à 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}"
    
  3. Créez le fichier manifeste pour le ClusterRole qui permet au contrôleur Envoy Gateway de surveiller les ressources InferencePool. Le graphique n'accorde pas cette autorisation. Un élément ClusterRoleBinding distinct survit aux mises à niveau du graphique, contrairement à un correctif de l'élément ClusterRole gé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}
    EOF
    
  4. Appliquez le fichier manifeste pour ClusterRole :

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"
    
  5. 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=5m
    
  6. Vé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 Envoy Agent Router (un backend compatible avec OpenAI simulé derrière un AIGatewayRoute) dans l'espace de noms Envoy Agent Router, puis le supprime.

  1. 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
    EOF
    
  2. Appliquez 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}"
    
  3. Attendez que Gateway soit 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'"
    
  4. Attendez que le mock en amont Deployment soit 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'"
    
  5. Vérifiez que le proxy Envoy Pod de Gateway exé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-extproc
    
  6. Envoyez une requête de complétion de conversation via la passerelle à l'aide du transfert de port. Le processeur externe lit le champ model du corps de la requête et l'achemine vers le mock en amont :

    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": {
        ...
      }
    }
    
  7. 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

  • Insérez les images et les graphiques des nouvelles versions (mettez à jour les variables de version dans env.sh, réexécutez seed_registry.sh et seed_charts.sh), appliquez les nouveaux graphiques CRD avec kubectl apply --server-side, puis exécutez les mêmes commandes helm upgrade --install avec le nouveau --version. Consultez la matrice de compatibilité de l'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, AIGatewayRoute et InferencePool des guides de l'utilisateur, puis helm uninstall aieg --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}", helm uninstall eg --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}", ClusterRole envoy-gateway-inferencepool-reader, GatewayClass, Deployment Redis et enfin les CRD.

Dépannage

Problème constaté Cause probable Action
helm show chart ou helm upgrade échoue avec unauthorized ou FetchReference helm n'a 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 Kubernetes pour l'extraction d'images.
Les passerelles Envoy ou les routeurs d'agent Envoy Pod restent dans l'état ImagePullBackOff. L'image n'est pas initialisée ou le secret d'extraction de l'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", puis 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 parvient pas à accéder au 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é La passerelle Envoy ne dispose pas de l'autorisation de lire inferencepools, ou les CRD InferencePool sont manquants. Vérifiez le ClusterRoleBinding envoy-gateway-inferencepool-reader et le CRD inferencepools.inference.networking.k8s.io. Consultez les journaux du contrôleur pour forbidden.
La requête de saisie semi-automatique de chat renvoie 413 ou la connexion est réinitialisée pour les requêtes volumineuses La limite de mémoire tampon Envoy par défaut (32 Kio) est trop petite pour les charges utiles d'IA. Associez un ClientTrafficPolicy avec connection.bufferLimit (la validation utilise 50 Mi) 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, puis effectuez à nouveau la mise à niveau.

Autres ressources