Implementação de referência do roteador do agente do Envoy com o AI Gateway no GDC com isolamento físico

Este documento fornece instruções detalhadas para implantar um gateway de IA em ambientes isolados do Google Distributed Cloud (GDC). O gateway é criado com base no Envoy Gateway, a implementação da API Kubernetes Gateway baseada no proxy Envoy, e no Envoy Agent Router (antigo Envoy AI Gateway), a extensão que transforma o Envoy Gateway em um ponto de entrada unificado e compatível com a OpenAI para tráfego de modelos de linguagem grandes (LLMs). Ele aborda o seeding das imagens de contêiner e dos gráficos do Helm no registro local do Harbor, a instalação dos dois planos de controle em um cluster padrão, a preparação do back-end opcional de limitação de taxa baseada em token e a validação da instalação com cargas de trabalho de exemplo.

Os back-ends de disponibilização de modelos (Ollama, vLLM) são implantados com o conjunto complementar de guias Modelos de peso aberto em GDC isolado por ar. O Guia do usuário de roteamento baseado em corpo com o roteador de agente do Envoy mostra como rotear solicitações para eles por nome do modelo.

Arquitetura

A solução é executada em um cluster padrão do GDC. Uma estação de trabalho de administrador envia as imagens e os gráficos do Helm para o registro do Harbor do projeto e instala os dois planos de controle: o controlador do Envoy Gateway, que programa o plano de dados do proxy Envoy com recursos da API Gateway (GatewayClass, Gateway, HTTPRoute), e o controlador do roteador do agente Envoy, que estende esse plano de dados com um processador externo (ExtProc) para tráfego de IA (AIGatewayRoute, AIServiceBackend, InferencePool). Os clientes de aplicativos enviam solicitações compatíveis com a OpenAI para o proxy Envoy, que as encaminha para os back-ends de disponibilização do modelo ou InferencePools. Uma instância opcional do Redis armazena os contadores do serviço de limitação de taxa do Envoy para limitação de taxa baseada em token.

Arquitetura de referência do roteador do agente Envoy do gateway de IA no GDC com isolamento físico.

Envoy Gateway

O Envoy Gateway é um projeto de código aberto criado no proxy do Envoy, que simplifica a adoção, o uso e o gerenciamento do proxy do Envoy como um gateway de API do Kubernetes. Ela implementa e estende a API Kubernetes Gateway, a sucessora da API Ingress: os recursos GatewayClass e Gateway descrevem os pontos de entrada, os recursos de rota, como HTTPRoute, descrevem como o tráfego é correspondido e encaminhado, e o design orientado a papéis separa as responsabilidades das equipes de infraestrutura e de aplicativos. O Envoy Gateway adiciona as próprias APIs de extensão, por exemplo, EnvoyProxy (configurações do plano de dados), Backend (endpoints fora do cluster ou referenciados por FQDN) e ClientTrafficPolicy (configurações de conexão, como limites de buffer).

Roteador de agente do Envoy

O Envoy Agent Router (antigo Envoy AI Gateway) é um projeto de código aberto que usa o Envoy Gateway para processar o tráfego de solicitações de clientes de aplicativos para serviços de IA generativa. Ela fornece uma camada unificada para roteamento e gerenciamento do tráfego de LLMs com roteamento compatível com modelos, autenticação upstream, limitação de taxa baseada em token e capacidade de observação. Além disso, ela se integra à Extensão de inferência da API Gateway (InferencePool, seletor de endpoints) para seleção de endpoints com reconhecimento de métricas. O controlador monitora os recursos aigateway.envoyproxy.io/v1beta1 e injeta um processador externo ao lado do proxy Envoy. O processador externo analisa o corpo da solicitação (por exemplo, o campo model de uma solicitação de conclusão de chat da OpenAI ), define cabeçalhos de roteamento, como x-ai-eg-model, e faz a tradução entre esquemas de API quando necessário.

Antes de começar

