AI Gateway mit Envoy Agent Router – Referenzimplementierung auf GDC mit Air Gap

In diesem Dokument finden Sie eine detaillierte Anleitung zum Bereitstellen eines AI Gateway in GDC-Umgebungen (Google Distributed Cloud) mit Air Gap. Das Gateway basiert auf Envoy Gateway, der Kubernetes Gateway API-Implementierung, die auf dem Envoy-Proxy basiert, und Envoy Agent Router (früher Envoy AI Gateway), der Erweiterung, die Envoy Gateway in einen einheitlichen, OpenAI-kompatiblen Einstiegspunkt für Large Language Model (LLM)-Traffic verwandelt. Es umfasst das Seeding der Container-Images und Helm-Diagramme in die lokale Harbor-Registry, die Installation beider Steuerungsebenen auf einem Standardcluster, die Vorbereitung des optionalen tokenbasierten Backends für die Ratenbegrenzung und die Validierung der Installation mit Beispielarbeitslasten.

Back-Ends für die Modellbereitstellung (Ollama, vLLM) werden mit den zugehörigen Anleitungen Open-Weight-Modelle in GDC mit Air Gap bereitgestellt. Im Nutzerhandbuch zum Body-basierten Routing mit Envoy Agent Router wird gezeigt, wie Anfragen nach Modellname an sie weitergeleitet werden.

Architektur

Die Lösung wird in einem GDC-Standardcluster ausgeführt. Eine Administrator-Workstation stellt die Images und Helm-Diagramme in der Harbor-Registry des Projekts bereit und installiert die beiden Steuerungsebenen: den Envoy Gateway-Controller, der die Envoy-Proxy-Datenebene aus Gateway API-Ressourcen (GatewayClass, Gateway, HTTPRoute) programmiert, und den Envoy Agent Router-Controller, der diese Datenebene um einen externen Prozessor (ExtProc) für KI-Traffic (AIGatewayRoute, AIServiceBackend, InferencePool) erweitert. Anwendungsclients senden OpenAI-kompatible Anfragen an den Envoy-Proxy, der sie an die Back-Ends für die Modellbereitstellung oder InferencePools weiterleitet. In einer optionalen Redis-Instanz werden die Zähler des Envoy-Dienstes zur Ratenbegrenzung für die tokenbasierte Ratenbegrenzung gespeichert.

Referenzarchitektur für AI Gateway mit Envoy Agent Router in GDC mit Air Gap.

Envoy Gateway

Envoy Gateway ist ein Open-Source-Projekt, das auf Envoy Proxy basiert und die Einführung, Verwendung und Verwaltung von Envoy Proxy als Kubernetes API-Gateway vereinfacht. Sie implementiert und erweitert die Kubernetes Gateway API, den Nachfolger der Ingress API: GatewayClass- und Gateway-Ressourcen beschreiben die Einstiegspunkte, Routenressourcen wie HTTPRoute beschreiben, wie Traffic abgeglichen und weitergeleitet wird, und das rollenorientierte Design trennt die Verantwortlichkeiten von Infrastruktur- und Anwendungsteams. Envoy Gateway fügt eigene Erweiterungs-APIs hinzu, z. B. EnvoyProxy (Einstellungen für die Datenebene), Backend (Endpunkte außerhalb des Clusters oder mit FQDN-Referenz) und ClientTrafficPolicy (Verbindungseinstellungen wie Pufferlimits).

Envoy-Agent-Router

