本教程介绍了如何使用 KEDA 将 GKE 工作负载缩减为零个 Pod。将部署缩放为零个 Pod 可在无活动期间(例如周末和非办公时间)或针对间歇性工作负载(例如定期作业)节省资源。
目标
本教程介绍了以下用例:
- 将 Pub/Sub 工作负载缩放为零:将 Pod 数量按 Pub/Sub 主题中队列消息的数量进行缩放。当队列为空时,工作负载会自动缩减到零个 Pod。
- 将 LLM 工作负载缩放为零。在具有 GPU 的节点上部署 LLM 模型服务器。当服务处于空闲状态时,工作负载会自动缩减到零个 Pod。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
- GKE
- GPU resources used by GKE
- Pub/Sub
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
在本教程中,您将使用 Cloud Shell 运行命令。Cloud Shell 是一种 shell 环境,用于管理托管在 Google Cloud上的资源。它预装了 Google Cloud CLI、kubectl、Helm 和 Terraform 命令行工具。如果您不使用 Cloud Shell,则必须安装 Google Cloud CLI 和 Helm。
-
如需运行此页面中的命令,请在以下开发环境之一中设置 gcloud CLI:
Cloud Shell
如需使用已设置 gcloud CLI 的在线终端,请激活 Cloud Shell:
Cloud Shell 会话会在页面底部启动,并显示命令行提示符。该会话可能需要几秒钟来完成初始化。
本地 shell
如需使用本地开发环境,请按照以下步骤操作:
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.
设置您的环境
如需使用 Cloud Shell 设置您的环境,请按照以下步骤操作:
设置环境变量:
export PROJECT_ID=PROJECT_ID export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)') export LOCATION=LOCATION
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID,并将LOCATION
替换为应创建 GKE 集群的区域或可用区。如果您未在单次会话中完成本教程,或者您的环境变量因某种原因而未设置,请务必再次运行此命令以重新设置变量。
创建已启用集群自动扩缩和适用于 GKE 的工作负载身份联合的 Standard GKE 集群:
gcloud container clusters create scale-to-zero \ --project=${PROJECT_ID} --location=${LOCATION} \ --machine-type=n1-standard-2 \ --enable-autoscaling --min-nodes=1 --max-nodes=5 \ --workload-pool=${PROJECT_ID}.svc.id.goog
安装 KEDA
KEDA 是 Kubernetes 横向 Pod 自动扩缩器的补充组件。借助 KEDA,您可以将 Deployment 缩减到零个 Pod,也可以从零个 Pod 扩容到一个 Pod。Deployment 是一种 Kubernetes API 对象,可让您运行分布在集群节点中的 Pod 的多个副本。GKE 创建至少一个 Pod 后,系统会应用标准的水平 Pod 自动扩缩器算法。
在 GKE 将部署扩缩为零个 Pod 后,由于没有任何 Pod 在运行,因此自动扩缩无法依赖于 CPU 利用率等 Pod 指标。因此,KEDA 允许使用 Kubernetes External Metrics API 实现提取来自集群外部的指标。您可以使用此 API 根据 Pub/Sub 订阅中的待处理消息数量等指标进行自动扩缩。如需查看所有受支持的指标来源的列表,请参阅 KEDA 文档。
使用 Helm 或 kubectl
在集群上安装 KEDA。
Helm
运行以下命令以添加 KEDA Helm 代码库、安装 KEDA Helm 图表,并向 KEDA 服务账号授予对 Cloud Monitoring 的读取权限:
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --create-namespace --namespace keda
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}.svc.id.goog/subject/ns/keda/sa/keda-operator
请注意,此命令还会设置授权规则,这些规则要求集群必须使用适用于 GKE 的工作负载身份联合进行设置。
kubectl
运行以下命令,使用 kubectl apply
安装 KEDA,并向 KEDA 服务账号授予对 Cloud Monitoring 的读取权限:
kubectl apply --server-side -f https://github.com/kedacore/keda/releases/download/v2.15.1/keda-2.15.1.yaml
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}.svc.id.goog/subject/ns/keda/sa/keda-operator
请注意,此命令还会设置授权规则,这些规则要求集群必须使用适用于 GKE 的工作负载身份联合进行设置。
确认所有 KEDA 资源都显示在 keda
命名空间下:
kubectl get all -n keda
如需详细了解 KEDA 设计和资源,请参阅 KEDA 文档。
将 Pub/Sub 工作负载缩减为零
本部分介绍了一种工作负载,用于处理来自 Pub/Sub 订阅的消息,处理每条消息并确认其完成。工作负载会动态扩缩:随着未确认消息数量的增加,自动扩缩功能会实例化更多 Pod 以确保及时处理。
缩减到零可确保在长时间内未收到任何消息时不会实例化任何 Pod。这样可以节省资源,因为没有 Pod 会长时间处于空闲状态。
部署 Pub/Sub 工作负载
部署一个示例工作负载,用于处理在 Pub/Sub 主题中加入队列的消息。为了模拟真实的工作负载,此示例程序会等待 3 秒钟,然后才确认消息。工作负载配置为在 keda-pubsub-sa
服务账号下运行。
运行以下命令以创建 Pub/Sub 主题和订阅、配置其权限,并在 keda-pubub
命名空间下创建用于启动工作负载的部署。
gcloud pubsub topics create keda-echo
gcloud pubsub subscriptions create keda-echo-read --topic=keda-echo
gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
--role=roles/pubsub.subscriber \
--member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda-pubsub/sa/keda-pubsub-sa
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-with-workload-identity.yaml
配置缩减至零
如需将 Pub/Sub 工作负载配置为缩减为零,请使用 KEDA 定义 ScaledObject
资源,以指定部署应如何扩缩。然后,KEDA 会自动创建和管理底层 HorizontalPodAutoscaler
(HPA) 对象。
创建
ScaledObject
资源来描述预期的自动扩缩行为:curl https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-scaledobject.yaml | envsubst | kubectl apply -f -
这会创建以下对象:
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: keda-pubsub namespace: keda-pubsub spec: maxReplicaCount: 5 scaleTargetRef: name: keda-pubsub triggers: - type: gcp-pubsub authenticationRef: name: keda-auth metadata: subscriptionName: "projects/${PROJECT_ID}/subscriptions/keda-echo-read"
检查 KEDA 基于
ScaledObject
对象创建的HorizontalPodAutoscaler
(HPA) 对象:kubectl get hpa keda-hpa-keda-pubsub -n keda-pubsub -o yaml
您可以在 Kubernetes 文档中详细了解自动扩缩。
等待 KEDA 确认 Pub/Sub 订阅为空,并将部署扩缩为零个副本。
检查工作负载自动扩缩器:
kubectl describe hpa keda-hpa-keda-pubsub -n keda-pubsub
请注意,在命令响应中,
ScalingActive
条件为 false。关联的消息显示,Pod 横向自动扩缩器确认 KEDA 已将部署扩缩为零,此时它会停止运行,直到部署扩缩回一个 Pod。Name: keda-hpa-keda-pubsub Namespace: keda-pubsub Metrics: ( current / target ) "s0-gcp-ps-projects-[...]]" (target average value): 0 / 10 Min replicas: 1 Max replicas: 5 Deployment pods: 5 current / 5 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ScaleDownStabilized recent recommendations were higher than current one [...] ScalingActive False ScalingDisabled scaling is disabled since the replica count of the target is zero ScalingLimited True TooManyReplicas the desired replica count is more than the maximum replica count
触发纵向扩容
如需刺激部署进行扩容,请执行以下操作:
将消息加入 Pub/Sub 主题的队列:
for num in {1..20} do gcloud pubsub topics publish keda-echo --project=${PROJECT_ID} --message="Test" done
验证部署是否正在纵向扩容:
kubectl get deployments -n keda-pubsub
在输出中,您会注意到“Ready”(就绪)列显示一个副本:
NAME READY UP-TO-DATE AVAILABLE AGE keda-pubsub 1/1 1 1 2d
KEDA 会在观察到队列不为空后扩容部署。
将 LLM 工作负载缩减为零
本部分介绍了一种大语言模型 (LLM) 工作负载,该工作负载会部署带有附加 GPU 的 Ollama 服务器。Ollama 支持运行 Gemma 和 Llama 2 等热门 LLM,并主要通过 HTTP 公开其功能。
安装 KEDA-HTTP 插件
在闲置期间将 HTTP 服务缩减为零个 Pod 会导致请求失败,因为没有后端来处理请求。
本部分介绍了如何使用 KEDA-HTTP 插件解决此问题。KEDA-HTTP 会启动一个 HTTP 代理,该代理会接收用户请求并将其转发到配置为按需扩缩的服务。当服务没有 Pod 时,代理会触发服务扩容,并缓冲请求,直到服务扩容到至少一个 Pod。
使用 Helm 安装 KEDA-HTTP 插件。如需了解详情,请参阅 KEDA-HTTP 文档。
helm repo add ollama-helm https://otwld.github.io/ollama-helm/
helm repo update
# Set the proxy timeout to 120s, giving Ollama time to start.
helm install http-add-on kedacore/keda-add-ons-http \
--create-namespace --namespace keda \
--set interceptor.responseHeaderTimeout=120s
部署 Ollama LLM 工作负载
如需部署 Ollama LLM 工作负载,请执行以下操作:
创建一个包含
g2-standard-4
个带有挂接 GPU 的节点的节点池,并将集群自动扩缩配置为提供 0 到 2 个节点:gcloud container node-pools create gpu --machine-type=g2-standard-4 \ --location=${LOCATION} --cluster=scale-to-zero \ --min-nodes 0 --max-nodes 2 --num-nodes=1 --enable-autoscaling
添加官方 Ollama Helm 图表代码库,并更新本地 Helm 客户端的代码库:
helm repo add ollama-helm https://otwld.github.io/ollama-helm/ helm repo update
使用 Helm 图表部署 Ollama 服务器:
helm install ollama ollama-helm/ollama --create-namespace --namespace ollama \ -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/helm-values-ollama.yaml
helm-values-ollama.yaml
配置指定要加载的 LLM 模型、GPU 要求以及 Ollama 服务器的 TCP 端口。
配置缩减至零
如需将 Ollama 工作负载配置为缩减为零,KEDA-HTTP 会使用 HTTPScaledObject
。
创建
HTTPScaledObject
资源来描述预期的自动扩缩行为:kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/keda-ollama-httpscaledobject.yaml
这会创建
HTTPScaledObject
对象,用于定义以下字段:scaleTargetRef
:指定 KEDA-HTTP 应将请求转发到的服务。在此示例中,所有主机为ollama.ollama
的请求都会被路由到 Ollama 服务器。scaledownPeriod
:指定在没有收到请求时缩减速度(以秒为单位)。replicas
:指定要为 Ollama 部署维护的最小 Pod 数和最大 Pod 数。scalingMetric
:指定用于触发自动扩缩的指标,例如本例中的请求速率。如需了解更多指标选项,请参阅 KEDA-HTTP 文档。
kind: HTTPScaledObject apiVersion: http.keda.sh/v1alpha1 metadata: namespace: ollama name: ollama spec: hosts: - ollama.ollama scaleTargetRef: name: ollama kind: Deployment apiVersion: apps/v1 service: ollama port: 11434 replicas: min: 0 max: 2 scaledownPeriod: 3600 scalingMetric: requestRate: targetValue: 20
运行以下命令,验证 KEDA-HTTP 是否已成功处理在上一步中创建的
HTTPScaledObject
。kubectl get hpa,scaledobject -n ollama
输出显示了
HorizontalPodAutoscaler
(由 KEDA 创建)和ScaledObject
(由 KEDA-HTTP 创建)资源:NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE horizontalpodautoscaler.autoscaling/keda-hpa-ollama Deployment/ollama 0/100 (avg) 1 2 1 2d NAME SCALETARGETKIND SCALETARGETNAME MIN MAX TRIGGERS AUTHENTICATION READY ACTIVE FALLBACK PAUSED AGE scaledobject.keda.sh/ollama apps/v1.Deployment ollama 0 2 external-push True False False Unknown 2d
验证该部署是否已缩容到零个 Pod。
等待
scaledownPeriod
字段中设置的时间段,然后运行以下命令:kubectl get deployments -n ollama
输出结果显示 KEDA 缩减了 Ollama 部署,并且没有任何 Pod 在运行:
NAME READY UP-TO-DATE AVAILABLE AGE ollama 0/0 0 0 2d
触发纵向扩容
如需刺激部署进行扩容,请使用 KEDA-HTTP 插件设置的代理调用 Ollama 服务。这会导致请求速率指标的值增加,并触发第一个 Pod 的创建。
由于代理未公开,因此请使用 kubectl
端口转发功能访问代理。
kubectl port-forward svc/keda-add-ons-http-interceptor-proxy -n keda 8080:8080 &
# Set the 'Host' HTTP header so that the proxy routes requests to the Ollama server.
curl -H "Host: ollama.ollama" \
http://localhost:8080/api/generate \
-d '{ "model": "gemma:7b", "prompt": "Hello!" }'
curl
命令会向 Gemma 模型发送“Hello!”提示。观察响应中返回的答案令牌。如需了解该 API 的规范,请参阅 Ollama 指南。
清理
为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。
清理 Pub/Sub 订阅和主题:
gcloud pubsub subscriptions delete keda-echo-read gcloud pubsub topics delete keda-echo
删除 GKE 集群:
gcloud container clusters delete scale-to-zero --location=${LOCATION}
后续步骤
- 详细了解如何在 GKE 中自动扩缩 LLM 推理工作负载。
- 探索 KEDA GitHub 代码库和文档。