Antes de continuar com a implantação, verifique se o ambiente atende a todos os pré-requisitos necessários e se os utilitários de linha de comando exigidos estão configurados corretamente. Configurar essas ferramentas na sua estação de trabalho é essencial para gerenciar registros de contêineres, interagir com clusters e automatizar o processo de implantação.

  • O ambiente GDC com isolamento físico 1.16.2-hf1 ou mais recente está disponível com um cluster padrão que executa o Kubernetes v1.32.13-gke.400 ou mais recente.
  • Cluster padrão criado com recursos suficientes. Os componentes de gateway são executados apenas na CPU. Os back-ends de disponibilização do modelo têm requisitos próprios de acelerador (consulte os guias Modelos de peso aberto no GDC air-gapped).
  • Uma instância do Harbor disponível e acessível.
  • O IAM necessário foi aplicado.
  • Estação de trabalho com a conectividade necessária ao ambiente e à Internet

Configuração do ambiente

A configuração do ambiente abrange as identidades e permissões, a estação de trabalho e o acesso ao ambiente do GDC e ao cluster.

Identity and Access Management

Verifique se as contas, os papéis e as permissões necessárias do IAM estão configurados corretamente.

Papéis de usuário do GDC no projeto (RoleBinding no namespace do projeto, concedidos por um administrador do IAM do projeto):

  • Leitor de instâncias do Harbor (harbor-instance-viewer)
  • Criador de projetos do Harbor (harbor-project-creator, somente se o projeto do Harbor ainda não existir)
  • Administrador do cluster padrão (standard-cluster-admin, necessário para gdcloud clusters get-credentials)

Papel Usuário do GDC no cluster padrão: os papéis de projeto anteriores não concedem permissões dentro do cluster. Um administrador do IAM do projeto também precisa vincular o usuário ao StandardClusterRole cluster-admin com um StandardClusterRoleBinding no namespace do projeto no servidor da API de gerenciamento. A vinculação é propagada para os clusters padrão do projeto em segundos (status.clusters[].conditions mostra Propagated=True). São necessárias permissões em todo o cluster porque este guia instala definições de recursos personalizados, ClusterRoles e um GatewayClass.

cat <<EOF | kubectl --kubeconfig MANAGEMENT_API_SERVER apply -f -
apiVersion: iam.gdc.goog/v1
kind: StandardClusterRoleBinding
metadata:
  name: user-USER-cluster-admin
  namespace: PROJECT
spec:
  roleRef:
    apiGroup: iam.gdc.goog
    kind: StandardClusterRole
    name: cluster-admin
  subjects:
    - apiGroup: rbac.authorization.k8s.io
      kind: User
      name: USER
EOF

Substitua:

  • MANAGEMENT_API_SERVER: o caminho para o arquivo kubeconfig do servidor da API de gerenciamento.
  • USER: usuário.
  • PROJECT: projeto.

Permissões da conta de robô do Harbor crane (crane):

  • Listar repositório
  • Extrair repositório
  • Repositório de push
  • Ler artefato
  • Listar artefato
  • Criar tag
  • Tag de lista

Permissões da conta de robô de extração de imagens do Kubernetes do Harbor (kubernetes-image-puller):

  • Listar repositório
  • Extrair repositório
  • Ler artefato
  • Listar artefato
  • Tag de lista

Estação de trabalho

Este guia exige uma estação de trabalho com a conectividade necessária ao ambiente e à Internet.

Requisitos

As seguintes ferramentas precisam ser instaladas na estação de trabalho:

  • crane: gerencie e copie imagens de contêiner e artefatos OCI entre registros (documentação).
  • gdcloud: interface de linha de comando (CLI) para gerenciar recursos do GDC (documentação).
  • kubectl: interface de linha de comando (CLI) usada para se comunicar com um cluster do Kubernetes e gerenciá-lo.
  • helm: gerenciador de pacotes para Kubernetes, versão 3.8 ou mais recente (suporte ao registro OCI) (documentação).
  • curl: ferramenta de linha de comando para transferir dados com URLs.
  • jq: processador JSON de linha de comando leve e flexível.
  • yq: processador YAML portátil de linha de comando.