Envoy Agent Router (früher Envoy AI Gateway) ist ein Open-Source-Projekt, das Envoy Gateway verwendet, um Anfragetraffic von Anwendungsclients an Generative AI-Dienste zu verarbeiten. Es bietet eine einheitliche Ebene für das Routing und die Verwaltung von LLM-Traffic mit modellbewusstem Routing, Upstream-Authentifizierung, tokenbasierter Ratenbegrenzung und Beobachtbarkeit. Außerdem ist es in die Gateway API Inference Extension (InferencePool, Endpoint Picker) für die messwertbasierte Endpunktauswahl eingebunden. Der Controller überwacht die aigateway.envoyproxy.io/v1beta1-Ressourcen und fügt neben dem Envoy-Proxy einen externen Prozessor ein. Der externe Prozessor parst den Anfragetext (z. B. das Feld model einer OpenAI-Chat-Vervollständigungsanfrage), legt Routing-Header wie x-ai-eg-model fest und übersetzt bei Bedarf zwischen API-Schemas.

Hinweis

Bevor Sie mit der Bereitstellung fortfahren, müssen Sie sicherstellen, dass Ihre Umgebung alle erforderlichen Voraussetzungen erfüllt und die erforderlichen Befehlszeilen-Dienstprogramme richtig konfiguriert sind. Die Einrichtung dieser Tools auf Ihrer Workstation ist für die Verwaltung von Container-Registries, die Interaktion mit Clustern und die Automatisierung des Bereitstellungsprozesses unerlässlich.

  • Die GDC mit Air Gap-Umgebung ab Version 1.16.2-hf1 ist mit einem Standardcluster verfügbar, auf dem Kubernetes ab Version 1.32.13-gke.400 ausgeführt wird.
  • Standardcluster mit ausreichenden Ressourcen erstellt. Die Gateway-Komponenten werden nur auf der CPU ausgeführt. Backends für die Modellbereitstellung haben eigene Anforderungen an Beschleuniger (siehe die Leitfäden zu Open-Weight-Modellen in GDC mit Air Gap).
  • Harbor-Instanz verfügbar und zugänglich.
  • Erforderliche IAM-Berechtigungen angewendet.
  • Workstation mit der erforderlichen Verbindung zur Umgebung und zum Internet

Umgebungskonfiguration

Die Umgebungskonfiguration umfasst die Identitäten und Berechtigungen, die Workstation und den Zugriff auf die GDC-Umgebung und den Cluster.

Identity and Access Management

Prüfen Sie, ob die erforderlichen IAM-Konten, -Rollen und -Berechtigungen richtig konfiguriert sind.

GDC-Nutzerrollen im Projekt (RoleBinding im Projekt-Namespace, zugewiesen von einem IAM-Projektadministrator):

  • Harbor-Instanzbetrachter (harbor-instance-viewer)
  • Harbor-Projektersteller (harbor-project-creator, nur wenn das Harbor-Projekt noch nicht vorhanden ist)
  • Standard-Cluster-Administrator (standard-cluster-admin, erforderlich für gdcloud clusters get-credentials)

GDC-Nutzerrolle im Standardcluster: Die vorherigen Projektrollen gewähren keine Berechtigungen innerhalb des Clusters. Ein Projekt-IAM-Administrator muss den Nutzer zusätzlich an die StandardClusterRole cluster-admin mit einer StandardClusterRoleBinding im Projekt-Namespace auf dem Verwaltungs-API-Server binden. Die Bindung wird innerhalb von Sekunden an die Standardcluster des Projekts weitergegeben (status.clusters[].conditions zeigt Propagated=True). Clusterweite Berechtigungen sind erforderlich, da in dieser Anleitung benutzerdefinierte Ressourcendefinitionen, ClusterRoles und ein GatewayClass installiert werden.

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

Ersetzen Sie Folgendes:

  • MANAGEMENT_API_SERVER: der Pfad zur kubeconfig-Datei des Verwaltungs-API-Servers.
  • USER: Nutzer.
  • PROJECT: Projekt.

Berechtigungen für das Harbor crane (Crane)-Robot-Konto:

  • Repository auflisten
  • Pull-Repository
  • Repository übertragen
  • Artefakt lesen
  • Artefakt auflisten
  • Tag erstellen
  • Listen-Tag

