本文档介绍了如何使用 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.s3ns.svc.id.goog \ --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.s3ns.svc.id.goog \ --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
创建代理专用子网
警告: Cloud de Confiance by S3NS 允许每个 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 配置中指标的目标值必须设置为低于
GCPBackendPolicy中定义的maxUtilizationPercent设置。通过将 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.s3ns.svc.id.goog/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) 可以处理的中等负载。逐步提高负载测试的请求速率或并发数。
在运行负载测试期间,在 Cloud de Confiance 控制台中或使用
kubectl监控系统:- Pod 伸缩 (HPA):检查两个集群中
vllm-llama3-8b-instructDeployment 中的 Pod 数量。 - 节点伸缩(集群自动伸缩器):监控两个集群中
h100节点池的节点数量。 - 自定义指标:在监控中,观察两个集群中模型服务器部署的
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。