Execute todos os comandos deste guia na estação de trabalho, a menos que uma etapa indique o contrário.

Configuração da estação de trabalho

As seguintes informações sobre o ambiente são necessárias para a configuração da estação de trabalho:

  • GDC_STANDARD_CLUSTER_NAME: o nome do cluster padrão do GDC.
  • GDC_DOMAIN_SUFFIX: o sufixo de domínio do ambiente do GDC (por exemplo, gdc.example.com).
  • GDC_ORG: o nome da organização do GDC.
  • GDC_PROJECT: o nome do projeto do GDC.
  • GDC_ZONE: o nome da zona de implantação do GDC.
  • GDC_HARBOR_INSTANCE_NAME: o nome da instância do Harbor no projeto.

  • GDCS_HARBOR_PROJECT_NAME: o nome do projeto do Harbor a ser usado para a imagem (padrão: solutions)

  • GDCS_HARBOR_CRANE_ROBOT_NAME: o nome da conta do robô crane do Harbor.

  • GDCS_HARBOR_CRANE_ROBOT_TOKEN: o token de autenticação da conta de robô crane do Harbor.

  • GDCS_HARBOR_K8S_ROBOT_NAME: o nome da conta de robô de extração de imagens do Kubernetes do Harbor.

  • GDCS_HARBOR_K8S_ROBOT_TOKEN: o token de autenticação da conta de robô de extração de imagens do Kubernetes do Harbor.

Depois de reunir os valores de todas as variáveis necessárias, gere o arquivo de variáveis de ambiente. Depois de criado, você pode editar o arquivo manualmente a qualquer momento.

  1. Crie os diretórios raiz da solução e a pasta de segredos:

    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. Crie o arquivo de configuração do ambiente da plataforma:

    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
    

    Substitua:

    • STANDARD_CLUSTER_NAME: nome do cluster padrão do GDC.
    • DOMAIN_SUFFIX: sufixo de domínio do GDC.
    • ORG: organização da GDC.
    • PROJECT: projeto do GDC.
    • ZONE: zona da GDC.
    • HARBOR_INSTANCE_NAME: nome da instância do GDC Harbor.
  3. Crie o arquivo de configuração do ambiente do registro:

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

    Substitua:

    • HARBOR_CRANE_ROBOT_NAME: nome da conta do robô do GDC Harbor.
    • HARBOR_K8S_ROBOT_NAME: nome da conta do robô do GDC Harbor.
  4. Adicione seus tokens aos arquivos de secret:

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

    Substitua:

    • CRANE_ROBOT_TOKEN: token do robô guindaste.
    • KUBERNETES_ROBOT_TOKEN: token de robô do Kubernetes.
  5. Crie o arquivo de carregador do ambiente raiz:

    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
    