Berechtigungen für das Harbor Kubernetes-Image-Pull-Robot-Konto (kubernetes-image-puller):

  • Repository auflisten
  • Pull-Repository
  • Artefakt lesen
  • Artefakt auflisten
  • Listen-Tag

Workstation

Führen Sie alle Befehle in dieser Anleitung auf einer Workstation mit den erforderlichen Tools und der erforderlichen Verbindung zur Umgebung und zum Internet aus, sofern in einem Schritt nichts anderes angegeben ist.

Voraussetzungen

Die folgenden Tools müssen auf der Workstation installiert sein:

  • crane: Container-Images und OCI-Artefakte zwischen Registries verwalten und kopieren (Dokumentation).
  • gdcloud: Befehlszeile (CLI) zum Verwalten von GDC-Ressourcen (Dokumentation).
  • kubectl: Befehlszeile (CLI) zur Kommunikation mit einem Kubernetes-Cluster und zu dessen Verwaltung.
  • helm: Paketmanager für Kubernetes, Version 3.8 oder höher (OCI-Registry-Unterstützung) (Dokumentation).
  • curl: Befehlszeilentool zum Übertragen von Daten mit URLs.
  • jq: Ein einfacher und flexibler JSON-Prozessor für die Befehlszeile.
  • yq: portabler YAML-Prozessor für die Befehlszeile.

Führen Sie alle Befehle in dieser Anleitung auf der Workstation aus, sofern in einem Schritt nichts anderes angegeben ist.

Workstationkonfiguration

Die folgenden Informationen zur Umgebung sind für die Workstation-Konfiguration erforderlich:

  • GDC_STANDARD_CLUSTER_NAME: Der Name des GDC-Standardclusters.
  • GDC_DOMAIN_SUFFIX: Das Domain-Suffix für die GDC-Umgebung (z. B. gdc.example.com).
  • GDC_ORG: Der Name der GDC-Organisation.
  • GDC_PROJECT: Der Name des GDC-Projekts.
  • GDC_ZONE: Der Name der GDC-Bereitstellungszone.
  • GDC_HARBOR_INSTANCE_NAME: Der Name der Harbor-Instanz im Projekt.

  • GDCS_HARBOR_PROJECT_NAME: Der Name des Harbor-Projekts, das für das Image verwendet werden soll (Standard: solutions)

  • GDCS_HARBOR_CRANE_ROBOT_NAME: Der Name des Harbor-crane-Roboterkontos.

  • GDCS_HARBOR_CRANE_ROBOT_TOKEN: Das Authentifizierungstoken für das Harbor-crane-Roboterkonto.

  • GDCS_HARBOR_K8S_ROBOT_NAME: Der Name des Harbor-Kubernetes-Image-Pull-Roboterkontos.

  • GDCS_HARBOR_K8S_ROBOT_TOKEN: Das Authentifizierungstoken für das Harbor-Kubernetes-Image-Pull-Roboterkonto.

Nachdem Sie die Werte für alle erforderlichen Variablen erfasst haben, fahren Sie mit dem Erstellen der Datei für Umgebungsvariablen fort. Nachdem die Datei erstellt wurde, können Sie sie jederzeit manuell bearbeiten.

  1. Erstellen Sie die Stammverzeichnisse der Lösung und den Ordner für 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. Erstellen Sie die Konfigurationsdatei für die Plattformumgebung:

    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
    

    Ersetzen Sie Folgendes:

    • STANDARD_CLUSTER_NAME: Name des GDC-Standardclusters.
    • DOMAIN_SUFFIX: GDC-Domainsuffix.
    • ORG: GDC-Organisation.
    • PROJECT: GDC-Projekt.
    • ZONE: GDC-Zone.
    • HARBOR_INSTANCE_NAME: Name der GDC Harbor-Instanz.
  3. Erstellen Sie die Konfigurationsdatei für die Registry-Umgebung:

    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
    

    Ersetzen Sie Folgendes:

    • HARBOR_CRANE_ROBOT_NAME: Name des GDC Harbor-Roboterkontos.
    • HARBOR_K8S_ROBOT_NAME: Name des GDC Harbor-Roboterkontos.
  4. Fügen Sie Ihre Tokens den Secret-Dateien hinzu:

    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
    

    Ersetzen Sie Folgendes:

    • CRANE_ROBOT_TOKEN: Crane-Roboter-Token.
    • KUBERNETES_ROBOT_TOKEN: Kubernetes-Roboter-Token.
  5. Erstellen Sie die Loader-Datei für die Root-Umgebung:

    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
    

