使用 GKE 推理网关提供 LLM

本���程介绍如何使用 GKE 推理网关在 Google Kubernetes Engine (GKE) 上部署大语言模型 (LLM)。本教程包含集群设置、模型部署、GKE Inference Gateway 配置和处理 LLM 请求的步骤。

本教程适用于机器学习 (ML) 工程师、平台管理员和运维人员,以及希望使用 GKE 推理网关在 GKE 上部署和管理 LLM 应用的数据和 AI 专家。

在阅读本页面之前,请确保您熟悉以下内容:

GKE Inference Gateway 在 Google Kubernetes Engine (GKE) 网关的基础上进行了增强,可优化 GKE 上生成式 AI 应用和工作负载的服务。它可高效管理和扩缩 AI 工作负载,实现工作负载特定的性能目标(例如延迟时间),并提高资源利用率、可观测性和 AI 安全性。

准备工作

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装并初始化 gcloud CLI。如果您之前安装了 gcloud CLI,请通过运行 gcloud components update 命令来获取最新版本。较早版本的 gcloud CLI 可能不支持运行本文档中的命令。
  • 根据需要启用 Compute Engine API、Kubernetes Engine API、Network Services API 和 Model Armor API。

    前往启用对 API 的访问,然后按照说明操作。

  • 确保您在项目中拥有以下角色:roles/container.admin、roles/iam.serviceAccountAdmin。

  • 确保您的项目具有足够的 H100 GPU 配额。如需了解详情,请参阅规划 GPU 配额和分配配额。

  • 如果您还没有 Hugging Face 账号,请创建一个。您需要此账号才能访问本教程的模型资源。

  • 申请 Llama 3.1 模型的使用权限,并生成访问令牌。访问此模型需要在 Hugging Face 上获得批准的请求,如果未获得访问权限,部署将会失败。

    • 签署许可同意协议:您必须签署同意协议,才能使用 Llama 3.1 模型。前往 Hugging Face 上的模型页面,验证您的账号,然后接受相关条款。
    • 生成访问令牌:如需访问模型,您需要一个 Hugging Face 令牌。在您的 Hugging Face 账号中,依次前往您的个人资料 > 设置 > 访问令牌,创建一个至少具有读取权限的新令牌,然后将其复制到剪贴板。
  • 为您的 VPC 网络配置代理专用子网。网关控制器需要区域中的有效代理专用子网才能预配应用负载均衡器。

GKE Gateway Controller 要求

  • GKE 1.32.3 版或更高版本。
  • Google Cloud CLI 407.0.0 版或更高版本。
  • Gateway API 仅支持在 VPC 原生集群上使用。
  • 集群必须启用 HttpLoadBalancing 插件。
  • 如果您使用的是 Istio,则必须将 Istio 升级到以下版本之一:
    • 1.15.2 或更高版本
    • 1.14.5 或更高版本
    • 1.13.9 或更高版本
  • 如果您使用的是共享 VPC,则需要在宿主项目中将 Compute Network User 角色分配给服务项目的 GKE 服务账号。

限制和局限

有以下限制和局限:

  • GKE Inference Gateway 仅支持 gke-l7-regional-external-managed 和 gke-l7-rilb GatewayClass 资源。
  • 不支持跨区域内部应用负载均衡器。
  • 一个 InferencePool 最多可以有 8 个 targetPorts。

配置 GKE Inference Gateway

如需配置 GKE Inference Gateway,请参考以下示例。假设一个团队运行 vLLM 和 Llama3 模型,并在尝试使用如下两个不同的 LoRA 微调适配器的效果:“food-review”和“cad-fabricator”。

配置 GKE Inference Gateway 的高级工作流如下:

  1. 准备环境:设置必要的基础设施和组件。
  2. 创建推理池:使用 InferencePool 自定义资源定义模型服务器池。
  3. 指定推理目标:使用 InferenceObjective 自定义资源指定推理目标
  4. 创建网关:使用 Gateway API 公开推理服务。
  5. 创建 HTTPRoute:定义 HTTP 流量路由到推理服务的方式。
  6. 发送推理请求:向已部署的模型发送请求。

