本文档介绍如何使用 Google Kubernetes Engine (GKE) 多集群推理网关和 GKE 自动扩缩功能,为 AI 推理工作负载配置弹性跨区域高可用性。通过此设置,您可以智能地对不同区域中的多个 GKE 集群的工作负载进行负载平衡。
如需详细了解 GKE 多集群推理网关, 请参阅 GKE 多集群推理网关简介。
准备工作
启用 Google Kubernetes Engine API。
如果您计划使用 Google Cloud CLI 执行此任务,请安装并初始化该工具。
使用 GKE 1.34.1-gke.1127000 版或更高版本。
使用 gcloud CLI 480.0.0 版或更高版本。
确保节点使用的服务帐号具有
roles/monitoring.metricWriter和roles/stackdriver.resourceMetadata.writer权限。确保您对项目具有
roles/container.admin和roles/iam.serviceAccountAdminIdentity and Access Management (IAM) 角色。完成以下 Hugging Face 前提条件:
- 创建 Hugging Face 账号。
- 在 Hugging Face 上申请并获得 Llama 3.1 模型的访问权限。
- 在 Hugging Face 上模型的页面中签署许可协议。
- 生成至少具有读取权限的 Hugging Face 访问令牌。
创建集群和节点池
如需在不同区域中创建两个 GKE 集群并配置其节点池,请按以下步骤操作:
创建第一个集群:
gcloud container clusters create gke-west --zone \ CLUSTER_1_ZONE \ --project=PROJECT_ID \ --gateway-api=standard \ --cluster-version=GKE_VERSION \ --machine-type="MACHINE_TYPE" \ --disk-type="DISK_TYPE" \ --enable-managed-prometheus --monitoring=SYSTEM,DCGM \ --hpa-profile=performance \ --workload-pool=PROJECT_ID. \ --async替换以下内容:
PROJECT_ID:您的项目 IDCLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-cGKE_VERSION:要使用的 GKE 版本,例如1.34.1-gke.1127000MACHINE_TYPE:集群节点的机器类型,例如c2-standard-16DISK_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_1_ZONE \ --node-locations=CLUSTER_1_ZONE \ --cluster=CLUSTER_1_NAME \ --machine-type=NODE_POOL_MACHINE_TYPE \ --num-nodes=NUM_NODES \ --spot \ --min-nodes=MIN_NUM_NODES \ --max-nodes=MAX_NUM_NODES \ --enable-autoscaling \ --async替换以下内容:
PROJECT_ID:您的项目 IDCLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-cCLUSTER_1_NAME:第一个集群的名称,例如gke-westNODE_POOL_MACHINE_TYPE:节点池的机器类型,例如a3-highgpu-2gNUM_NODES:节点池中的节点数,例如3MIN_NUM_NODES:节点池中自动扩缩的最小节点数,例如1MAX_NUM_NODES:节点池中自动扩缩的最大节点数,例如10
在第一个集群中获取凭据并创建 Hugging Face 令牌 Secret:
gcloud container clusters get-credentials CLUSTER_1_NAME \ --location CLUSTER_1_ZONE \ --project=PROJECT_ID kubectl create secret generic hf-token \ --from-literal=token=HF_TOKEN替换以下内容:
PROJECT_ID:您的项目 IDCLUSTER_1_NAME:第一个集群的名称,例如gke-westCLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-cHF_TOKEN:您的 Hugging Face 访问令牌
在与第一个集群不同的区域中创建第二个集群:
gcloud container clusters create gke-east --zone CLUSTER_2_ZONE \ --project=PROJECT_ID \ --gateway-api=standard \ --cluster-version=GKE_VERSION \ --machine-type="MACHINE_TYPE" \ --disk-type="DISK_TYPE" \ --enable-managed-prometheus \ --monitoring=SYSTEM,DCGM \ --hpa-profile=performance \ --workload-pool=PROJECT_ID. \ --async将
CLUSTER_2_ZONE替换为第二个集群的可用区,例如us-east4-a。为第二个集群创建 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 \ --min-nodes=MIN_NUM_NODES \ --max-nodes=MAX_NUM_NODES \ --enable-autoscaling \ --async替换以下内容:
PROJECT_ID:您的项目 IDCLUSTER_2_ZONE:第二个集群的可用区,例如us-east4-aCLUSTER_2_NAME:第二个集群的名称,例如gke-eastNODE_POOL_MACHINE_TYPE:节点池的机器类型,例如a3-highgpu-2gNUM_NODES:节点池中的节点数,例如3MIN_NUM_NODES:节点池中自动扩缩的最小节点数,例如1MAX_NUM_NODES:节点池中自动扩缩的最大节点数,例如10
在第二个集群中获取凭据并为 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替换以下内容。如需了解其他变量的定义,请参阅前面的步骤:
HF_TOKEN:您的 Hugging Face 访问令牌
将集群注册到舰队
将集群注册到项目的舰队:
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-westCLUSTER_2_NAME:第二个集群的名称,例如gke-east
启用多集群 Ingress 功能并指定配置集群:
gcloud container fleet ingress enable \ --config-membership=projects/PROJECT_ID/locations/global/memberships/CLUSTER_1_NAME替换以下内容。如需了解其他变量的定义,请参阅前面的步骤:
PROJECT_ID:您的项目 IDCLUSTER_1_NAME:第一个集群的名称,例如gke-west
创建代理专用子网
警告 Google Cloud :允许每个 VPC 网络在每个区域中仅有一个
代理专用子网。如果目标区域已包含设置了 purpose=REGIONAL_MANAGED_PROXY 的代理专用子网,则创建 GLOBAL_MANAGED_PROXY 子网会失败。您必须先删除现有的区域级代理专用子网。删除区域级代理专用子网会影响该区域中使用它的任何基于 Envoy 的区域级负载平衡器,因此请相应地规划更改。
在第一个集群的区域中创建子网:
gcloud compute networks subnets create CLUSTER_1_REGION-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=CLUSTER_1_REGION \ --network=default \ --range=SUBNET_RANGE_1 \ --project=PROJECT_ID替换以下内容:
PROJECT_ID:您的项目 IDCLUSTER_1_REGION:第一个集群的区域,例如europe-west3SUBNET_RANGE_1:第一个集群区域中代理专用子网的子网 IP 范围,例如10.0.0.0/23
在第二个集群的区域中创建子网:
gcloud compute networks subnets create CLUSTER_2_REGION-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=CLUSTER_2_REGION \ --network=default \ --range=SUBNET_RANGE_2 \ --project=PROJECT_ID替换以下内容:
PROJECT_ID:您的项目 IDCLUSTER_2_REGION:第二个集群的区域,例如us-east4SUBNET_RANGE_2:第二个集群区域中代理专用子网的子网 IP 范围,例如10.5.0.0/23
安装所需的自定义资源
为集群定义上下文变量:
CLUSTER1_CONTEXT="gke_PROJECT_ID_CLUSTER_1_ZONE_CLUSTER_1_NAME" CLUSTER2_CONTEXT="gke_PROJECT_ID_CLUSTER_2_ZONE_CLUSTER_2_NAME"替换以下内容:
PROJECT_ID:您的项目 IDCLUSTER_1_ZONE:第一个集群的可用区,例如europe-west3-cCLUSTER_1_NAME:第一个集群的名称,例如gke-westCLUSTER_2_ZONE:第二个集群的可用区,例如us-east4-aCLUSTER_2_NAME:第二个集群的名称,例如gke-east
在两个集群上安装 InferencePool 和 InferenceObjective 自定义资源:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/v1.0.1/manifests.yaml --context=$CLUSTER1_CONTEXT kubectl apply -f https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/v1.0.1/manifests.yaml --context=$CLUSTER2_CONTEXT
将资源部署到目标集群
将模型服务器部署到这两个集群:
kubectl apply -f \ https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/release-1.0/config/manifests/vllm/gpu-deployment.yaml \ --context=$CLUSTER1_CONTEXT kubectl apply -f \ https://raw.githubusercontent.com/kubernetes-sigs/gateway-api-inference-extension/release-1.0/config/manifests/vllm/gpu-deployment.yaml \ --context=$CLUSTER2_CONTEXT将以下清单保存到名为
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使用 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 \ --set inferenceExtension.monitoring.gke.enabled=true \ --version v1.0.1 \ oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool helm 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.0.1 \ oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool在这两个集群中,将
InferencePool资源标记为已导出:kubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \ --context=$CLUSTER1_CONTEXT kubectl annotate inferencepool vllm-llama3-8b-instruct networking.gke.io/export="True" \ --context=$CLUSTER2_CONTEXT
部署跨区域推理网关
将以下清单另存为
mygateway.yaml:--- kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 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 allowedRoutes: kinds: - kind: HTTPRoute namespaces: from: All --- apiVersion: gateway.networking.k8s.io/v1beta1 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 --- kind: HealthCheckPolicy apiVersion: networking.gke.io/v1 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 mygateway.yaml --context=CLUSTER1_CONTEXT替换以下内容:
CLUSTER1_CONTEXT:第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west
启用自定义指标报告
创建一个名为
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 exportName: kv-cache - name: vllm:gpu_cache_usage_perc exportName: kv-cache-old对于每个集群,应用指标配置:
kubectl apply -f metrics.yaml --context=CLUSTER1_CONTEXT kubectl apply -f metrics.yaml --context=CLUSTER2_CONTEXT如需了解
CLUSTER1_CONTEXT和CLUSTER2_CONTEXT的定义,请参阅 安装所需的自定义资源。
配置负载均衡政策
本部分介绍如何配置负载均衡政策。此政策定义了如何根据自定义指标和地区偏好设置在推理池之间分配流量。以下配置将 us-east4 设置为首选区域。只有当 us-east4 区域中的 gke.named_metrics.kv-cache 自定义指标的利用率达到 80% 时,流量才会溢出到其他区域。
- 对于 vLLM v0.10.2 及更高版本,请使用
gke.named_metrics.kv-cache指标。 - 对于早期版本,请使用
gke.named_metrics.kv-cache-old指标。
创建一个名为
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: timeoutSec: 600 balancingMode: CUSTOM_METRICS trafficDuration: LONG customMetrics: - name: gke.named_metrics.kv-cache maxUtilizationPercent: 80 dryRun: false scopes: - selector: gke.io/region: "us-east4" backendPreference: PREFERRED应用新政策:
kubectl apply -f backend-policy.yaml --context=CLUSTER1_CONTEXT将
CLUSTER1_CONTEXT替换为第一个集群的上下文,例如gke_my-project_europe-west3-c_gke-west
配置自动扩缩
为了帮助确保每个集群都能处理不断增加的负载,然后再将流量溢出到其他区域,您需要为模型服务器部署配置 Pod 横向自动扩缩器 (HPA)。
主要配置原则
使用相同的自定义指标:应将 HPA 配置为根据您在
GCPBackendPolicy中使用的相同自定义指标(例如vllm:kv_cache_usage_perc)进行伸缩,以用于多集群推理网关。这种方法有助于确保负载均衡和伸缩决策都由推理服务器的同一信号驱动。您选择的指标的值必须介于 0 和 1 之间,以表示利用率。如果指标值大于 1,则负载均衡器会将其解读为 100% 利用率,这可能会导致意外的路由行为。设置较低的 HPA 目标:HPA 配置中指标的目标值必须设置为低于
maxUtilizationPercent设置,该设置定义在GCPBackendPolicy中。通过将 HPA 的目标利用率设置为较低的值(例如,HPA 在平均利用率为 50% 时进行扩缩),您可以让集群在达到负载均衡器的阈值(例如,利用率为 80%)之前添加更多副本。这种方法有助于最大限度地提高首选区域内的容量。较低的利用率目标还有助于防止过早的流量溢出,因为当当前区域真正接近其限制时,它会保留弹性跨区域高可用性。
为您的用户授予创建所需授权角色的权限:
kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin --user "$(gcloud config get-value account)" --context=CLUSTER1_CONTEXT kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin --user "$(gcloud config get-value account)" --context=CLUSTER2_CONTEXTCLUSTER1_CONTEXT和CLUSTER2_CONTEXT变量在 安装所需的自定义资源 部分中定义。对于每个集群,应用清单:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml --context=CLUSTER1_CONTEXT kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml --context=CLUSTER2_CONTEXT允许
custom-metrics-stackdriver-adapter服务帐号读取 Cloud Monitoring 指标:PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)") gcloud projects add-iam-policy-binding projects/PROJECT_ID \ --role roles/monitoring.viewer \ --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID./subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter将
PROJECT_ID替换为您的项目 ID将以下清单保存到名为
pod-monitoring.yaml的文件中:apiVersion: monitoring.googleapis.com/v1 kind: PodMonitoring metadata: name: inference-server-podmon spec: selector: matchLabels: app: vllm-llama3-8b-instruct endpoints: - port: 8000 path: /metrics interval: 5s将清单应用于两个集群:
kubectl apply -f pod-monitoring.yaml --context=CLUSTER1_CONTEXT kubectl apply -f pod-monitoring.yaml --context=CLUSTER2_CONTEXT将以下清单保存到名为
hpa.yaml的文件中:apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: inference-server-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: vllm-llama3-8b-instruct minReplicas: 1 maxReplicas: 10 metrics: - type: Pods pods: metric: name: prometheus.googleapis.com|vllm:gpu_cache_usage_perc|gauge target: type: AverageValue averageValue: "0.5"将清单应用于两个集群:
kubectl apply -f hpa.yaml --context=CLUSTER1_CONTEXT kubectl apply -f hpa.yaml --context=CLUSTER2_CONTEXT
验证 Deployment
获取网关 IP 地址:
export GW_IP=$(kubectl get gateway/cross-region-gateway -n default --context=CLUSTER1_CONTEXT -o jsonpath='{.status.addresses[0].value}') echo ${GW_IP}CLUSTER1_CONTEXT变量在 安装所需的自定义资源部分中定义。在临时 Pod 中启动交互式
sh会话:kubectl run -it --rm --image=curlimages/curl curly --context=CLUSTER1_CONTEXT -- /bin/shCLUSTER1_CONTEXT变量在 安装所需的自定义资源部分中定义。在
curlyPod 中,发送测试请求:curl -i -X POST <var>GW_IP</var>: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 }'将
GW_IP替换为上一步中的网关 IP 地址。
对网关执行负载测试
使用同一 VPC 网络中的负载生成器,对网关 IP 地址应用持续负载。
首先使用您预计首选区域 (
us-east4) 可以处理的适中负载。逐渐提高负载测试的请求速率或并发数。
在负载测试运行时,在 Google Cloud 控制台中或 使用
kubectl监控系统:- Pod 伸缩 (HPA):检查两个集群中
vllm-llama3-8b-instructDeployment 中的 Pod 数量。 - 节点伸缩(集群自动伸缩器):监控两个集群中
h100节点池中的节点数。 - 自定义指标:在 Monitoring 中监控两个集群中模型服务器部署的
vllm:kv_cache_usage_perc指标(适用于 vllm v0.10.2 及更高版本)或vllm:gpu_cache_usage_perc指标(适用于 vllm 版本低于 v.0.10.2)。 - 负载平衡器指标:检查 Monitoring 中与
cross-region-gateway关联的负载平衡器 的指标。
- Pod 伸缩 (HPA):检查两个集群中
随着负载的增加,us-east4 中的利用率也会增加。当 gke-east 集群中的 HPA 横向扩容,并且平均利用率接近 GCPBackendPolicy 中定义的 maxUtilization 值 (80%) 时,负载平衡器会开始将请求路由到 europe-west3 中的 gke-west 集群。
后续步骤
- 详细了解 GKE Gateway API。
- 详细了解 GKE 多集群推理网关。
- 详细了解多集群 Ingress。