Implementazione di riferimento di AI Gateway con Envoy Agent Router su GDC con air gap

Questo documento fornisce istruzioni passo passo per il deployment di un gateway AI negli ambienti air gap di Google Distributed Cloud (GDC). Il gateway è basato su Envoy Gateway, l'implementazione dell'API Gateway di Kubernetes basata sul proxy Envoy, e Envoy Agent Router (in precedenza Envoy AI Gateway), l'estensione che trasforma Envoy Gateway in un punto di ingresso unificato e compatibile con OpenAI per il traffico dei modelli linguistici di grandi dimensioni (LLM). Vengono trattati argomenti come l'inserimento delle immagini container e dei grafici Helm nel registro Harbor locale, l'installazione di entrambi i control plane su un cluster standard, la preparazione del backenlimitazione di frequenzaza basata su token facoltativo e la convalida dell'installazione con carichi di lavoro di esempio.

I backend di erogazione del modello (Ollama, vLLM) vengono implementati con il set di guide complementari Modelli open weight su GDC con air gap; la Guida per l'utente del router dell'agente Envoy per il routing basato sul corpo mostra come instradare le richieste in base al nome del modello.

Architettura

La soluzione viene eseguita in un cluster GDC standard. Una workstation amministratore inserisce le immagini e i grafici Helm nel registro Harbor del progetto e installa i due control plane: il controller Envoy Gateway, che programma il data plane del proxy Envoy dalle risorse dell'API Gateway (GatewayClass, Gateway, HTTPRoute) e il controller Envoy Agent Router, che estende il data plane con un processore esterno (ExtProc) per il traffico AI (AIGatewayRoute, AIServiceBackend, InferencePool). I client dell'applicazione inviano richieste compatibili con OpenAI al proxy Envoy, che le indirizza ai backend di erogazione del modello o ai InferencePool. Un'istanza Redis facoltativa memorizza i contatori del servizio di limitazione della frequenza di Envoy per la limitazione della frequenza basata su token.

Architettura di riferimento del router dell'agente Envoy con AI Gateway su GDC con air gap.

Envoy Gateway

Envoy Gateway è un progetto open source, basato sul proxy Envoy, che semplifica l'adozione, l'utilizzo e la gestione del proxy Envoy come gateway API Kubernetes. Implementa ed estende l'API Gateway di Kubernetes, il successore dell'API Ingress: le risorse GatewayClass e Gateway descrivono i punti di ingresso, le risorse di route come HTTPRoute descrivono come il traffico viene abbinato e inoltrato e la progettazione orientata ai ruoli separa le responsabilità dei team dell'infrastruttura e delle applicazioni. Envoy Gateway aggiunge le proprie API di estensione, ad esempio EnvoyProxy (impostazioni del data plane), Backend (endpoint esterni al cluster o a cui viene fatto riferimento tramite FQDN) e ClientTrafficPolicy (impostazioni di connessione come i limiti del buffer).

Router agente Envoy

Envoy Agent Router (in precedenza Envoy AI Gateway) è un progetto open source che utilizza Envoy Gateway per gestire il traffico delle richieste dai client delle applicazioni ai servizi di AI generativa. Fornisce un livello unificato per il routing e la gestione del traffico LLM con routing basato sul modello, autenticazione upstream,limitazione di frequenzaza basata su token e osservabilità e si integra con l'estensione Gateway API Inference(InferencePool, Endpoint Picker) per la selezione degli endpoint basata sulle metriche. Il controller monitora le risorse aigateway.envoyproxy.io/v1beta1 e inserisce un processore esterno accanto al proxy Envoy; il processore esterno analizza il corpo della richiesta (ad esempio il campo model di una richiesta di completamento della chat OpenAI), imposta le intestazioni di routing come x-ai-eg-model e traduce tra gli schemi API, se necessario.

Prima di iniziare

Prima di procedere con il deployment, assicurati che il tuo ambiente soddisfi tutti i prerequisiti necessari e che le utilità della riga di comando richieste siano configurate correttamente. La configurazione di questi strumenti sulla workstation è essenziale per gestire i registri dei container, interagire con i cluster e automatizzare il processo di deployment.

  • L'ambiente GDC con air gap 1.16.2-hf1 o versioni successive è disponibile con un cluster standard che esegue Kubernetes v1.32.13-gke.400 o versioni successive.
  • Cluster standard creato con risorse sufficienti. I componenti del gateway vengono eseguiti solo sulla CPU; i backend di erogazione del modello hanno requisiti propri per gli acceleratori (consulta le guide Open Weight Models on GDC air-gapped).
  • L'istanza Harbor è disponibile e accessibile.
  • IAM necessario applicato.
  • Workstation con la connettività necessaria all'ambiente e a internet