创建网关

网关资源是外部流量进入 Kubernetes 集群的入口点。它定义用于接受传入连接的监听器。

GKE 推理网关可与以下网关类搭配使用:

  • gke-l7-rilb:对于区域级内部应用负载均衡器。
  • gke-l7-regional-external-managed:对于区域级外部应用负载均衡器。

如需了解详情,请参阅网关类文档。

如需创建网关,请执行以下步骤:

  1. 将以下示例清单保存为 gateway.yaml:

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: GATEWAY_NAME
    spec:
      gatewayClassName: GATEWAY_CLASS
      listeners:
        - protocol: HTTP
          port: 80
          name: http
    

    替换以下内容:

    • GATEWAY_NAME:网关资源的唯一名称。例如 inference-gateway。
    • GATEWAY_CLASS:您要使用的网关类。 例如 gke-l7-regional-external-managed。
  2. 将清单应用到您的集群:

    kubectl apply -f gateway.yaml
    

注意:如需详细了解如何配置 TLS 以使用 HTTPS 保护网关,请参阅 GKE 文档中的 TLS 配置。

准备环境

  1. 安装 Helm。

  2. 创建 GKE 集群:

    • 创建 1.32.3 版或更高版本的 GKE Autopilot 或 Standard 集群。如需查看一键式部署参考设置,请参阅 cluster-toolkit gke-a3-highgpu 示例。
    • 使用您偏好的计算机器家族和加速器配置节点。
    • 使用 GKE 推理快速入门,获取基于您选择的加速器、模型和性能需求的预配置且经过测试的部署清单。
  3. 在 GKE 集群中安装所需的自定义资源定义 (CRD):

    • 对于 GKE 1.34.0-gke.1626000 版或更高版本,默认情况下会包含 InferencePool CRD。因此,您只需安装 Alpha 版 InferenceObjective CRD:

      kubectl apply -f https://github.com/kubernetes-sigs/gateway-api-inference-extension/raw/v1.5.0/config/crd/bases/inference.networking.x-k8s.io_inferenceobjectives.yaml
      
    • 对于 1.34.0-gke.1626000 版之前的 GKE 版本,请安装 v1 InferencePool 和 Alpha 版 InferenceObjective CRD:

      kubectl apply -f  https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/v1.5.0/manifests.yaml
      

      如需了解详情,请参阅兼容性矩阵。

  4. 如果您使用的 GKE 版本低于 v1.32.2-gke.1182001,并且想要将 Model Armor 与 GKE Inference Gateway 搭配使用,则必须安装流量和路由扩展 CRD:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-gateway-api/refs/heads/main/config/crd/networking.gke.io_gcptrafficextensions.yaml
    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-gateway-api/refs/heads/main/config/crd/networking.gke.io_gcproutingextensions.yaml
    
  5. 设置以下环境变量:

    export GAIE_VERSION=v1.5.0
    export GUIDE_NAME="optimized-baseline"
    export NAMESPACE=llm-d-optimized-baseline
    export INFRA_PROVIDER=gke   # gke | base
    
  6. 安装 llm-d 端点选择器 (EPP) 所需的 Gateway API 推理扩展程序自定义资源定义 (CRD):

    kubectl apply -k \
      "https://github.com/kubernetes-sigs/gateway-api-inference-extension/config/crd?ref=${GAIE_VERSION}"
    
  7. 创建目标命名空间:

    kubectl create namespace ${NAMESPACE}
    

创建模型服务器和模型部署

本部分介绍如何部署模型服务器和模型。此示例使用提供 Llama3 模型的 vLLM 模型服务器。相应部署将被标记为 app:vllm-llama3-8b-instruct。此部署还使用了 Hugging Face 中的两个名为 food-review 和 cad-fabricator 的 LoRA 适配器。

