本教程介绍如何使用 KEDA 将 GKE 工作负载缩减至零个 Pod。在非活动期间(例如周末和非办公时间),或对于间歇性工作负载(例如定期作业),将部署缩减至零个 Pod 可以节省资源。
安装 KEDA
KEDA 是一个与 Kubernetes Pod 横向自动扩缩器相辅相成的组件。借助 KEDA,您可以将 Deployment 缩减到零个 Pod,以及从零个 Pod 扩容到一个 Pod。Deployment 是一个 Kubernetes API 对象,可让您运行在集群节点中分布的多个 Pod 副本。在 GKE 至少创建一个 Pod 后,系统会应用标准的 Pod 横向自动扩缩器算法。
GKE 将 Deployment 缩减到零个 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
请注意,此命令还会设置授权规则,这些规则要求集群使用 Workload Identity Federation for 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
请注意,此命令还会设置授权规则,这些规则要求集群使用 Workload Identity Federation for 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-pubsub
命名空间下创建启动工作负载的 Deployment。
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 订阅为空,并将 Deployment 缩减为零副本。
检查工作负载自动扩缩器:
kubectl describe hpa keda-hpa-keda-pubsub -n keda-pubsub
可以看到,在命令响应中,
ScalingActive
条件为 false。关联的消息显示,Pod 横向自动扩缩器确认 KEDA 已将 Deployment 缩减至零,此时它会停止运行,直到 Deployment 重新扩容为一个 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
触发扩容
如需促使 Deployment 扩容,请执行以下操作:
将消息加入 Pub/Sub 主题的队列:
for num in {1..20} do gcloud pubsub topics publish keda-echo --project=${PROJECT_ID} --message="Test" done
验证 Deployment 正在扩容:
kubectl get deployments -n keda-pubsub
在输出中,可以看到到“Ready”列显示一个副本:
NAME READY UP-TO-DATE AVAILABLE AGE keda-pubsub 1/1 1 1 2d
KEDA 在观察到队列不为空后会将 Deployment 扩容。
将 LLM 工作负载缩减至零
本部分介绍部署挂接 GPU 的 Ollama 服务器的大语言模型 (LLM) 工作负载。Ollama 支持运行 Gemma 和 Llama 2 等热门 LLM,并主要通过 HTTP 公开其功能。
安装 KEDA-HTTP 插件
在非活跃期间将 HTTP 服务缩减至零个 Pod 会导致请求失败,因为没有后端来处理请求。
本部分介绍如何使用 KEDA-HTTP 插件来解决此问题。KEDA-HTTP 会启动一个 HTTP 代理,该代理接收用户请求并将其转发到已配置为缩减至零的 Service。当 Service 没有 Pod 时,代理会触发 Service 进行扩容,并缓冲请求,直到 Service 扩容到至少一个 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 工作负载,请执行以下操作:
创建一个包含挂接了 GPU 的
g2-standard-4
节点的节点池,并配置集群自动扩缩功能以提供 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 应将请求转发到的 Service。在此示例中,主机为ollama.ollama
的所有请求都会路由到 Ollama 服务器。scaledownPeriod
:指定在未收到任何请求时缩减的速度(以秒为单位)。replicas
:指定要为 Ollama 部署维护的 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
验证 Deployment 缩减至零个 Pod。
等待
scaledownPeriod
字段中设置的时长,然后运行以下命令:kubectl get deployments -n ollama
输出显示 KEDA 缩减了 Ollama 部署,并且没有 Pod 正在运行:
NAME READY UP-TO-DATE AVAILABLE AGE ollama 0/0 0 0 2d
触发扩容
如需促使 Deployment 扩容,请使用 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
命令将提示“Hello!”发送到 Gemma 模型。观察响应中返回的回答令牌。如需了解 API 的规范,请参阅 Ollama 指南。