Configurazione dell'ambiente

La configurazione dell'ambiente copre le identità e le autorizzazioni, la workstation e l'accesso all'ambiente GDC e al cluster.

Identity and Access Management

Assicurati che gli account, i ruoli e le autorizzazioni IAM necessari siano configurati correttamente.

Ruoli Utente GDC nel progetto (RoleBinding nello spazio dei nomi del progetto, concessi da un amministratore IAM progetto):

  • Visualizzatore istanze Harbor (harbor-instance-viewer)
  • Autore progetto Harbor (harbor-project-creator, solo se il progetto Harbor non esiste ancora)
  • Amministratore cluster standard (standard-cluster-admin, obbligatorio per gdcloud clusters get-credentials)

Ruolo Utente GDC sul cluster standard: i ruoli di progetto precedenti non concedono autorizzazioni all'interno del cluster. Un amministratore IAM del progetto deve inoltre associare l'utente a StandardClusterRole cluster-admin con un StandardClusterRoleBinding nello spazio dei nomi del progetto sul server API di gestione; l'associazione viene propagata ai cluster standard del progetto in pochi secondi (status.clusters[].conditions mostra Propagated=True). Sono necessarie autorizzazioni a livello di cluster perché questa guida installa definizioni di risorse personalizzate, ClusterRole e 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

Sostituisci quanto segue:

  • MANAGEMENT_API_SERVER: il percorso del file kubeconfig del server API di gestione.
  • USER: utente.
  • PROJECT: progetto.

Autorizzazioni dell'account robot Harbor crane (crane):

  • Elenca repository
  • Pull Repository
  • Repository push
  • Leggi artefatto
  • Elenca artefatto
  • Crea tag
  • Tag elenco

Account robot Harbor Kubernetes image pull (kubernetes-image-puller) permessi:

  • Elenca repository
  • Pull Repository
  • Leggi artefatto
  • Elenca artefatto
  • Tag elenco

Workstation

Questa guida richiede una workstation con la connettività necessaria all'ambiente e a internet.

Requisiti

Sulla workstation devono essere installati i seguenti strumenti:

  • crane: gestisci e copia immagini container e artefatti OCI tra i registri (documentazione).
  • gdcloud: interfaccia a riga di comando (CLI) per la gestione delle risorse GDC (documentazione).
  • kubectl: interfaccia a riga di comando (CLI) utilizzata per comunicare con un cluster Kubernetes e gestirlo.
  • helm: package manager per Kubernetes, versione 3.8 o successive (supporto del registro OCI) (documentazione).
  • curl: strumento a riga di comando per il trasferimento di dati con URL.
  • jq: processore JSON da riga di comando leggero e flessibile.
  • yq: processore YAML portatile da riga di comando.

Esegui tutti i comandi di questa guida dalla workstation, a meno che un passaggio non indichi diversamente.

Configurazione workstation

Per la configurazione della workstation sono necessarie le seguenti informazioni sull'ambiente:

  • GDC_STANDARD_CLUSTER_NAME: il nome del cluster standard GDC.
  • GDC_DOMAIN_SUFFIX: il suffisso di dominio per l'ambiente GDC (ad esempio gdc.example.com).
  • GDC_ORG: il nome dell'organizzazione GDC.
  • GDC_PROJECT: il nome del progetto GDC.
  • GDC_ZONE: il nome della zona di deployment di GDC.
  • GDC_HARBOR_INSTANCE_NAME: il nome dell'istanza Harbor nel progetto.

  • GDCS_HARBOR_PROJECT_NAME: il nome del progetto Harbor da utilizzare per l'immagine (impostazione predefinita: solutions)

  • GDCS_HARBOR_CRANE_ROBOT_NAME: il nome dell'account di servizio robot crane di Harbor.

  • GDCS_HARBOR_CRANE_ROBOT_TOKEN: il token di autenticazione per l'account robot Harbor crane.

  • GDCS_HARBOR_K8S_ROBOT_NAME: il nome del service account robot di pull dell'immagine Kubernetes di Harbor.

  • GDCS_HARBOR_K8S_ROBOT_TOKEN: il token di autenticazione per l'account di servizio di pull delle immagini Kubernetes di Harbor.