Lösungsvariablen konfigurieren

  1. Erstellen Sie das Verzeichnis für die Lösungsimplementierung:

    mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d
    
  2. Erstellen Sie die Konfigurationsdatei für die Lösungsumgebung:

    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. Erstellen Sie die Loader-Datei für die Implementierungsumgebung:

    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. Bearbeiten und prüfen Sie die Umgebungsdateien mit Ihrem bevorzugten Editor:

    ${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. Rufen Sie die Umgebungsdatei auf:

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

    Die Ausgabe sieht etwa so aus:

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

GDC

In diesem Leitfaden wird davon ausgegangen, dass Ihre Workstation so konfiguriert ist, dass sie den TLS-Zertifikaten für Ihre GDC-Umgebung und Harbor-Instanz vertraut.

  1. Konfigurieren Sie 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. Authentifizieren Sie sich bei der GDC-Umgebung:

    gdcloud auth login
    

Cluster

  1. Clusteranmeldedaten abrufen:

    gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \
    --project="${GDC_PROJECT}" \
    --standard \
    --zone="${GDC_ZONE}"
    
  2. Prüfen Sie die Verbindung zum Cluster:

    kubectl get nodes -L node.cluster.private.gdc.goog/machine-class
    

Artefaktmigration vorbereiten

  1. Erstellen Sie eine Docker-Konfigurationsdatei für Crane. Ein Roboterkonto wird verwendet, um große Image-Ebenen zu übertragen und so Zeitüberschreitungen bei Authentifizierungstokens zu vermeiden, wenn der Managed Harbor Service (MHS)-Anmeldedaten-Helper (docker-credential-mhs) mit einem Nutzerkonto verwendet wird:

    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. Erstellen Sie eine Docker-Konfigurationsdatei für 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. Melden Sie sich mit helm in der Harbor-OCI-Registry an. Verwenden Sie dazu das Roboterkonto zum Abrufen von Kubernetes-Images. helm speichert eigene Registry-Anmeldedaten und benötigt diese, um die Diagramme aus Harbor abzurufen:

    set +o history
    helm registry login "${GDC_HARBOR_HOST}" \
    --password="${GDCS_HARBOR_K8S_ROBOT_TOKEN}" \
    --username="${GDCS_HARBOR_K8S_ROBOT_NAME}"
    set -o history
    

    Die Ausgabe sieht etwa so aus:

    Login Succeeded
    
  4. Erstellen Sie das Skript 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. Erstellen Sie das Skript seed_charts.sh. Als OCI-Artefakte veröffentlichte Helm-Diagramme werden ebenfalls mit crane kopiert, ohne Plattformauswahl und ohne das Tag create, das für Container-Image-Repositories verwendet wird:

    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"
    

    Ersetzen Sie Folgendes:

    • REGISTRY_HOST: Registry-Host.
    • REPOSITORY: Repository.
    • CHART_VERSION: Diagrammversion.
  6. Definieren Sie die Liste der erforderlichen Container-Images für die Lösung:

    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. Übertragen Sie die erforderlichen Container-Images per Seed an Artifact Registry:

    ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
    
  1. Definieren Sie die Liste der erforderlichen Helm-Diagramme für die Lösung:

    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. Übertragen Sie die erforderlichen Helm-Diagramme in die Artifact Registry:

    ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh
    
  3. Prüfen Sie, ob die Diagramme aus Harbor zurückgelesen werden können:

    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):'
    

    Die Ausgabe sieht etwa so aus:

    name: gateway-helm
    version: v1.8.5
    name: ai-gateway-helm
    version: v1.1.0
    
  4. Laden Sie die Manifeste für die Gateway API Inference Extension herunter. Sie werden als Release-Asset und nicht als Diagramm veröffentlicht:

    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"
    

    Die Ausgabe sieht etwa so aus:

    4
    

