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

Dieses Dokument enthält eine Schritt-für-Schritt-Anleitung für die Bereitstellung eines AI Gateway in GDC-Umgebungen (Google Distributed Cloud) mit Air Gap. Das Gateway basiert auf Envoy Gateway, der auf dem Envoy-Proxy basierenden Kubernetes Gateway API-Implementierung, 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 umwandelt. Darin wird beschrieben, wie Sie die Container-Images und Helm-Diagramme in die lokale Harbor-Registry einfügen, beide Steuerungsebenen in einem Standardcluster installieren, das optionale tokenbasierte Backend für die Ratenbegrenzung vorbereiten und die Installation mit Beispielarbeitslasten validieren.

Die Backends für die Modellbereitstellung (Ollama, vLLM) werden mit der zugehörigen Reihe von Anleitungen Open Weight Models on GDC mit Air Gap bereitgestellt. Im Nutzerhandbuch für Body-basiertes Routing mit Envoy Agent Router wird beschrieben, wie Anfragen nach Modellname an sie weitergeleitet werden.

Architektur

Die Lösung wird in einem GDC-Standardcluster ausgeführt. Auf einer Administrator-Workstation werden die Bilder und Helm-Diagramme in die Harbor-Registry des Projekts eingefügt und die beiden Steuerungsebenen installiert: der Envoy Gateway-Controller, der die Envoy-Proxy-Datenebene aus Gateway API-Ressourcen (GatewayClass, Gateway, HTTPRoute) programmiert, und der Envoy Agent Router-Controller, der diese Datenebene mit einem 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 an InferencePool weiterleitet. In einer optionalen Redis-Instanz werden die Zähler des Envoy-Ratenbegrenzungsdienstes für die tokenbasierte Ratenbegrenzung gespeichert.

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

Envoy Gateway

Envoy Gateway ist ein Open-Source-Projekt, das auf dem 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 referenziert) 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 Dienste mit generativer KI zu verarbeiten. Sie bietet eine einheitliche Ebene für das Routing und die Verwaltung von LLM-Traffic mit modellbewusstem Routing, Upstream-Authentifizierung, tokenbasierten Ratenbegrenzung und Observability. Außerdem ist sie in die Gateway API Inference Extension (InferencePool, Endpoint Picker) für die metrikbewusste Endpunktauswahl integriert. 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-Completion-Anfrage), 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 Befehlszeilenprogramme richtig konfiguriert sind. Die Einrichtung dieser Tools auf Ihrer Workstation ist unerlässlich, um Containerregistrierungen zu verwalten, mit Clustern zu interagieren und den Bereitstellungsprozess zu automatisieren.

  • Die GDC-Umgebung ohne Internetverbindung 1.16.2-hf1 oder höher ist mit einem Standardcluster verfügbar, auf dem Kubernetes v1.32.13-gke.400 oder höher ausgeführt wird.
  • Standardcluster mit ausreichenden Ressourcen erstellt. Die Gateway-Komponenten werden nur auf der CPU ausgeführt. Für die Back-Ends für die Modellbereitstellung gelten eigene Anforderungen an Beschleuniger (siehe die Anleitungen Open Weight Models on GDC air-gapped).
  • Die Harbor-Instanz ist verfügbar und zugänglich.
  • Erforderliches IAM angewendet.
  • Workstation mit der erforderlichen Verbindung zur Umgebung und zum Internet

Umgebungskonfiguration

Die Umgebungskonfiguration umfasst die Identitäten und Berechtigungen, die Arbeitsstation 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-Nutzer-Rollen für Projekt (RoleBinding im Projekt-Namespace, zugewiesen von einem Projekt-IAM-Administrator):

  • Harbor-Instanz-Betrachter (harbor-instance-viewer)
  • Harbor Project Creator (harbor-project-creator, nur wenn das Harbor-Projekt noch nicht vorhanden ist)
  • Standard-Clusteradministrator (standard-cluster-admin, für gdcloud clusters get-credentials erforderlich)

Rolle GDC-Nutzer im Standardcluster: Die vorherigen Projektrollen gewähren keine Berechtigungen im Cluster. Ein Projekt-IAM-Administrator muss den Nutzer zusätzlich mit einem StandardClusterRoleBinding im Projekt-Namespace auf dem Management-API-Server an die StandardClusterRole cluster-admin 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 Management-API-Servers.
  • USER: user.
  • PROJECT: Projekt

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

  • Repository auflisten
  • Repository pullen
  • Repository pushen
  • Artefakt lesen
  • Artefakt auflisten
  • Tag erstellen
  • List-Tag

Berechtigungen für das Roboterkonto für das Abrufen von Harbor-Kubernetes-Images (kubernetes-image-puller):

  • Repository auflisten
  • Repository pullen
  • Artefakt lesen
  • Artefakt auflisten
  • List-Tag

Workstation

Für diesen Leitfaden ist eine Workstation mit der erforderlichen Verbindung zum Netzwerk und zum Internet erforderlich.

Voraussetzungen

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

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

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

Workstationkonfiguration

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

  • GDC_STANDARD_CLUSTER_NAME: Der Name des GDC-Standardclusters.
  • GDC_DOMAIN_SUFFIX: Das Domainsuffix 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 crane-Roboterkonto von Harbor.

  • GDCS_HARBOR_K8S_ROBOT_NAME: Der Name des Harbor-Robotkontos für das Abrufen von Kubernetes-Images.

  • GDCS_HARBOR_K8S_ROBOT_TOKEN: Das Authentifizierungstoken für das Harbor-Robotkonto zum Abrufen von Kubernetes-Images.