Una volta raccolti i valori di tutte le variabili richieste, procedi con la generazione del file delle variabili di ambiente. Una volta creato, puoi modificare manualmente il file in qualsiasi momento.

  1. Crea le directory della soluzione radice e la cartella dei segreti:

    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. Crea il file di configurazione dell'ambiente della piattaforma:

    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
    

    Sostituisci quanto segue:

    • STANDARD_CLUSTER_NAME: Nome del cluster standard GDC.
    • DOMAIN_SUFFIX: suffisso del dominio GDC.
    • ORG: Organizzazione GDC.
    • PROJECT: Progetto GDC.
    • ZONE: zona GDC.
    • HARBOR_INSTANCE_NAME: Il nome dell'istanza GDC Harbor.
  3. Crea il file di configurazione dell'ambiente del registro:

    cat << 'EOF' > ${HOME}/gdcag-solutions/env.d/registry.sh && echo "Successfully created." || echo "Failed to create!"
    # GDC Solutions Registry & Secrets
    export GDCS_HARBOR_PROJECT_NAME="solutions"
    export GDCS_HARBOR_CRANE_ROBOT_NAME="HARBOR_CRANE_ROBOT_NAME"
    export GDCS_HARBOR_CRANE_ROBOT_TOKEN="$(cat ${GDCS_ROOT_HOME}/secrets/harbor_crane_robot_token)"
    export GDCS_HARBOR_K8S_ROBOT_NAME="HARBOR_K8S_ROBOT_NAME"
    export GDCS_HARBOR_K8S_ROBOT_TOKEN="$(cat ${GDCS_ROOT_HOME}/secrets/harbor_k8s_robot_token)"
    export GDCS_HARBOR_K8S_PULL_SECRET="gdcs-image-pull-secret"
    
    # Derived registry values
    export GDCS_HARBOR_PROJECT_URI="${GDC_HARBOR_HOST}/${GDCS_HARBOR_PROJECT_NAME}"
    export GDCS_HARBOR_CHART_OCI_URI="oci://${GDCS_HARBOR_PROJECT_URI}"
    EOF
    

    Sostituisci quanto segue:

    • HARBOR_CRANE_ROBOT_NAME: Nome dell'account robot GDC Harbor.
    • HARBOR_K8S_ROBOT_NAME: Nome dell'account robot GDC Harbor.
  4. Aggiungi i token ai file dei secret:

    set +o history
    
    echo "CRANE_ROBOT_TOKEN" > ${HOME}/gdcag-solutions/secrets/harbor_crane_robot_token
    echo "KUBERNETES_ROBOT_TOKEN" > ${HOME}/gdcag-solutions/secrets/harbor_k8s_robot_token
    
    set -o history
    

    Sostituisci quanto segue:

    • CRANE_ROBOT_TOKEN: token del robot gru.
    • KUBERNETES_ROBOT_TOKEN: token robot Kubernetes.
  5. Crea il file di caricamento dell'ambiente principale:

    cat << 'EOF' > ${HOME}/gdcag-solutions/env.sh && echo "Successfully created." || echo "Failed to create!"
    export GDCS_ROOT_HOME="${HOME}/gdcag-solutions"
    echo "GDCS_ROOT_HOME=${GDCS_ROOT_HOME}"
    
    # Sourced in dependency order
    source "${GDCS_ROOT_HOME}/env.d/platform.sh"
    source "${GDCS_ROOT_HOME}/env.d/registry.sh"
    EOF
    