您可以根据自己的模型服务器容器和模型、服务端口以及部署名称来调整此示例。您还可以在部署中配置 LoRA 适配器,或部署基础模型。以下步骤介绍如何创建必要的 Kubernetes 资源。

  1. 创建一个 Kubernetes Secret 来存储您的 Hugging Face 令牌。此令牌用于访问基础模型和 LoRA 适配器:

    kubectl create secret generic hf-token --from-literal=token=HF_TOKEN
    

    将 HF_TOKEN 替换为您的 Hugging Face 令牌。

  2. 使用 llm-d 优化基准指南中的 GKE 特定 Kustomize 叠加层部署 vLLM 模型服务器。设置 INFRA_PROVIDER=gke 会应用特定于 GKE 的配置,包括 Cloud Monitoring 集成:

    kubectl apply -n ${NAMESPACE} \
      -k guides/${GUIDE_NAME}/modelserver/gpu/vllm/${INFRA_PROVIDER}/
    

注意:GKE 默认提供自动应用监控。GKE 不需要 llm-d 监控堆栈,但如果您愿意,也可以使用它。

如果模型服务器需要多个端口,请确保容器规范公开每个端口。以下示例定义了一个 Deployment,其中容器公开了三个端口:

多端口部署示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: multiport-model-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: multiport-model-server
  template:
    metadata:
      labels:
        app: multiport-model-server
    spec:
      containers:
      - name: model-server
        image: your-model-server-image
        ports:
        - containerPort: 8080
        - containerPort: 8081
        - containerPort: 9000

创建推理池

InferencePool Kubernetes 自定义资源定义了一组采用相同的基础大语言模型 (LLM) 和计算配置的 Pod。selector 字段指定此池包含的 Pod。此选择器中的标签必须与应用于模型服务器 Pod 的标签完全一致。targetPorts 字段定义模型服务器在 Pod 内使用的端口。您最多可以指定 8 个端口。extensionRef 字段引用可为推理池提供额外功能的扩展服务。InferencePool 使 GKE Inference Gateway 能够将流量路由到模型服务器 Pod。

以下 InferencePool 清单指定了多个与模型服务器 Deployment 公开的端口相对应的 targetPort:

多端口 InferencePool 示例

apiVersion: inference.networking.k8s.io/v1
kind: InferencePool
metadata:
  name: my-multiport-pool
  namespace: default
spec:
  selector:
    matchLabels:
      app: multiport-model-server
  targetPorts:
    - number: 8080
    - number: 8081
    - number: 9000

在创建 InferencePool 之前,请确保 InferencePool 选择的模型服务器 Pod 已在运行。

从 llm-d GitHub 代码库克隆 InferencePool 的配方和建议。此步骤为必需步骤:

git clone https://github.com/llm-d/llm-d -b v0.7.0 && cd llm-d

如需使用 Helm 创建 InferencePool 和 Endpoint Picker,请执行以下步骤:

helm install ${GUIDE_NAME} \
  -f guides/recipes/scheduler/base.values.yaml \
  -f guides/${GUIDE_NAME}/scheduler/${GUIDE_NAME}.values.yaml \
  --set provider.name=gke \
  --set inferenceExtension.monitoring.gke.enabled=true \
  -n ${NAMESPACE} \
  --version ${GAIE_VERSION} \
  oci://LLM_D_REGISTRY_PATH

替换以下内容:

  • GAIE_VERSION:Helm 图表的版本。例如 v1.5.0。
  • LLM_D_REGISTRY_PATH:Helm 图表的 OCI 注册表路径。例如 registry.k8s.io/gateway-api-inference-extension/charts/inferencepool。

在 guides/recipes/scheduler/base.values.yaml 文件中,更改以下字段以与模型部署 Pod 的标签相符:

  • inferencePool.modelServers.matchLabels:用于选择模型服务器 Pod 的标签的键和值。

    注意:键和值与 optimized-baseline 指南示例一致,因此我们将其替换为与您的部署 Pod 标签匹配。