Configurar variáveis de solução

  1. Crie o diretório de implementação da solução:

    mkdir -p ${HOME}/gdcag-solutions/ai-gateway/envoy/env.d
    
  2. Crie o arquivo de configuração do ambiente de solução:

    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. Crie o arquivo do carregador do ambiente de implementação:

    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. Edite e revise os arquivos de ambiente com seu editor preferido:

    ${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. Use o comando source no arquivo de ambiente:

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

    O resultado será o seguinte:

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

GDC

Este guia pressupõe que sua estação de trabalho esteja configurada para confiar nos certificados TLS do seu ambiente do GDC e da instância do Harbor.

  1. Configurar 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. Autentique-se no ambiente do GDC:

    gdcloud auth login
    

Cluster

  1. Recupere as credenciais do cluster:

    gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \
    --project="${GDC_PROJECT}" \
    --standard \
    --zone="${GDC_ZONE}"
    
  2. Verifique a conectividade com o cluster:

    kubectl get nodes -L node.cluster.private.gdc.goog/machine-class
    
  3. Verifique se cada nó executa a versão do Kubernetes exigida na seção Antes de começar deste guia:

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

Preparação para a migração de artefatos

  1. Crie um arquivo de configuração do Docker para o crane. Uma conta de robô é usada para enviar camadas de imagens grandes para evitar tempos limite de token de autenticação ao usar o ajudante de credenciais do Managed Harbor Service (MHS) (docker-credential-mhs) com uma conta de usuário:

    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. Crie um arquivo de configuração do Docker para o 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. Faça login no registro do Harbor OCI com helm usando a conta de robô de extração de imagens do Kubernetes. O helm mantém as próprias credenciais de registro e precisa delas para buscar os gráficos do Harbor:

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

    O resultado será o seguinte:

    Login Succeeded
    
  4. Crie o script seed_registry.sh:

    cat << 'EOF' > ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh && echo "Successfully created." || echo "Failed to create!"
    #!/bin/bash
    
    # seed_registry.sh: Modular artifact migration for GDC Solutions
    
    # Requires the env.sh file to be sourced first.
    SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    set -o nounset
    source "${SCRIPT_DIR}/env.sh"
    
    # Set the Docker config
    export DOCKER_CONFIG="${GDCS_HARBOR_CRANE_DOCKER_CONFIG}"
    eval "${SERIALIZED_IMAGES}"
    
    # Ensure GDCS_REGISTRY_IMAGES is set
    if [[ ${#GDCS_REGISTRY_IMAGES[@]} -eq 0 ]]; then
      echo "GDCS_REGISTRY_IMAGES must be set, exiting..."
      exit 1
    fi
    
    # Migrate the images
    for source_image in "${GDCS_REGISTRY_IMAGES[@]}"; do
      # Strip the registry host only when the first path segment is a host (contains a dot or a port)
      first_segment="${source_image%%/*}"
      if [[ "${first_segment}" == *.* || "${first_segment}" == *:* ]]; then
        image_path="${source_image#*/}"
      else
        image_path="${source_image}"
      fi
      destination_image="${GDCS_HARBOR_PROJECT_URI}/${image_path}"
      # Ensure the folder structure is created
      crane append \
        --new_layer=<(tar czf - -T /dev/null) \
        --new_tag="${destination_image%:*}:create" \
        --oci-empty-base 2> /dev/null || true
      # Copy the linux/amd64 platform only to avoid transferring multi-arch layers over air-gapped links
      crane copy --platform linux/amd64 "${source_image}" "${destination_image}" 2> /dev/null
    done
    echo "Migration complete: Images are available at ${GDCS_HARBOR_PROJECT_URI}"
    EOF
    chmod u+x "${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh"
    
  5. Crie o script seed_charts.sh. Os gráficos Helm publicados como artefatos OCI também são copiados com crane, sem seleção de plataforma e sem a tag create usada para repositórios de imagens de contêiner:

    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"
    

    Substitua:

    • REGISTRY_HOST: host do registro.
    • REPOSITORY: repositório.
    • CHART_VERSION: versão do gráfico.
  6. Defina a lista de imagens de contêiner necessárias para a solução:

    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. Faça o seeding das imagens de contêiner necessárias para o Artifact Registry:

    ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
    
  1. Defina a lista de gráficos Helm necessários para a solução:

    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. Inicialize os gráficos do Helm necessários no Artifact Registry:

    ${GDCS_IMPLEMENTATION_HOME}/seed_charts.sh
    
  3. Verifique se os gráficos podem ser lidos novamente no Harbor:

    helm show chart "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/gateway-helm" --version "${GDCS_ENVOY_GATEWAY_VERSION}" | grep -E '^(name|version):'
    helm show chart "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/ai-gateway-helm" --version "${GDCS_ENVOY_AGENT_ROUTER_VERSION}" | grep -E '^(name|version):'
    

    O resultado será o seguinte:

    name: gateway-helm
    version: v1.8.5
    name: ai-gateway-helm
    version: v1.1.0
    
  4. Faça o download dos manifestos da extensão de inferência da API Gateway. Eles são publicados como um recurso de lançamento, não como um gráfico:

    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"
    

    O resultado será o seguinte:

    4
    

Envoy Gateway

O Envoy Gateway é instalado primeiro e validado por conta própria com o início rápido upstream. A integração do Envoy Agent Router é abordada na próxima seção.

Namespace

  1. Crie o namespace para o Envoy Gateway. Os proxies Deployment do Envoy de cada Gateway também são criados nesse namespace:

    kubectl create namespace "${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  2. Adicione o imagePullSecret:

    kubectl create secret docker-registry "${GDCS_HARBOR_K8S_PULL_SECRET}" \
    --dry-run=client \
    --from-file=.dockerconfigjson=${GDCS_HARBOR_K8S_DOCKER_CONFIG}/config.json \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}" \
    --output=yaml | kubectl apply -f -
    

Definições de recursos do Kubernetes

  1. Instale a API Gateway (canal padrão) e as definições de recursos personalizados (CRDs) do Envoy Gateway do gráfico de inicialização:

    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. Verifique se os CRDs estão registrados:

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

Controlador

  1. Crie o arquivo de valores do Helm para o Envoy Gateway. As imagens são extraídas do Harbor com o segredo de extração de imagens; crds.enabled=false porque os CRDs foram instalados separadamente:

    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. Instale o 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. Aguarde até que o controlador do Envoy Gateway esteja disponível:

    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. Verifique se as imagens do controlador e o job de geração de certificados vêm do Harbor:

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

Proxy do Envoy e classe de gateway

  1. Crie o manifesto para o modelo de plano de dados EnvoyProxy e o GatewayClass. O EnvoyProxy define a imagem do proxy, o segredo de extração de imagem e as solicitações de recursos dos Pods de proxy. O GatewayClass é compartilhado pelos guias do usuário:

    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. Aplique o manifesto para o EnvoyProxy e o GatewayClass:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/gateway-class.yaml"
    
  3. Verifique se o GatewayClass foi aceito:

    kubectl get gatewayclass "${GDCS_GATEWAY_CLASS_NAME}"
    

    O resultado será o seguinte:

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

Validação

A validação implanta o guia de início rápido do Envoy Gateway (um back-end de eco por trás de um HTTPRoute) no namespace do Envoy Gateway e o remove depois.

  1. Crie o manifesto para a carga de trabalho do guia de início rápido:

    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. Aplique o manifesto para a carga de trabalho de início rápido:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/eg-quickstart.yaml" \
    --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"
    
  3. Aguarde até que o Gateway seja programado:

    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. Aguarde até que o back-end Deployment esteja disponível:

    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. Envie uma solicitação de teste pelo gateway usando o encaminhamento de porta. O Envoy Service de um Gateway é encontrado pelos rótulos do gateway proprietário:

    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}
    

    O resultado será o seguinte:

    {
      "path": "/get",
      "host": "www.example.com",
      "method": "GET",
      ...
      "namespace": "envoy-gateway-system",
      "pod": "eg-quickstart-backend-...",
      ...
    }
    
  6. Remova a carga de trabalho do guia de início rápido:

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

Roteador de agente do Envoy

O roteador do agente do Envoy é instalado no próprio namespace. Em seguida, o gateway do Envoy é reconfigurado para chamá-lo como servidor de extensão.

Namespace

  1. Crie o namespace para o controlador do roteador do agente do Envoy:

    kubectl create namespace "${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  2. Adicione o imagePullSecret:

    kubectl create secret docker-registry "${GDCS_HARBOR_K8S_PULL_SECRET}" \
    --dry-run=client \
    --from-file=.dockerconfigjson=${GDCS_HARBOR_K8S_DOCKER_CONFIG}/config.json \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}" \
    --output=yaml | kubectl apply -f -
    

Definições de recursos do Kubernetes

  1. Instale os CRDs do roteador de agente do Envoy no gráfico de seed:

    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. Instale os CRDs da extensão de inferência da API Gateway (InferencePool, InferenceObjective) dos manifestos baixados:

    kubectl apply --server-side \
    --filename="${GDCS_IMPLEMENTATION_HOME}/manifests/gateway-api-inference-extension-${GDCS_GATEWAY_API_INFERENCE_EXTENSION_VERSION}.yaml"
    
  3. Verifique se os CRDs estão registrados:

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

    O resultado será o seguinte:

    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

A limitação de taxa baseada em token é aplicada pelo serviço de limitação de taxa do Envoy, que armazena os contadores no Redis. Este guia implanta um Redis de réplica única sem persistência. Um serviço Redis atual pode ser usado mudando o valor de rateLimit.backend.redis.url na próxima seção.

  1. Crie o manifesto para o 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. Aplique o manifesto do Redis Deployment:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/redis.yaml" \
    --namespace="${GDCS_REDIS_NAMESPACE}"
    
  3. Aguarde até que o Redis Deployment esteja disponível:

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

Controlador

  1. Crie o arquivo de valores do Helm para o roteador do agente Envoy:

    cat <<EOF > "${GDCS_IMPLEMENTATION_HOME}/envoy-agent-router-values.yaml" && echo "Successfully created." || echo "Failed to create!"
    controller:
      image:
        repository: ${GDCS_HARBOR_PROJECT_URI}/envoyproxy/ai-gateway-controller
      imagePullSecrets:
        - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    envoyGateway:
      namespace: ${GDCS_ENVOY_GATEWAY_NAMESPACE}
    extProc:
      image:
        repository: ${GDCS_HARBOR_PROJECT_URI}/envoyproxy/ai-gateway-extproc
      imagePullSecrets:
        - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    global:
      imagePullSecrets:
        - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
    EOF
    
  2. Instale o roteador do agente Envoy:

    helm upgrade --install aieg "${GDCS_HARBOR_CHART_OCI_URI}/envoyproxy/ai-gateway-helm" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}" \
    --values="${GDCS_IMPLEMENTATION_HOME}/envoy-agent-router-values.yaml" \
    --version="${GDCS_ENVOY_AGENT_ROUTER_VERSION}"
    
  3. Aguarde até que o controlador do roteador do agente Envoy esteja disponível:

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