Configura le variabili della soluzione

  1. Crea la directory di implementazione della soluzione:

    mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d
    
  2. Crea il file di configurazione dell'ambiente della soluzione:

    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. Crea il file di caricamento dell'ambiente di implementazione:

    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. Modifica e rivedi i file di ambiente con il tuo editor preferito:

    ${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. Recupera il file di ambiente:

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

    L'output è simile al seguente:

    GDCS_ROOT_HOME=HOME_DIRECTORY_PATH/gdcag-solutions
    GDCS_IMPLEMENTATION_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/ai-gateway/envoy
    

GDC

Questa guida presuppone che la workstation sia configurata per considerare attendibili i certificati TLS per l'ambiente GDC e l'istanza Harbor.

  1. Configura gdcloud:

    gdcloud config set core/account "default-user"
    gdcloud config set core/organization_console_url "${GDC_ZONAL_CONSOLE_URL}"
    gdcloud config set core/project "${GDC_PROJECT}"
    gdcloud config set core/zone "${GDC_ZONE}"
    
  2. Esegui l'autenticazione nell'ambiente GDC:

    gdcloud auth login
    

Cluster

  1. Recupera le credenziali del cluster:

    gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \
    --project="${GDC_PROJECT}" \
    --standard \
    --zone="${GDC_ZONE}"
    
  2. Verifica la connettività al cluster:

    kubectl get nodes -L node.cluster.private.gdc.goog/machine-class
    
  3. Verifica che ogni nodo esegua la versione di Kubernetes richiesta dalla sezione Prima di iniziare di questa guida:

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

Preparazione della migrazione degli artefatti

  1. Crea un file di configurazione Docker per crane. Un account robot viene utilizzato per trasferire livelli di immagini di grandi dimensioni per evitare timeout dei token di autenticazione quando si utilizza l'helper delle credenziali Managed Harbor Service (MHS) (docker-credential-mhs) con un account utente:

    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. Crea un file di configurazione Docker per 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. Accedi al registro Harbor OCI con helm utilizzando l'account robot pull di immagini Kubernetes. helm conserva le proprie credenziali del registro e le utilizza per recuperare i grafici da 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
    

    L'output è simile al seguente:

    Login Succeeded
    
  4. Crea lo 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. Crea lo script seed_charts.sh. Anche i grafici Helm pubblicati come artefatti OCI vengono copiati con crane, senza selezione della piattaforma e senza il tag create utilizzato per i repository di immagini container:

    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"
    

    Sostituisci quanto segue:

    • REGISTRY_HOST: host del registro.
    • REPOSITORY: repository.
    • CHART_VERSION: versione del grafico.
  6. Definisci l'elenco delle immagini container richieste per la soluzione:

    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. Inserisci le immagini container richieste in Artifact Registry:

    ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
    
  1. Definisci l'elenco dei grafici Helm richiesti per la soluzione:

    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. Inserisci i grafici Helm richiesti nel registro degli artefatti:

    ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh
    
  3. Verifica che i grafici possano essere letti da 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):'
    

    L'output è simile al seguente:

    name: gateway-helm
    version: v1.8.5
    name: ai-gateway-helm
    version: v1.1.0
    
  4. Scarica i manifest dell'estensione di inferenza dell'API Gateway. Vengono pubblicati come asset di rilascio, non come grafico:

    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"
    

    L'output è simile al seguente:

    4
    

Envoy Gateway

Envoy Gateway viene installato per primo e convalidato separatamente con la guida rapida upstream. L'integrazione di Envoy Agent Router viene descritta nella sezione successiva.

Spazio dei nomi

  1. Crea lo spazio dei nomi per Envoy Gateway. Anche i proxy Envoy Deployment di ogni Gateway vengono creati in questo spazio dei nomi:

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

Definizioni di risorse personalizzate

  1. Installa l'API Gateway (canale standard) e le definizioni di risorse personalizzate (CRD) di Envoy Gateway dal grafico seed:

    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. Verifica che le CRD siano registrate:

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

Controller

  1. Crea il file dei valori Helm per Envoy Gateway. Le immagini vengono estratte da Harbor con il segreto di pull delle immagini; crds.enabled=false perché le CRD sono state installate separatamente:

    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. Installa 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. Attendi che il controller Envoy Gateway sia disponibile:

    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. Verifica che le immagini del controller e il relativo job di generazione dei certificati provengano da Harbor:

    kubectl get pods --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --output=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
    

Proxy Envoy e classe gateway

  1. Crea il manifest per il modello del data plane EnvoyProxy e per GatewayClass. EnvoyProxy imposta l'immagine proxy, il segreto di pull dell'immagine e le richieste di risorse dei proxy Pod; GatewayClass è condiviso dalle guide utente:

    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. Applica il manifest per EnvoyProxy e GatewayClass:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"
    
  3. Verifica che GatewayClass sia accettato:

    kubectl get gatewayclass "${GDCS_GATEWAY_CLASS_NAME}"
    

    L'output è simile al seguente:

    NAME               CONTROLLER                                      ACCEPTED   AGE
    envoy-ai-gateway   gateway.envoyproxy.io/gatewayclass-controller   True       5s
    