对于监控,Google Cloud Managed Service for Prometheus 的指标抓取功能默认处于启用状态。

  • 如需停用此功能,请向命令添加 --set inferenceExtension.monitoring.prometheus.enabled=false 标志。
  • 如果您在 GKE Autopilot 集群中使用默认监控,还必须添加 --set provider.gke.autopilot=true 标志。

Helm 安装程序会自动安装必要的超时政策、端点选择器以及所需的 Pod,以便实现可观测性。

这会创建一个 InferencePool 对象:其中 vllm-llama3-8b-instruct 引用 Pod 内的模型端点服务。它还会为创建的 InferencePool 创建一个名为 app:vllm-llama3-8b-instruct-epp 的端点选择器 Deployment。

部署具有高可用性的端点选择器

部署具有首选后端的端点选择器 (EPP) 可实现由 Cloud Load Balancing 支持的主动-被动路由拓扑。

将端点选择器与首选后端搭配使用有助于您实现以下目标:

  • 状态一致性:Cloud Load Balancing 会��� 100% 的稳态 ext_proc 流量定向到主端点选择器副本 (epp-0),从而保留键值对 (KV) 缓存状态和请求调度上下文。
  • 零停机时间故障切换:如果主 Endpoint Picker Pod 崩溃或正在维护,Cloud Load Balancing 会使用主动 gRPC 健康检查检测到故障,并立即将流量路由到备用副本 (epp-1)。
  • 应急开启弹性:与 failureMode: FailOpen 搭配使用时,短暂的路由失败会绕过端点选择器,并允许请求直接转发到模型服务器,而不会丢弃用户请求。

启用首选后端后,GKE 会通过以下方式修改架构和路由:

  • 端点选择器 StatefulSet 架构:端点选择器部署为 StatefulSet 而不是 Deployment。Pod 序号用于指定副本角色:序号 epp-0 用作固定到 PREFERRED 后端层的主副本,序号 epp-1 用作固定到 DEFAULT 层的备用副本。
  • 路由状态保持集中:稳态 ext_proc 流量仅路由到主端点选择器副本 (epp-0),以保持键值对 (KV) 缓存跟踪和请求调度状态集中化。如果 epp-0 健康状况不佳,Cloud Load Balancing 会将流量转移到备用副本 (epp-1)。
  • 双服务架构:Helm 图表会创建一个主服务 (Service/${GUIDE_NAME}-epp) 和一个备用备份服务 (Service/${GUIDE_NAME}-epp-backup)。InferencePool 资源以声明方式定位备用备份服务。将声明性网关所有权锚定到备用服务可确保 GKE 网关控制器协调循环不会分离您附加到后端服务的主要网络端点组 (NEG)。