Nachdem Sie die Werte für alle erforderlichen Variablen erfasst haben, fahren Sie mit dem Generieren der Umgebungsvariablen-Datei fort. Nach der Erstellung können Sie die Datei jederzeit manuell bearbeiten.

  1. Erstellen Sie die Stammverzeichnisse der Lösung und den Ordner „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: Standardname des GDC-Clusters.
    • 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 die 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: Token für Kranroboter.
    • 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 Umgebungsvariablen 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 Ihre 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 in 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
    
  3. Prüfen Sie, ob auf jedem Knoten die Kubernetes-Version ausgeführt wird, die im Abschnitt Vorbereitung dieses Leitfadens erforderlich ist:

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

Migration von Artefakten vorbereiten

  1. Erstellen Sie eine Docker-Konfigurationsdatei für Crane. Ein Roboterkonto wird verwendet, um große Bildebenen zu übertragen, um Zeitüberschreitungen von Autorisierungstokens zu vermeiden, wenn der MHS-Anmeldeinformationshelfer (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 mit dem Kubernetes-Roboterkonto für das Abrufen von Images an. helm verwaltet seine eigenen Registry-Anmeldedaten und benötigt sie, 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 seed_registry.sh-Skript:

    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 dass eine Plattform ausgewählt wird 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: Die Version des Diagramms.
  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 Push an die 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. Stellen Sie die erforderlichen Helm-Diagramme in der Artifact Registry bereit:

    ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh
    
  3. Prüfen Sie, ob die Diagramme aus Harbor gelesen 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 der 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 dem Upstream-Schnellstart validiert. Die Integration des Envoy Agent Router folgt im nächsten Abschnitt.

Namespace

  1. Erstellen Sie den Namespace für Envoy Gateway. Die Envoy-Proxys Deployment jedes 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 (Standardchannel) und die benutzerdefinierten Ressourcendefinitionen (CRDs) von 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-Datei mit den Werten für Envoy Gateway. Die Bilder 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. Envoy Gateway installieren:

    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 Bilder des Controllers und des Zertifikaterstellungsjobs aus 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-Datenebene-Vorlage und die GatewayClass. Mit EnvoyProxy werden das Proxybild, das Image-Pull-Secret und die Ressourcenanforderungen der Proxy-Pod festgelegt. GatewayClass wird in den Nutzerhandbüchern 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 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 Kurzanleitung:

    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 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 über die Portweiterleitung eine Testanfrage über das Gateway. 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 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. Envoy Gateway wird dann neu konfiguriert, um ihn als Erweiterungsserver aufzurufen.

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 dieser Anleitung wird eine Redis-Instanz 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 die Redis-Instanz 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-Instanz 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-Datei mit den Werten 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 Ratenbegrenzungsservice zu verwenden.

  1. Erstellen Sie die Helm-Datei mit Werten 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 dem der Envoy Gateway-Controller InferencePool-Ressourcen überwachen kann. Das Diagramm gewährt diese Berechtigung nicht. Ein separates ClusterRoleBinding übersteht Diagramm-Upgrades, im Gegensatz zu einem Patch des vom Diagramm verwalteten ClusterRole:

    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 für 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 grundlegende Beispiel für den Envoy-Agent-Router (ein Mock-Upstream, der mit OpenAI kompatibel ist und sich hinter einem AIGatewayRoute befindet) im Namespace des Envoy-Agent-Routers 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 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 der Gateway den externen Prozessor-Sidecar 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 über das Gateway eine Chat-Vervollständigungsanfrage mithilfe der Portweiterleitung. Der externe Prozessor liest das Feld model des Anfragetexts und leitet es an den Mock-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

Aufgaben für den zweiten Tag für die Steuerungsebenen des Gateways.

Upgrade

  • Erstelle die Bilder und Diagramme der neuen Versionen (aktualisiere die Versionsvariablen in env.sh, führe seed_registry.sh und seed_charts.sh noch einmal aus), wende die neuen CRD-Diagramme mit kubectl apply --server-side an und führe dann dieselben helm upgrade --install-Befehle mit dem neuen --version aus. In der Envoy Agent Router-Kompatibilitätsmatrix finden Sie die Envoy Gateway- und Gateway API-Versionen, die von der Zielversion unterstützt werden. Envoy Agent Router 1.1.0 wurde für Envoy Gateway 1.8 entwickelt.

Deinstallieren

  • Löschen Sie zuerst die Gateway-, AIGatewayRoute- und InferencePool-Ressourcen 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 (es wird nicht die crane-Docker-Konfiguration verwendet). Führen Sie den Schritt helm registry login noch einmal mit dem Kubernetes-Roboterkonto zum Abrufen von Images aus.
Envoy Gateway oder Envoy Agent Router Pods bleiben in ImagePullBackOff Image nicht bereitgestellt oder das Secret zum Abrufen von Images fehlt im Namespace Prüfen Sie kubectl describe pod, vergleichen Sie den Bildpfad 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}"; bestätigen Sie, dass service/ai-gateway-controller in ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} vorhanden ist und Port 1063 aufgeführt wird. Wiederholen Sie den Neustart des Roll-outs.
AIGatewayRoute mit Verweis auf eine InferencePool wird 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.
Bei einer Anfrage zur Vervollständigung eines Chats wird 413 zurückgegeben 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 eine ClientTrafficPolicy mit connection.bufferLimit (für die Validierung werden 50 Mi verwendet) an die Gateway an.
Die Ratenbegrenzung für den Dienst Pod ist CrashLoopBackOff Redis ist unter der konfigurierten URL nicht erreichbar kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}"; korrigieren Sie rateLimit.backend.redis.url in der Datei mit den Integrationswerten und führen Sie das Upgrade noch einmal durch.

Zusätzliches Material