Convalida

La convalida esegue il deployment della guida rapida di Envoy Gateway (un backend echo dietro un HTTPRoute) nello spazio dei nomi di Envoy Gateway e lo rimuove in seguito.

  1. Crea il manifest per il carico di lavoro di avvio rapido:

    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. Applica il manifest per il carico di lavoro di avvio rapido:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  3. Attendi che Gateway venga programmato:

    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. Attendi che il backend Deployment sia disponibile:

    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. Invia una richiesta di test tramite il gateway utilizzando il port forwarding. L'Envoy Service di un Gateway viene trovato dalle etichette del gateway proprietario:

    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}
    

    L'output è simile al seguente:

    {
      "path": "/get",
      "host": "www.example.com",
      "method": "GET",
      ...
      "namespace": "envoy-gateway-system",
      "pod": "eg-quickstart-backend-...",
      ...
    }
    
  6. Rimuovi il workload di avvio rapido:

    kubectl delete \
    --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    

Router agente Envoy

Envoy Agent Router viene installato nel proprio spazio dei nomi; Envoy Gateway viene quindi riconfigurato per chiamarlo come server di estensione.

Spazio dei nomi

  1. Crea lo spazio dei nomi per il controller del router dell'agente Envoy:

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

Definizioni di risorse personalizzate

  1. Installa le CRD del router agente Envoy dal grafico iniziale:

    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. Installa i CRD dell'estensione di inferenza dell'API Gateway (InferencePool, InferenceObjective) dai manifest scaricati:

    kubectl apply --server-side \
    --filename="${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml"
    
  3. Verifica che le CRD siano registrate:

    kubectl get crd | grep -E 'aigateway.envoyproxy.io|inference.networking'
    

    L'output è simile al seguente:

    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 limitazione di frequenza basata sui token viene applicata dal servizio di limitazione di frequenza Envoy, che archivia i contatori in Redis. Questa guida esegue il deployment di una singola replica Redis senza persistenza. In alternativa, è possibile utilizzare un servizio Redis esistente modificando il valore di rateLimit.backend.redis.url nella sezione successiva.

  1. Crea il manifest per Redis Deployment:

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/redis.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: v1
    kind: Service
    metadata:
      name: redis
      labels:
        app: redis
    spec:
      ports:
        - name: redis
          port: 6379
      selector:
        app: redis
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: redis
      template:
        metadata:
          labels:
            app: redis
        spec:
          containers:
            - image: ${GDCS_HARBOR_PROJECT_URI}/library/redis:${GDCS_REDIS_IMAGE_TAG}
              imagePullPolicy: IfNotPresent
              name: redis
              ports:
                - name: redis
                  containerPort: 6379
              resources:
                limits:
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 128Mi
          imagePullSecrets:
            - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
          restartPolicy: Always
    EOF
    
  2. Applica il manifest per Redis Deployment:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \
    --namespace="${GDCS_REDIS_NAMESPACE}"
    
  3. Attendi che Redis Deployment sia disponibile:

    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'"
    

Controller

  1. Crea il file dei valori Helm per 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. Installa Envoy Agent Router:

    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. Attendi che il controller Envoy Agent Router sia disponibile:

    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'"
    

Integrazione di Envoy Gateway

Envoy Gateway deve essere riconfigurato per chiamare il controller Envoy Agent Router come server di estensione, per accettare le risorse InferencePool come backend e per utilizzare il servizio di limitazione della frequenza basato su Redis.

  1. Crea il file dei valori di Helm per l'integrazione:

    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. Esegui l'upgrade di Envoy Gateway con entrambi i file di valori:

    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. Crea il manifest per ClusterRole che consente al controller Envoy Gateway di monitorare le risorse InferencePool. Il grafico non concede questa autorizzazione; un ClusterRoleBinding separato sopravvive agli upgrade del grafico, a differenza di una patch del ClusterRole gestito dal grafico:

    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. Applica il manifest per ClusterRole:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"
    
  5. Riavvia il controller Envoy Gateway in modo che applichi la nuova configurazione e le nuove autorizzazioni e attendi che lo stato sia Disponibile:

    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. Verifica che il servizio di limite di frequenza sia stato implementato e sia disponibile:

    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'"
    