如需使用 Helm 创建具有高可用性的 InferencePool 和 Endpoint Picker,请执行以下步骤:

  1. 使用 Helm 部署具有首选后端的 InferencePool 和端点选择器:

    helm install ${GUIDE_NAME} \
      -f guides/recipes/scheduler/base.values.yaml \
      -f guides/${GUIDE_NAME}/scheduler/${GUIDE_NAME}.values.yaml \
      --set provider.name=gke \
      --set inferenceExtension.monitoring.gke.enabled=true \
      --set provider.gke.preferredBackends.enabled=true \
      --set provider.gke.preferredBackends.preferredReplicas=1 \
      --set provider.gke.preferredBackends.defaultReplicas=1 \
      -n ${NAMESPACE} \
      --version ${GAIE_VERSION} \
      oci://LLM_D_REGISTRY_PATH
    

    替换以下内容:

    • GAIE_VERSION:Helm 图表的 Gateway API 推理扩展程序 (GAIE) 版本。例如 v1.5.0。首选后端需要 Helm 图表版本 v1.5.0 或更高版本。
    • LLM_D_REGISTRY_PATH:Helm 图表的 OCI 注册表路径。例如 registry.k8s.io/gateway-api-inference-extension/charts/inferencepool。

    如需查看完整的参数列表,请参阅 values.yaml。

  2. 将主 NEG 附加到 BackendService:

    export PROJECT_ID=PROJECT_ID
    export REGION=REGION
    
    export BACKEND_SERVICE=$(gcloud compute backend-services list --project=${PROJECT_ID} --format="value(name)" | grep "${GUIDE_NAME}-epp")
    
    export PRIMARY_NEG=$(kubectl get svc ${GUIDE_NAME}-epp -n ${NAMESPACE} -o jsonpath='{.metadata.annotations.cloud\.google\.com/neg-status}' | jq -r '.network_endpoint_groups["9002"]')
    
    for ZONE in $(kubectl get svc ${GUIDE_NAME}-epp -n ${NAMESPACE} -o jsonpath='{.metadata.annotations.cloud\.google\.com/neg-status}' | jq -r '.zones[]'); do
      gcloud compute backend-services add-backend ${BACKEND_SERVICE} \
        --network-endpoint-group=${PRIMARY_NEG} \
        --network-endpoint-group-zone=${ZONE} \
        --region=${REGION} \
        --project=${PROJECT_ID} \
        --balancing-mode=RATE \
        --max-rate-per-endpoint=100 \
        --preference=PREFERRED
      sleep 15
    done
    

    替换以下内容:

    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • REGION:集群和后端服务的 Google Cloud 区域。

将可用区级 NEG 附加到 Google Cloud BackendService 后,伸缩副本数量(preferredReplicas 或 defaultReplicas)或重启 Pod 无需再次运行 gcloud 命令。GKE NEG 控制器会自动将各个 Pod IP 地址同步到已注册的可用区级 NEG。

如果您删除并重新创建父 Gateway 或 InferencePool 资源,GKE Gateway 控制器会使用新的云标识符重新创建底层 Google Cloud BackendService。在这种情况下,请执行上述连接工作流程,将主要可用区级 NEG 连接到新创建的 BackendService。

创建 HTTPRoute

HTTPRoute 资源定义 GKE 网关如何将传入的 HTTP 请求路由到后端服务,例如您的 InferencePool。HTTPRoute 资源指定匹配规则(例如,标头或路径)以及应将流量转发到的后端。

  1. 如需创建 HTTPRoute,请将以下示例清单保存为 httproute.yaml:

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: HTTPROUTE_NAME
    spec:
      parentRefs:
      - name: GATEWAY_NAME
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: PATH_PREFIX
        backendRefs:
        - name: INFERENCE_POOL_NAME
          group: "inference.networking.k8s.io"
          kind: InferencePool
    

    替换以下内容:

    • HTTPROUTE_NAME:HTTPRoute 资源的唯一名称。例如 my-route。
    • GATEWAY_NAME:您创建的 Gateway 资源的名称。例如 inference-gateway。
    • PATH_PREFIX:用于匹配传入请求的路径前缀。例如,/ 可匹配所有路径。
    • INFERENCE_POOL_NAME:要将流量路由到的 InferencePool 资源的名称。例如 vllm-llama3-8b-instruct。
  2. 将清单应用到您的集群:

    kubectl apply -f httproute.yaml
    

指定推理目标

通过 InferenceObjective 自定义资源,可让您指定请求的优先级。

InferenceObjective 资源的 metadata.name 字段指定推理目标名称,Priority 字段指定其服务重要性,poolRef 字段指定模型所部署的 InferencePool。

apiVersion: inference.networking.x-k8s.io/v1alpha2
kind: InferenceObjective
metadata:
  name: NAME
spec:
  priority: VALUE
  poolRef:
    name: INFERENCE_POOL_NAME
    group: "inference.networking.k8s.io"

替换以下内容:

  • NAME:推理目标的名称。例如 food-review。
  • VALUE:推理目标的优先级。这是一个整数,值越大表示请求越重要。例如,10。
  • INFERENCE_POOL_NAME:您在上一步中创建的 InferencePool 的名称。例如 vllm-llama3-8b-instruct。

