本文档介绍了如何设置 Google Kubernetes Engine (GKE) 多集群推理网关,以在多个 GKE 集群(可以跨不同区域)之间智能地对 AI/机器学习推理工作负载进行负载均衡。此设置使用 Gateway API、多集群 Ingress 和 InferencePool 及 InferenceObjective 等自定义资源来提高可伸缩性,帮助确保高可用性,并优化模型服务部署的资源利用率。
为了理解本文档,请熟悉以下内容:
- GKE 上的 AI/机器学习编排。
- 生成式 AI 术语。
- GKE 网络概念,包括:
- Google Cloud中的负载均衡,尤其是负载平衡器如何与 GKE 交互。
本文档适用于以下角色:
- 希望使用 GKE 的容器编排功能处理 AI/机器学习工作负载的机器学习 (ML) 工程师、平台管理员和运维人员,以及数据和 AI 专家。
- 与 GKE 网络交互的云架构师或网络专家。
如需详细了解我们在Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE Enterprise 用户角色和任务。
准备工作
在开始之前,请确保您已执行以下任务:
- 启用 Google Kubernetes Engine API。 启用 Google Kubernetes Engine API
- 如果您要使用 Google Cloud CLI 执行此任务,请安装并初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请通过运行
gcloud components update命令来获取最新版本。较早版本的 gcloud CLI 可能不支持运行本文档中的命令。
启用 Compute Engine API、Google Kubernetes Engine API、Model Armor 和 Network Services API。
前往启用对 API 的访问,然后按照说明操作。
启用 Autoscaling API。
前往自动扩缩 API,然后按照说明操作。
Hugging Face 前提条件:
- 如果您还没有 Hugging Face 账号,请创建一个。
- 在 Hugging Face 上申请并获得对 Llama 3.1 模型的访问权限。
- 在 Hugging Face 上相应模型的页面上签署许可同意协议。
- 生成至少具有
Read权限的 Hugging Face 访问令牌。
要求
- 确保您的项目具有足够的 H100 GPU 配额。如需了解详情,请参阅规划 GPU 配额和分配配额。
- 使用 GKE 1.34.1-gke.1127000 版或更高版本。
- 使用 gcloud CLI 480.0.0 版或更高版本。
- 您的节点服务账号必须有权向 Autoscaling API 写入指标。
- 您必须拥有项目的以下 IAM 角色:
roles/container.admin和roles/iam.serviceAccountAdmin。
设置多集群推理网关
如需设置 GKE 多集群推理网关,请按以下步骤操作:
创建集群和节点池
如需托管 AI/ML 推理工作负载并启用跨区域负载均衡,请在不同区域中创建两个 GKE 集群,每个集群都包含一个 H100 GPU 节点池。
创建第一个集群:
gcloud container clusters create CLUSTER_1_NAME \ --region LOCATION \ --project=PROJECT_ID \ --gateway-api=standard \ --release-channel "rapid" \ --cluster-version=GKE_VERSION \ --machine-type="MACHINE_TYPE" \ --disk-type="DISK_TYPE" \ --enable-managed-prometheus --monitoring=SYSTEM,DCGM \ --hpa-profile=performance \ --async # Allows the command to return immediately替换以下内容:
CLUSTER_1_NAME:第一个集群的名称,例如gke-west。LOCATION:第一个集群的区域,例如europe-west3。PROJECT_ID:您的项目 ID。GKE_VERSION:要使用的 GKE 版本,例如1.34.1-gke.1127000。MACHINE_TYPE:集群节点的机器类型,例如c2-standard-16。DISK_TYPE:集群节点的磁盘类型,例如pd-standard。
为第一个集群创建 H100 节点池:
gcloud container node-pools create NODE_POOL_NAME \ --accelerator "type=nvidia-h100-80gb,count=2,gpu-driver-version=latest" \ --project=PROJECT_ID \ --location=CLUSTER_1_ZONE \ --node-locations=CLUSTER_1_ZONE \ --cluster=CLUSTER_1_NAME \ --machine-type=NODE_POOL_MACHINE_TYPE \ --num-nodes=NUM_NODES \ --spot \ --async # Allows the command to return immediately替换以下内容:
NODE_POOL_NAME:节点池的名称,例如h100。PROJECT_ID:您的项目 ID。CLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-c。CLUSTER_1_NAME:第一个集群的名称,例如gke-west。NODE_POOL_MACHINE_TYPE:节点池的机器类型,例如a3-highgpu-2g。NUM_NODES:节点池中的节点数,例如3。
获取凭据:
gcloud container clusters get-credentials CLUSTER_1_NAME \ --location CLUSTER_1_ZONE \ --project=PROJECT_ID替换以下内容:
PROJECT_ID:您的项目 ID。CLUSTER_1_NAME:第一个集群的名称,例如gke-west。CLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-c。
在第一个集群上,为 Hugging Face 令牌创建一个 Secret:
kubectl create secret generic hf-token \ --from-literal=token=HF_TOKEN将
HF_TOKEN替换为您的 Hugging Face 访问令牌。在与第一个集群不同的区域中创建第二个集群:
gcloud container clusters create gke-east --region LOCATION \ --project=PROJECT_ID \ --gateway-api=standard \ --release-channel "rapid" \ --cluster-version=GKE_VERSION \ --machine-type="MACHINE_TYPE" \ --disk-type="DISK_TYPE" \ --enable-managed-prometheus \ --monitoring=SYSTEM,DCGM \ --hpa-profile=performance \ --async # Allows the command to return immediately while the cluster is created in the background.替换以下内容:
LOCATION:第二个集群的区域。 此区域必须与第一个集群的区域不同。例如us-east4。PROJECT_ID:您的项目 ID。GKE_VERSION:要使用的 GKE 版本,例如1.34.1-gke.1127000。MACHINE_TYPE:集群节点的机器类型,例如c2-standard-16。DISK_TYPE:集群节点的磁盘类型,例如pd-standard。
为第二个集群创建 H100 节点池:
gcloud container node-pools create h100 \ --accelerator "type=nvidia-h100-80gb,count=2,gpu-driver-version=latest" \ --project=PROJECT_ID \ --location=CLUSTER_2_ZONE \ --node-locations=CLUSTER_2_ZONE \ --cluster=CLUSTER_2_NAME \ --machine-type=NODE_POOL_MACHINE_TYPE \ --num-nodes=NUM_NODES \ --spot \ --async # Allows the command to return immediately替换以下内容:
PROJECT_ID:您的项目 ID。CLUSTER_2_ZONE:第二个集群的可用区,例如us-east4-a。CLUSTER_2_NAME:第二个集群的名称,例如gke-east。NODE_POOL_MACHINE_TYPE:节点池的机器类型,例如a3-highgpu-2g。NUM_NODES:节点池中的节点数,例如3。
对于第二个集群,获取凭据并为 Hugging Face 令牌创建 Secret:
gcloud container clusters get-credentials CLUSTER_2_NAME \ --location CLUSTER_2_ZONE \ --project=PROJECT_ID kubectl create secret generic hf-token --from-literal=token=HF_TOKEN替换以下内容:
CLUSTER_2_NAME:第二个集群的名称,例如gke-east。CLUSTER_2_ZONE:第二个集群的可用区,例如us-east4-a。PROJECT_ID:您的项目 ID。HF_TOKEN:您的 Hugging Face 访问令牌。
将集群注册到舰队
如需启用多集群功能(例如 GKE 多集群推理网关),请将集群注册到舰队。
将这两个集群都注册到项目的舰队:
gcloud container fleet memberships register CLUSTER_1_NAME \ --gke-cluster CLUSTER_1_ZONE/CLUSTER_1_NAME \ --location=global \ --project=PROJECT_ID gcloud container fleet memberships register CLUSTER_2_NAME \ --gke-cluster CLUSTER_2_ZONE/CLUSTER_2_NAME \ --location=global \ --project=PROJECT_ID替换以下内容:
CLUSTER_1_NAME:第一个集群的名称,例如gke-west。CLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-c。PROJECT_ID:您的项目 ID。CLUSTER_2_NAME:第二个集群的名称,例如gke-east。CLUSTER_2_ZONE:第二个集群的可用区,例如us-east4-a。
如需允许单个网关管理多个集群之间的流量,请启用多集群 Ingress 功能并指定配置集群:
gcloud container fleet ingress enable \ --config-membership=projects/PROJECT_ID/locations/global/memberships/CLUSTER_1_NAME替换以下内容:
PROJECT_ID:您的项目 ID。CLUSTER_1_NAME:第一个集群的名称,例如gke-west。
创建代理专用子网
对于内部网关,请在每个区域中创建一个代理专用子网。内部网关的 Envoy 代理使用这些专用子网来处理 VPC 网络内的流量。
在第一个集群的区域中创建子网:
gcloud compute networks subnets create CLUSTER_1_REGION-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=CLUSTER_1_REGION \ --network=default \ --range=10.0.0.0/23 \ --project=PROJECT_ID在第二个集群的区域中创建子网:
gcloud compute networks subnets create CLUSTER_2_REGION-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=CLUSTER_2_REGION \ --network=default \ --range=10.5.0.0/23 \ --project=PROJECT_ID替换以下内容:
PROJECT_ID:您的项目 ID。CLUSTER_1_REGION:第一个集群所在的区域,例如europe-west3。CLUSTER_2_REGION:第二个集群所在的区域,例如us-east4。
安装所需的 CRD
GKE 多集群推理网关使用 InferencePool 和 InferenceObjective 等自定义资源。GKE Gateway API 控制器用于管理 InferencePool 自定义资源定义 (CRD)。不过,您必须在集群上手动安装处于 Alpha 阶段的 InferenceObjective CRD。
为集群定义上下文变量:
CLUSTER1_CONTEXT="gke_PROJECT_ID_CLUSTER_1_ZONE_CLUSTER_1_NAME" CLUSTER2_CONTEXT="gke_PROJECT_ID_CLUSTER_2_ZONE_CLUSTER_2_NAME"替换以下内容:
PROJECT_ID:您的项目 ID。CLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-c。CLUSTER_1_NAME:第一个集群的名称,例如gke-west。CLUSTER_2_ZONE:第二个集群的可用区,例如us-east4-a。CLUSTER_2_NAME:第二个集群的名称,例如gke-east。
在两个集群上安装
InferenceObjectiveCRD:kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/crd/bases/inference.networking.x-k8s.io_inferenceobjectives.yaml --context=CLUSTER1_CONTEXT kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/crd/bases/inference.networking.x-k8s.io_inferenceobjectives.yaml --context=CLUSTER2_CONTEXT替换以下内容:
CLUSTER1_CONTEXT:第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。CLUSTER2_CONTEXT:第二个集群的上下文,例如gke_my-project_us-east4-a_gke-east。
将资源部署到目标集群
为了在每个集群上提供 AI/ML 推理工作负载,请部署所需的资源,例如模型服务器和 InferenceObjective 自定义资源。
将模型服务器部署到这两个集群:
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/manifests/vllm/gpu-deployment.yaml --context=CLUSTER1_CONTEXT kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/v1.1.0/config/manifests/vllm/gpu-deployment.yaml --context=CLUSTER2_CONTEXT替换以下内容:
CLUSTER1_CONTEXT:第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。CLUSTER2_CONTEXT:第二个集群的上下文,例如gke_my-project_us-east4-a_gke-east。
将
InferenceObjective资源部署到这两个集群。将以下示例清单保存到名为inference-objective.yaml的文件中:apiVersion: inference.networking.x-k8s.io/v1alpha2 kind: InferenceObjective metadata: name: food-review spec: priority: 10 poolRef: name: llama3-8b-instruct group: "inference.networking.k8s.io"将清单应用于两个集群:
kubectl apply -f inference-objective.yaml --context=CLUSTER1_CONTEXT kubectl apply -f inference-objective.yaml --context=CLUSTER2_CONTEXT替换以下内容:
CLUSTER1_CONTEXT:第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。CLUSTER2_CONTEXT:第二个集群的上下文,例如gke_my-project_us-east4-a_gke-east。
使用 Helm 将
InferencePool资源部署到这两个集群:helm install vllm-llama3-8b-instruct \ --kube-context CLUSTER1_CONTEXT \ --set inferencePool.modelServers.matchLabels.app=vllm-llama3-8b-instruct \ --set provider.name=gke \ --version v1.1.0 \ oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepoolhelm install vllm-llama3-8b-instruct \ --kube-context CLUSTER2_CONTEXT \ --set inferencePool.modelServers.matchLabels.app=vllm-llama3-8b-instruct \ --set provider.name=gke \ --set inferenceExtension.monitoring.gke.enabled=true \ --version v1.1.0 \ oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool替换以下内容:
CLUSTER1_CONTEXT:第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。CLUSTER2_CONTEXT:第二个集群的上下文,例如gke_my-project_us-east4-a_gke-east。
将
InferencePool资源标记为已在两个集群上导出。此注解使配置集群可以导入InferencePool,这是多集群路由的必要步骤。kubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \ --context=CLUSTER1_CONTEXTkubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \ --context=CLUSTER2_CONTEXT替换以下内容:
CLUSTER1_CONTEXT:第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。CLUSTER2_CONTEXT:第二个集群的上下文,例如gke_my-project_us-east4-a_gke-east。
将资源部署到配置集群
如需定义如何在所有已注册集群中的 InferencePool 资源之间路由流量和进行负载均衡,请部署 Gateway、HTTPRoute 和 HealthCheckPolicy 资源。您仅将这些资源部署到指定的配置集群(本文档中为 gke-west)。
创建一个名为
mcig.yaml的文件,其中包含以下内容:--- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: cross-region-gateway namespace: default spec: gatewayClassName: gke-l7-cross-regional-internal-managed-mc addresses: - type: networking.gke.io/ephemeral-ipv4-address/europe-west3 value: "europe-west3" - type: networking.gke.io/ephemeral-ipv4-address/us-east4 value: "us-east4" listeners: - name: http protocol: HTTP port: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: vllm-llama3-8b-instruct-default spec: parentRefs: - name: cross-region-gateway kind: Gateway rules: - backendRefs: - group: networking.gke.io kind: GCPInferencePoolImport name: vllm-llama3-8b-instruct --- apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: health-check-policy namespace: default spec: targetRef: group: "networking.gke.io" kind: GCPInferencePoolImport name: vllm-llama3-8b-instruct default: config: type: HTTP httpHealthCheck: requestPath: /health port: 8000应用清单:
kubectl apply -f mcig.yaml --context=CLUSTER1_CONTEXT将
CLUSTER1_CONTEXT替换为第一个集群(配置集群)的上下文,例如gke_my-project_europe-west3-c_gke-west。
启用自定义指标报告
为了启用自定义指标报告并改进跨区域负载均衡,您需要从所有集群导出 KV 缓存使用情况指标。负载均衡器使用此导出的 KV 缓存使用情况数据作为自定义负载信号。使用此自定义负载信号可以根据每个集群的实际工作负载做出更智能的负载均衡决策。
创建一个名为
metrics.yaml的文件,其中包含以下内容:apiVersion: autoscaling.gke.io/v1beta1 kind: AutoscalingMetric metadata: name: gpu-cache namespace: default spec: selector: matchLabels: app: vllm-llama3-8b-instruct endpoints: - port: 8000 path: /metrics metrics: - name: vllm:kv_cache_usage_perc # For vLLM versions v0.10.2 and newer exportName: kv-cache - name: vllm:gpu_cache_usage_perc # For vLLM versions v0.6.2 and newer exportName: kv-cache-old将指标配置应用于这两个集群:
kubectl apply -f metrics.yaml --context=CLUSTER1_CONTEXT kubectl apply -f metrics.yaml --context=CLUSTER2_CONTEXT替换以下内容:
CLUSTER1_CONTEXT:第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。CLUSTER2_CONTEXT:第二个集群的上下文,例如gke_my-project_us-east4-a_gke-east。
配置负载均衡政策
如需优化 AI/ML 推理请求在 GKE 集群中的分配方式,请配置负载均衡政策。选择合适的均衡模式有助于确保高效利用资源、防止单个集群过载,并提高推理服务的整体性能和响应速度。
配置超时
如果您的请求预计会持续很长时间,请为负载均衡器配置更长的超时时间。在 GCPBackendPolicy 中,将 timeoutSec 字段设置为至少为估计的 P99 请求延迟时间的两倍。
例如,以下清单将负载均衡器超时时间设置为 100 秒。
apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: my-backend-policy
spec:
targetRef:
group: "networking.gke.io"
kind: GCPInferencePoolImport
name: vllm-llama3-8b-instruct
default:
timeoutSec: 100
balancingMode: CUSTOM_METRICS
trafficDuration: LONG
customMetrics:
- name: gke.named_metrics.kv-cache
dryRun: false
如需了解详情,请参阅多集群网关限制。
由于自定义指标和正在处理的请求数这两种负载均衡模式互斥,因此请在 GCPBackendPolicy 中仅配置其中一种模式。
为部署选择负载均衡模式。
自定义指标
为了实现最佳负载均衡,请从 60% 的目标利用率开始。如需实现此目标,请在 GCPBackendPolicy 的 customMetrics 配置中设置 maxUtilization: 60。
创建一个名为
backend-policy.yaml的文件,其中包含以下内容,以根据kv-cache自定义指标启用负载均衡:apiVersion: networking.gke.io/v1 kind: GCPBackendPolicy metadata: name: my-backend-policy spec: targetRef: group: "networking.gke.io" kind: GCPInferencePoolImport name: vllm-llama3-8b-instruct default: balancingMode: CUSTOM_METRICS trafficDuration: LONG customMetrics: - name: gke.named_metrics.kv-cache dryRun: false maxUtilization: 60应用新政策:
kubectl apply -f backend-policy.yaml --context=CLUSTER1_CONTEXT将
CLUSTER1_CONTEXT替换为第一个集群的上下文,例如gke_my-project-europe-west3-c-gke-west。
正在处理的请求
如需使用动态均衡模式,请估计每个后端可以处理的动态请求数量,并明确配置容量值。
创建一个名为
backend-policy.yaml的文件,其中包含以下内容,以实现基于正在处理的请求数量的负载均衡:kind: GCPBackendPolicy apiVersion: networking.gke.io/v1 metadata: name: my-backend-policy spec: targetRef: group: "networking.gke.io" kind: GCPInferencePoolImport name: vllm-llama3-8b-instruct default: balancingMode: IN_FLIGHT trafficDuration: LONG maxInFlightRequestsPerEndpoint: 1000 dryRun: false应用新政策:
kubectl apply -f backend-policy.yaml --context=CLUSTER1_CONTEXT将
CLUSTER1_CONTEXT替换为第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。
验证 Deployment
如需验证内部负载均衡器,您必须从 VPC 网络内部发送请求,因为内部负载均衡器使用专用 IP 地址。在其中一个集群内运行临时 Pod,以从您的 VPC 网络发送请求并验证内部负载均衡器:
在临时 Pod 中启动交互式 shell 会话:
kubectl run -it --rm --image=curlimages/curl curly --context=CLUSTER1_CONTEXT -- /bin/sh将
CLUSTER1_CONTEXT替换为第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west。在新 shell 中,获取网关 IP 地址并发送测试请求:
GW_IP=$(kubectl get gateway/cross-region-gateway -n default -o jsonpath='{.status.addresses[0].value}') curl -i -X POST ${GW_IP}:80/v1/completions -H 'Content-Type: application/json' -d '{ "model": "food-review-1", "prompt": "What is the best pizza in the world?", "max_tokens": 100, "temperature": 0 }'以下是成功响应的示例:
{ "id": "cmpl-...", "object": "text_completion", "created": 1704067200, "model": "food-review-1", "choices": [ { "text": "The best pizza in the world is subjective, but many argue for Neapolitan pizza...", "index": 0, "logprobs": null, "finish_reason": "length" } ], "usage": { "prompt_tokens": 10, "completion_tokens": 100, "total_tokens": 110 } }
后续步骤
- 详细了解 GKE Gateway API。
- 详细了解 GKE 多集群推理网关。
- 详细了解多集群 Ingress。