Convalida

La convalida esegue il deployment dell'esempio di base di Envoy Agent Router (un upstream compatibile con OpenAI simulato dietro un AIGatewayRoute) nello spazio dei nomi di Envoy Agent Router e lo rimuove in seguito.

  1. Crea il manifest per il workload di convalida:

    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. Applica il manifest per il workload di convalida:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  3. Attendi che Gateway venga programmato:

    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. Attendi che il mock upstream Deployment sia disponibile:

    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. Verifica che il proxy Envoy Pod di Gateway esegua il sidecar del processore esterno inserito da 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}'
    

    L'output è simile al seguente:

    envoy-envoy-ai-gateway-system-aieg-basic-...   envoy shutdown-manager ai-gateway-extproc
    
  6. Invia una richiesta di completamento della chat tramite il gateway utilizzando il port forwarding. Il processore esterno legge il campo model del corpo della richiesta e lo indirizza al mock upstream:

    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}
    

    L'output è simile al seguente:

    {
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "..."
          },
          "finish_reason": "stop"
        }
      ],
      "usage": {
        ...
      }
    }
    
  7. Rimuovi il workload di convalida:

    kubectl delete \
    --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    

Operazioni

Attività del secondo giorno per i control plane del gateway.

Esegui l'upgrade

  • Inserisci le immagini e i grafici delle nuove versioni (aggiorna le variabili di versione in env.sh, esegui di nuovo seed_registry.sh e seed_charts.sh), applica i nuovi grafici CRD con kubectl apply --server-side, quindi esegui gli stessi comandi helm upgrade --install con il nuovo --version. Consulta la matrice di compatibilità di Envoy Agent Router per le versioni di Envoy Gateway e Gateway API supportate dalla release di destinazione. Envoy Agent Router 1.1.0 è basato su Envoy Gateway 1.8.

Disinstalla

  • Elimina prima le risorse Gateway, AIGatewayRoute e InferencePool delle guide utente, poi helm uninstall aieg --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}", helm uninstall eg --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}", ClusterRole envoy-gateway-inferencepool-reader, GatewayClass, Redis Deployment e infine i CRD.

Risoluzione dei problemi

Sintomo Probabile causa Azione
helm show chart o helm upgrade non riesce con unauthorized o FetchReference helm non dispone di credenziali per Harbor (non utilizza la configurazione Docker crane) Esegui di nuovo il passaggio helm registry login con l'account di servizio robot pull dell'immagine Kubernetes.
Envoy Gateway o Envoy Agent Router Pods rimangono in ImagePullBackOff L'immagine non è stata inizializzata o il secret di pull dell'immagine non è presente nello spazio dei nomi Controlla kubectl describe pod, confronta il percorso dell'immagine con crane ls "${GDCS_HARBOR_PROJECT_URI}/envoyproxy/gateway" e verifica che il secret esista in ${GDCS_ENVOY_GATEWAY_NAMESPACE} e ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}.
Gateway rimane Programmed=False dopo l'integrazione Il controller Envoy Gateway non riesce a raggiungere il server delle estensioni o non è stato riavviato dopo l'upgrade kubectl logs deployment/envoy-gateway --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"; verifica che service/ai-gateway-controller esista in ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} e che la porta 1063 sia elencata; ripeti il riavvio del lancio.
AIGatewayRoute che fa riferimento a un InferencePool non è accettato Envoy Gateway non dispone dell'autorizzazione per leggere inferencepools o mancano le CRD InferencePool Verifica ClusterRoleBinding envoy-gateway-inferencepool-reader e inferencepools.inference.networking.k8s.io CRD; controlla i log del controller per forbidden.
La richiesta di completamento della chat restituisce 413 o la connessione viene reimpostata per i prompt di grandi dimensioni Il limite predefinito del buffer Envoy (32 KiB) è troppo piccolo per i payload AI Allega un ClientTrafficPolicy con connection.bufferLimit (la convalida utilizza 50 Mi) a Gateway.
Il servizio di limitazione di frequenza Pod è CrashLoopBackOff Redis non è raggiungibile all'URL configurato kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}"; correggi rateLimit.backend.redis.url nel file dei valori di integrazione ed esegui di nuovo l'upgrade.

Materiali aggiuntivi