Envoy Gateway

Envoy Gateway wird zuerst installiert und mit der Upstream-Kurzanleitung validiert. Die Integration von Envoy Agent Router folgt im nächsten Abschnitt.

Namespace

  1. Erstellen Sie den Namespace für Envoy Gateway. Die Envoy-Proxy-Deployments aller Gateway werden ebenfalls in diesem Namespace erstellt:

    kubectl create namespace "${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  2. Fügen Sie die imagePullSecret hinzu:

    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 -
    

Benutzerdefinierte Ressourcendefinitionen

  1. Installieren Sie die Gateway API (Standardkanal) und die benutzerdefinierten Ressourcendefinitionen (CRDs) für Envoy Gateway aus dem Seed-Diagramm:

    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. Prüfen Sie, ob die CRDs registriert sind:

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

Controller

  1. Erstellen Sie die Helm-Wertedatei für Envoy Gateway. Die Images werden mit dem Image-Pull-Secret aus Harbor abgerufen. crds.enabled=false, da die CRDs separat installiert wurden:

    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. Installieren Sie 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. Warten Sie, bis der Envoy Gateway-Controller verfügbar ist:

    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. Prüfen Sie, ob die Images des Controllers und seines Zertifikatgenerierungsjobs von Harbor stammen:

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

Envoy-Proxy und Gateway-Klasse

  1. Erstellen Sie das Manifest für die EnvoyProxy-Datenebenenvorlage und die GatewayClass. Mit dem EnvoyProxy werden das Proxy-Image, das Image-Pull-Secret und die Ressourcenanfragen der Proxy-Pods festgelegt. Die GatewayClass wird von den Nutzerhandbüchern gemeinsam verwendet:

    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. Wenden Sie das Manifest für EnvoyProxy und GatewayClass an:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"
    
  3. Prüfen Sie, ob der GatewayClass akzeptiert wurde:

    kubectl get gatewayclass "${GDCS_GATEWAY_CLASS_NAME}"
    

    Die Ausgabe sieht etwa so aus:

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

Validierung

Bei der Validierung wird der Envoy Gateway-Schnellstart (ein Echo-Backend hinter einem HTTPRoute) im Envoy Gateway-Namespace bereitgestellt und anschließend entfernt.

  1. Erstellen Sie das Manifest für die Schnellstart-Arbeitslast:

    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. Wenden Sie das Manifest für die Arbeitslast der Kurzanleitung an:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  3. Warten Sie, bis die Gateway programmiert ist:

    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. Warten Sie, bis das Backend Deployment verfügbar ist:

    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. Senden Sie eine Testanfrage über das Gateway mithilfe der Portweiterleitung. Der Envoy-Service eines Gateway wird anhand der Labels des zugehörigen Gateways ermittelt:

    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}
    

    Die Ausgabe sieht etwa so aus:

    {
      "path": "/get",
      "host": "www.example.com",
      "method": "GET",
      ...
      "namespace": "envoy-gateway-system",
      "pod": "eg-quickstart-backend-...",
      ...
    }
    
  6. Entfernen Sie die Arbeitslast aus der Kurzanleitung:

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

Envoy-Agent-Router

Der Envoy Agent Router wird in einem eigenen Namespace installiert. Das Envoy Gateway wird dann so konfiguriert, dass es als Erweiterungsserver aufgerufen wird.