Integração do Envoy Gateway

O Envoy Gateway precisa ser reconfigurado para chamar o controlador do roteador do agente Envoy como servidor de extensão, aceitar recursos InferencePool como back-ends e usar o serviço de limitação de taxa com suporte do Redis.

  1. Crie o arquivo de valores do Helm para a integração:

    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. Faça upgrade do Envoy Gateway com os dois arquivos de valores:

    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. Crie o manifesto para o ClusterRole que permite ao controlador do Envoy Gateway monitorar recursos InferencePool. O gráfico não concede essa permissão. Um ClusterRoleBinding separado sobrevive a upgrades do gráfico, ao contrário de um patch do ClusterRole gerenciado pelo gráfico:

    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. Aplique o manifesto para o ClusterRole:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/envoy-gateway-inferencepool-rbac.yaml"
    
  5. Reinicie o controlador do Envoy Gateway para que ele receba a nova configuração e as permissões. Aguarde até que ele esteja disponível:

    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. Verifique se o serviço de limitação de taxa foi implantado e está disponível:

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

Validação

A validação implanta o exemplo básico do roteador de agente do Envoy (um upstream compatível com OpenAI simulado por trás de um AIGatewayRoute) no namespace do roteador de agente do Envoy e o remove depois.

  1. Crie o manifesto para a carga de trabalho de validação:

    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. Aplique o manifesto para a carga de trabalho de validação:

    kubectl apply \
    --filename="${GDCS_IMPLEMENTATION_HOME}/aieg-basic.yaml" \
    --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}"
    
  3. Aguarde até que o Gateway seja programado:

    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. Aguarde até que o upstream simulado Deployment esteja disponível:

    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. Verifique se o proxy Envoy Pod do Gateway executa o sidecar do processador externo injetado pelo roteador do agente do Envoy:

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

    O resultado será o seguinte:

    envoy-envoy-ai-gateway-system-aieg-basic-...   envoy shutdown-manager ai-gateway-extproc
    
  6. Envie uma solicitação de conclusão de chat pelo gateway usando o encaminhamento de porta. O processador externo lê o campo model do corpo da solicitação e o encaminha para o upstream simulado:

    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}
    

    O resultado será o seguinte:

    {
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "..."
          },
          "finish_reason": "stop"
        }
      ],
      "usage": {
        ...
      }
    }
    
  7. Remova a carga de trabalho de validação:

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

