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 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.

Architecture de référence de la passerelle d'IA avec le routeur d'agent Envoy sur GDC sous air gap.

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 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 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 Harbor crane.

  • GDCS_HARBOR_CRANE_ROBOT_TOKEN : jeton d'authentification du compte de robot Harbor crane.

  • 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.

  1. 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/*
    
  2. 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}"
    EOF
    

    Remplacez 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.
  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 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 history
    

    Remplacez les éléments suivants :

    • CRANE_ROBOT_TOKEN : jeton du robot Crane.
    • KUBERNETES_ROBOT_TOKEN : jeton de robot Kubernetes.
  5. 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

  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 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"
    EOF
    
  3. Cré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"
    EOF
    
  4. Modifiez 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.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 poste de travail est configuré 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
    

Préparation de la migration des artefacts

  1. 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 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 OCI Harbor avec helm à l'aide du compte robot d'extraction d'images Kubernetes. helm conserve 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 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 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.
  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. Amorcez les images de conteneurs requises dans 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. Transférez les charts Helm requis vers Artifact Registry :

    ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh
    
  3. Vé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.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é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

  1. Créez l'espace de noms pour Envoy Gateway. Les Deployment du 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 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=-
    
  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 Gateway

  1. Créez le fichier manifeste pour le modèle de plan de données EnvoyProxy et le GatewayClass. EnvoyProxy définit l'image du proxy, le secret d'extraction d'image et les requêtes de ressources des Pods du 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 d'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 le 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. Le Service Envoy d'un Gateway est 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-...",
      ...
    }
    
  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 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

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

    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 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=-
    
  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 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.

  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 l'instance Redis Deployment 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 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}
    EOF
    
  2. Installez 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}"
    
  3. 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.

  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 ClusterRoleBinding distinct survit aux mises à niveau du graphique, contrairement à un correctif du 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 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.

  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 le 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 service en amont fictif 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 Pod du proxy Envoy 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 chat 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 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": {
        ...
      }
    }
    
  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

  • Amorcez les images et les charts 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 charts 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é 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, 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
É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