如需创建 InferenceObjective,请执行以下步骤:

  1. 将以下清单保存为 inference-objectives.yaml。此清单会创建两个 InferenceObjective 资源。第一个对象在 vllm-llama3-8b-instruct InferencePool 上配置 food-review 推理目标,优先级为 10。第二个对象将 llama3-base-model 推理目标配置为以更高的优先级(即 20)部署。

    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceObjective
    metadata:
      name: food-review
    spec:
      priority: 10
      poolRef:
        name: vllm-llama3-8b-instruct
        group: "inference.networking.k8s.io"
    ---
    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceObjective
    metadata:
      name: llama3-base-model
    spec:
      priority: 20 # Higher priority
      poolRef:
        name: vllm-llama3-8b-instruct
    
  2. 将示例清单应用于集群:

    kubectl apply -f inference-objectives.yaml
    

验证 Deployment

如需验证所有组件是否都在运行,请运行以下命令:

kubectl get inferencepool
kubectl get inferenceobjective
kubectl get pods -l app=vllm-llama3-8b-instruct-epp

发送推理请求

配置 GKE Inference Gateway 后,您便可以向已部署的模型发送推理请求。这样一来,您就可以根据输入提示和指定参数生成文本。

如需发送推理请求,请执行以下步骤:

  1. 设置以下环境变量:

    export GATEWAY_NAME=GATEWAY_NAME
    export PORT_NUMBER=PORT_NUMBER # Use 80 for HTTP
    

    替换以下内容:

    • GATEWAY_NAME:网关资源的名称。
    • PORT_NUMBER:您在网关中配置的端口号。
  2. 如需获取网关端点,请运行以下命令:

    echo "Waiting for the Gateway IP address..."
    IP=""
    while [ -z "$IP" ]; do
      IP=$(kubectl get gateway/${GATEWAY_NAME} -o jsonpath='{.status.addresses[0].value}' 2>/dev/null)
      if [ -z "$IP" ]; then
        echo "Gateway IP not found, waiting 5 seconds..."
        sleep 5
      fi
    done
    
    echo "Gateway IP address is: $IP"
    PORT=${PORT_NUMBER}
    
  3. 如需使用 curl 向 /v1/completions 端点发送请求,请运行以下命令:

    curl -i -X POST ${IP}:${PORT}/v1/completions \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer $(gcloud auth application-default print-access-token)' \
    -d '{
        "model": "MODEL_NAME",
        "prompt": "PROMPT_TEXT",
        "max_tokens": MAX_TOKENS,
        "temperature": "TEMPERATURE"
    }'
    

    替换以下内容:

    • MODEL_NAME:要使用的模型或 LoRA 适配器的名称。
    • PROMPT_TEXT:模型的输入提示。
    • MAX_TOKENS:回答中可生成的 token 数量上限。
    • TEMPERATURE:控制输出的随机性。使用值 0 可获得确定性输出,使用更高的值则可获得更具创造性的输出。

以下示例展示了如何向 GKE 推理网关发送示例请求:

curl -i -X POST ${IP}:${PORT}/v1/completions -H 'Content-Type: application/json' -H 'Authorization: Bearer $(gcloud auth application-default print-access-token)' -d '{
    "model": "food-review-1",
    "prompt": "What is the best pizza in the world?",
    "max_tokens": 2048,
    "temperature": 0
}'

请注意以下事项:

  • 请求正文:请求正文可以包含其他参数,例如 stop 和 top_p。如需查看完整的选项列表,请参阅 OpenAI API 规范。
  • 错误处理:在客户端代码中实现适当的错误处理,以处理响应中可能出现的错误。例如,检查 curl 响应中的 HTTP 状态代码。非 200 状态代码通常表示错误。
  • 身份验证和授权:对于生产部署,请使用身份验证和授权机制保护您的 API 端点。在请求中添加相应的标头(例如 Authorization)。

后续步骤