Operações

Tarefas do segundo dia para os planos de controle do gateway.

Fazer upgrade

  • Insira as imagens e os gráficos das novas versões (atualize as variáveis de versão em env.sh, execute novamente seed_registry.sh e seed_charts.sh), aplique os novos gráficos do CRD com kubectl apply --server-side e execute os mesmos comandos helm upgrade --install com o novo --version. Confira a matriz de compatibilidade do roteador de agentes do Envoy para as versões do gateway do Envoy e da API Gateway compatíveis com a versão de destino. O roteador de agentes do Envoy 1.1.0 é criado para o gateway do Envoy 1.8.

Desinstalar

  • Exclua primeiro os recursos Gateway, AIGatewayRoute e InferencePool dos guias do usuário e depois helm uninstall aieg --namespace="${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}", helm uninstall eg --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}", o ClusterRole envoy-gateway-inferencepool-reader, o GatewayClass, o Redis Deployment e, por fim, os CRDs.

Solução de problemas

Sintoma Causa provável Ação
helm show chart ou helm upgrade falha com unauthorized ou FetchReference helm não tem credenciais para o Harbor (não usa a configuração do Docker crane). Execute a etapa helm registry login novamente com a conta de robô de extração de imagens do Kubernetes.
O Envoy Gateway ou o roteador do agente Envoy Pods permanecem em ImagePullBackOff A imagem não foi propagada ou o secret de pull da imagem está faltando no namespace Verifique kubectl describe pod, compare o caminho da imagem com crane ls "${GDCS_HARBOR_PROJECT_URI}/envoyproxy/gateway" e verifique se o secret existe em ${GDCS_ENVOY_GATEWAY_NAMESPACE} e ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE}.
Gateway permanece Programmed=False após a integração O controlador do Envoy Gateway não consegue acessar o servidor de extensão ou não foi reiniciado após o upgrade. kubectl logs deployment/envoy-gateway --namespace="${GDCS_ENVOY_GATEWAY_NAMESPACE}"; confirme se service/ai-gateway-controller existe em ${GDCS_ENVOY_AGENT_ROUTER_NAMESPACE} e se a porta 1063 está listada; repita a reinicialização do lançamento.
AIGatewayRoute que faz referência a um InferencePool não é aceito O Envoy Gateway não tem permissão para ler inferencepools ou os CRDs InferencePool estão ausentes. Verifique o ClusterRoleBinding envoy-gateway-inferencepool-reader e o CRD inferencepools.inference.networking.k8s.io. Confira os registros do controlador para forbidden.
A solicitação de conclusão de chat retorna 413 ou a conexão é redefinida para comandos grandes O limite de buffer padrão do Envoy (32 KiB) é muito pequeno para payloads de IA. Anexe um ClientTrafficPolicy com connection.bufferLimit (a validação usa 50 Mi) ao Gateway.
O serviço de limitação de taxa Pod está CrashLoopBackOff Não é possível acessar o Redis no URL configurado kubectl get service redis --namespace="${GDCS_REDIS_NAMESPACE}": corrija rateLimit.backend.redis.url no arquivo de valores de integração e faça upgrade novamente.

Outros materiais