Namespace

  1. Erstellen Sie den Namespace für den Envoy Agent Router-Controller:

    kubectl create namespace "${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  2. Fügen Sie die imagePullSecret hinzu:

    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 -
    

Benutzerdefinierte Ressourcendefinitionen

  1. Installieren Sie die Envoy Agent Router-CRDs aus dem Seed-Diagramm:

    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. Installieren Sie die Gateway API Inference Extension-CRDs (InferencePool, InferenceObjective) aus den heruntergeladenen Manifesten:

    kubectl apply --server-side \
    --filename="${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml"
    
  3. Prüfen Sie, ob die CRDs registriert sind:

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

    Die Ausgabe sieht etwa so aus:

    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

Die tokenbasierte Ratenbegrenzung wird vom Envoy-Ratenbegrenzungsdienst erzwungen, der seine Zähler in Redis speichert. In diesem Leitfaden wird ein Redis-Dienst mit einem einzelnen Replikat ohne Persistenz bereitgestellt. Sie können stattdessen einen vorhandenen Redis-Dienst verwenden, indem Sie den Wert rateLimit.backend.redis.url im nächsten Abschnitt ändern.

  1. Erstellen Sie das Manifest für den 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. Wenden Sie das Manifest für den Redis-Deployment an:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \
    --namespace="${GDCS_REDIS_NAMESPACE}"
    
  3. Warten Sie, bis die Redis-Deployment verfügbar ist:

    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. Erstellen Sie die Helm-Wertedatei für den 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. Envoy-Agent-Router installieren:

    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. Warten Sie, bis der Envoy Agent Router-Controller verfügbar ist:

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

Envoy Gateway-Integration

Envoy Gateway muss neu konfiguriert werden, um den Envoy Agent Router-Controller als Erweiterungsserver aufzurufen, InferencePool-Ressourcen als Backends zu akzeptieren und den Redis-basierten Dienst zur Ratenbegrenzung zu verwenden.

  1. Erstellen Sie die Helm-Wertedatei für die Integration:

    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. Aktualisieren Sie Envoy Gateway mit beiden Wertedateien:

    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. Erstellen Sie das Manifest für die ClusterRole, mit der der Envoy Gateway-Controller InferencePool-Ressourcen beobachten kann. Das Diagramm gewährt diese Berechtigung nicht. Ein separates ClusterRoleBinding bleibt im Gegensatz zu einem Patch des vom Diagramm verwalteten ClusterRole bei Diagrammupgrades erhalten:

    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. Wenden Sie das Manifest für ClusterRole an:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"
    
  5. Starten Sie den Envoy Gateway-Controller neu, damit er die neue Konfiguration und die neuen Berechtigungen übernimmt, und warten Sie, bis er verfügbar ist:

    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. Prüfen Sie, ob der Dienst zur Ratenbegrenzung bereitgestellt wurde und verfügbar ist:

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

Validierung

Bei der Validierung wird das einfache Beispiel für den Envoy Agent Router (ein simulierter OpenAI-kompatibler Upstream hinter einem AIGatewayRoute) im Envoy Agent Router-Namespace bereitgestellt und anschließend entfernt.

  1. Erstellen Sie das Manifest für die Validierungsarbeitslast:

    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. Wenden Sie das Manifest für die Validierungsarbeitslast an:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  3. Warten Sie, bis die Gateway programmiert ist:

    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. Warten Sie, bis der Mock-Upstream Deployment verfügbar ist:

    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. Prüfen Sie, ob der Envoy-Proxy Pod von Gateway den Sidecar-Container des externen Prozessors ausführt, der vom Envoy Agent Router eingefügt wurde:

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

    Die Ausgabe sieht etwa so aus:

    envoy-envoy-ai-gateway-system-aieg-basic-...   envoy shutdown-manager ai-gateway-extproc
    
  6. Senden Sie eine Anfrage zur Chatvervollständigung über das Gateway mithilfe der Portweiterleitung. Der externe Prozessor liest das Feld model des Anfragetexts und leitet es an den simulierten Upstream weiter:

    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}
    

    Die Ausgabe sieht etwa so aus:

    {
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "..."
          },
          "finish_reason": "stop"
        }
      ],
      "usage": {
        ...
      }
    }
    
  7. Entfernen Sie die Validierungsarbeitslast:

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

Vorgänge

Day-Two-Aufgaben für die Gateway-Steuerungsebenen.

Upgrade

  • Stellen Sie die Images und Diagramme der neuen Versionen bereit (aktualisieren Sie die Versionsvariablen in env.sh, führen Sie seed_registry.sh und seed_charts.sh noch einmal aus), wenden Sie die neuen CRD-Diagramme mit kubectl apply --server-side an und führen Sie dann dieselben helm upgrade --install-Befehle mit der neuen --version aus. In der Kompatibilitätsmatrix für Envoy Agent Router finden Sie die Envoy Gateway- und Gateway API-Versionen, die vom Zielrelease unterstützt werden. Envoy Agent Router 1.1.0 basiert auf Envoy Gateway 1.8.

Deinstallieren

  • Löschen Sie zuerst die Ressourcen Gateway, AIGatewayRoute und InferencePool der Nutzerhandbücher, dann helm uninstall aieg --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}", helm uninstall eg --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}", die ClusterRole envoy-gateway-inferencepool-reader, die GatewayClass, die Redis-Deployment und schließlich die CRDs.

Fehlerbehebung

Symptom Wahrscheinliche Ursache Aktion
helm show chart oder helm upgrade schlägt mit unauthorized oder FetchReference fehl helm hat keine Anmeldedaten für Harbor (die Docker-Konfiguration crane wird nicht verwendet) Führen Sie den Schritt helm registry login noch einmal mit dem Kubernetes-Image-Pull-Robot-Konto aus.
Envoy Gateway- oder Envoy Agent Router-Pods bleiben in ImagePullBackOff Image wurde nicht per Seeding bereitgestellt oder das Image-Pull-Secret fehlt im Namespace Prüfen Sie kubectl describe pod, vergleichen Sie den Image-Pfad mit crane ls "${GDCS_HARBOR_PROJECT_URI}/envoyproxy/gateway" und prüfen Sie, ob das Secret in ${GDCS_ENVOY_GATEWAY_NAMESPACE} und ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} vorhanden ist.
Gateway bleibt nach der Integration Programmed=False Der Envoy Gateway-Controller kann den Erweiterungsserver nicht erreichen oder wurde nach dem Upgrade nicht neu gestartet. kubectl logs deployment/envoy-gateway --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"; prüfen Sie, ob service/ai-gateway-controller in ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} vorhanden ist und Port 1063 aufgeführt ist. Wiederholen Sie den Neustart des Roll-outs.
AIGatewayRoute, die auf eine InferencePool verweisen, werden nicht akzeptiert Envoy Gateway hat keine Berechtigung zum Lesen von inferencepools oder die InferencePool-CRDs fehlen Prüfen Sie die ClusterRoleBinding-envoy-gateway-inferencepool-reader und die inferencepools.inference.networking.k8s.io-CRD. Suchen Sie in den Controller-Logs nach forbidden.
Die Anfrage zum Vervollständigen des Chats gibt 413 zurück oder die Verbindung wird bei großen Prompts zurückgesetzt. Das standardmäßige Envoy-Pufferlimit (32 KiB) ist für KI-Nutzlasten zu klein. Hängen Sie einen ClientTrafficPolicy mit connection.bufferLimit (die Validierung verwendet 50 Mi) an den Gateway an.
Der Dienst zur Ratenbegrenzung Pod ist CrashLoopBackOff Redis ist unter der konfigurierten URL nicht erreichbar kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}"; Beheben Sie rateLimit.backend.redis.url in der Datei mit den Integrationswerten und führen Sie das Upgrade noch einmal durch.

Zusätzliche Materialien