KEDA:Kubernetes 事件驱动自动扩缩容

KEDA:Kubernetes 事件驱动自动扩缩容

Kubernetes 原生的 HPA(Horizontal Pod Autoscaler)只能基于 CPU 和内存指标进行扩缩容,面对消息队列积压、数据库连接数、自定义业务指标等场景时显得力不从心。KEDA(Kubernetes Event-driven Autoscaling)正是为填补这一空缺而生。KEDA 作为 HPA 的扩展层,支持 50+ 种外部事件源(Kafka、Redis、RabbitMQ、Prometheus、AWS SQS、Azure Queue 等),能够根据这些外部事件动态调整 Pod 副本数,甚至可以将副本数缩减至零以节省资源,并在有事件到来时迅速从零扩容。KEDA 已是 CNCF 毕业项目,在生产环境中被广泛采用。


服务器配置

KEDA 控制器本身资源占用很少,但要发挥弹性扩缩容的价值,集群需要有足够的资源池来承载突发流量下的 Pod 扩容需求。推荐配置如下:

组件 规格
CPU 4 核
内存 8 GB
系统盘 60 GB SSD
操作系统 Ubuntu 22.04 LTS
网络 公网 IP

搭建 K3s 集群可以考虑 雨云服务器 rainyun。注册填2026off 领 5 折,4 核 8GB 机型在演示 KEDA 弹性扩缩容时,能够为多个 Kafka 消费者 Pod 的快速启停提供充足的资源缓冲,同时还可以部署 Kafka、Redis 等消息中间件作为测试用的事件源。

确认集群状态:

bash 复制代码
kubectl get nodes
# NAME        STATUS   ROLES                  AGE   VERSION
# k3s-node1   Ready    control-plane,master   3d    v1.29.0+k3s1

安装

添加 Helm 仓库

bash 复制代码
helm repo add kedacore https://kedacore.github.io/charts
helm repo update

安装 KEDA

bash 复制代码
kubectl create namespace keda

helm install keda kedacore/keda \
  --namespace keda \
  --set watchNamespace="" \
  --set resources.operator.requests.cpu=100m \
  --set resources.operator.requests.memory=100Mi \
  --set resources.metricServer.requests.cpu=100m \
  --set resources.metricServer.requests.memory=100Mi

验证安装

bash 复制代码
kubectl get pods -n keda
# NAME                                      READY   STATUS    AGE
# keda-operator-7d8f5b6b8-xk9pv            1/1     Running   2m
# keda-operator-metrics-apiserver-abc123    1/1     Running   2m
# keda-admission-webhooks-6b9b4f9-lmn2p    1/1     Running   2m

# 验证 CRD 已注册
kubectl get crd | grep keda
# scaledobjects.keda.sh
# scaledjobs.keda.sh
# triggerauthentications.keda.sh
# clustertriggerauthentications.keda.sh

核心概念

ScaledObject

ScaledObject 是 KEDA 的核心 CRD,用于将外部事件源绑定到一个 Deployment、StatefulSet 或自定义资源上,控制其副本数的伸缩。你在 ScaledObject 中定义:

  • scaleTargetRef:目标工作负载(Deployment/StatefulSet 等)
  • minReplicaCount:最小副本数(设为 0 即启用缩零)
  • maxReplicaCount:最大副本数上限
  • triggers:触发扩缩容的事件源列表,支持多个触发器
  • cooldownPeriod:缩容前的冷却等待时间(秒)
  • pollingInterval:KEDA 轮询事件源的间隔(秒)

ScaledJob

ScaledJob 用于基于事件驱动的批处理场景。与 ScaledObject 不同,ScaledJob 每次扩容时创建新的 Job 来处理消息,处理完成后 Job 自动删除,适合每条消息都需要一个独立 Pod 处理的场景(如视频转码、报告生成等)。

TriggerAuthentication / ClusterTriggerAuthentication

TriggerAuthentication 用于安全地将认证信息(API Key、连接字符串、证书等)传递给触发器,避免直接在 ScaledObject 中硬编码敏感信息。ClusterTriggerAuthentication 是集群级别的,可跨命名空间共用。

与 HPA 的关系

KEDA 并不替代 HPA,而是作为 HPA 的外部指标提供者(External Metrics Provider)。KEDA 创建 ScaledObject 后,会自动为目标工作负载生成对应的 HPA 对象,并向 HPA 暴露外部指标。你可以通过 kubectl get hpa 看到 KEDA 自动创建的 HPA 资源。


实战示例

1. 基于 Kafka 消费者积压扩缩容

场景:根据 Kafka Topic 中未消费的消息数量,动态调整消费者 Pod 数量。

首先创建 Kafka 连接认证:

yaml 复制代码
# kafka-trigger-auth.yaml
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: kafka-trigger-auth
  namespace: default
spec:
  secretTargetRef:
  - parameter: sasl
    name: kafka-credentials
    key: sasl
  - parameter: username
    name: kafka-credentials
    key: username
  - parameter: password
    name: kafka-credentials
    key: password
  - parameter: tls
    name: kafka-credentials
    key: tls
bash 复制代码
kubectl create secret generic kafka-credentials \
  --from-literal=sasl=plaintext \
  --from-literal=username=kafka-user \
  --from-literal=password=kafka-password \
  --from-literal=tls=disable

创建 ScaledObject:

yaml 复制代码
# kafka-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: kafka-consumer-scaler
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: kafka-consumer
  minReplicaCount: 0          # 无消息时缩减为零
  maxReplicaCount: 20         # 最多扩容到 20 个 Pod
  pollingInterval: 15         # 每 15 秒检查一次
  cooldownPeriod: 60          # 缩容前等待 60 秒
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka.kafka.svc.cluster.local:9092
      consumerGroup: my-consumer-group
      topic: orders
      lagThreshold: "50"      # 每个 Pod 处理 50 条积压消息
      offsetResetPolicy: latest
    authenticationRef:
      name: kafka-trigger-auth
bash 复制代码
kubectl apply -f kafka-trigger-auth.yaml
kubectl apply -f kafka-scaledobject.yaml

2. 基于 Redis List 队列深度扩缩容

场景:根据 Redis List 中待处理任务数量,自动调整 Worker Pod 数量:

yaml 复制代码
# redis-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: redis-trigger-auth
  namespace: default
spec:
  secretTargetRef:
  - parameter: address
    name: redis-secret
    key: address
  - parameter: password
    name: redis-secret
    key: password
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: redis-worker-scaler
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: task-worker
  minReplicaCount: 1
  maxReplicaCount: 30
  pollingInterval: 10
  cooldownPeriod: 120
  triggers:
  - type: redis
    authenticationRef:
      name: redis-trigger-auth
    metadata:
      listName: task-queue
      listLength: "20"        # 每个 Pod 处理 20 个队列项
      enableTLS: "false"
      databaseIndex: "0"
bash 复制代码
kubectl create secret generic redis-secret \
  --from-literal=address=redis.default.svc.cluster.local:6379 \
  --from-literal=password=your-redis-password

kubectl apply -f redis-scaledobject.yaml

3. 基于 Prometheus 指标扩缩容

场景:根据业务自定义指标(如 HTTP 请求 QPS)进行扩缩容:

yaml 复制代码
# prometheus-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: api-server-scaler
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicaCount: 2
  maxReplicaCount: 50
  pollingInterval: 30
  cooldownPeriod: 180
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus.monitoring.svc.cluster.local:9090
      metricName: http_requests_per_second
      # 当平均每个 Pod QPS 超过 100 时扩容
      threshold: "100"
      query: sum(rate(http_requests_total{namespace="default",deployment="api-server"}[1m]))
bash 复制代码
kubectl apply -f prometheus-scaledobject.yaml

4. ScaledJob 批处理任务

场景:视频转码任务队列,每条消息独立启动一个 Pod 进行处理:

yaml 复制代码
# video-transcode-scaledjob.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
  name: video-transcode-job
  namespace: default
spec:
  jobTargetRef:
    parallelism: 5             # 最多同时运行 5 个 Job
    completions: 1
    template:
      spec:
        containers:
        - name: transcoder
          image: my-transcoder:latest
          env:
          - name: QUEUE_URL
            value: "sqs://my-video-queue"
          resources:
            requests:
              cpu: "1"
              memory: "2Gi"
            limits:
              cpu: "2"
              memory: "4Gi"
        restartPolicy: Never
  pollingInterval: 30
  maxReplicaCount: 20
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5
  triggers:
  - type: redis
    authenticationRef:
      name: redis-trigger-auth
    metadata:
      listName: video-transcode-queue
      listLength: "1"          # 每条消息触发一个 Job
bash 复制代码
kubectl apply -f video-transcode-scaledjob.yaml

5. Cron 触发器(定时扩缩容)

场景:工作时间保持最少 5 个副本,非工作时间缩减至 1 个:

yaml 复制代码
# cron-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: business-hours-scaler
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicaCount: 1
  maxReplicaCount: 20
  triggers:
  - type: cron
    metadata:
      timezone: Asia/Shanghai
      start: "0 9 * * 1-5"    # 工作日早 9 点开始
      end: "0 18 * * 1-5"     # 工作日晚 6 点结束
      desiredReplicas: "5"    # 工作时间维持 5 个副本

常用命令

bash 复制代码
# 查看所有 ScaledObject 及其状态
kubectl get scaledobject -A
kubectl describe scaledobject kafka-consumer-scaler -n default

# 查看 KEDA 自动创建的 HPA
kubectl get hpa -n default
kubectl describe hpa keda-hpa-kafka-consumer-scaler -n default

# 查看 ScaledJob
kubectl get scaledjob -A

# 查看 TriggerAuthentication
kubectl get triggerauthentication -A
kubectl get clustertriggerauthentication -A

# 查看 KEDA 控制器日志(排查扩缩容问题)
kubectl logs -n keda deploy/keda-operator -f
kubectl logs -n keda deploy/keda-operator-metrics-apiserver -f

# 监控扩缩容事件
kubectl get events -n default --field-selector reason=KEDAScaleTargetActivated
kubectl get events -n default --field-selector reason=KEDAScaleTargetDeactivated

# 查看当前外部指标值(用于验证触发器是否正常工作)
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/s0-kafka-orders" | python3 -m json.tool

# 强制立即触发扩缩容检查(通过重启 KEDA operator)
kubectl rollout restart deploy/keda-operator -n keda

# 临时暂停 ScaledObject(不影响工作负载,只暂停 KEDA 管理)
kubectl patch scaledobject kafka-consumer-scaler -n default \
  --type merge \
  -p '{"metadata":{"annotations":{"autoscaling.keda.sh/paused-replicas":"2"}}}'

# 恢复 ScaledObject
kubectl patch scaledobject kafka-consumer-scaler -n default \
  --type merge \
  -p '{"metadata":{"annotations":{"autoscaling.keda.sh/paused-replicas":null}}}'

KEDA 将 Kubernetes 的弹性扩缩容能力提升到了一个全新的维度。通过与 Kafka、Redis、Prometheus 等生产级事件源的深度集成,以及独特的缩零能力,KEDA 在显著提升系统弹性的同时大幅降低了空闲资源的浪费。无论是高并发消息处理、批量数据处理还是业务流量的波峰波谷应对,KEDA 都能给出优雅的解决方案。

相关推荐
ABILI .8 小时前
Linux上安装部署k8s单机版(minikube)
linux·运维·kubernetes
weixin_408318048 小时前
企业级直播平台技术选型与成本分析:三种方案架构对比
微服务·云原生·架构
珂玥c8 小时前
k8s集群高可用的碎碎念
云原生·容器·kubernetes
xiaogg36788 小时前
k8s 部署yaml文件和Dockerfile文件配置
java·docker·kubernetes
日取其半万世不竭8 小时前
Docker 网络模式详解:bridge、host、overlay 和 macvlan
网络·docker·容器
小夏子_riotous9 小时前
Kubernetes学习路径——7. Pod控制器详解
docker·云原生·容器·kubernetes·云计算·paas·kubelet
程序员阿明9 小时前
docker搭建openPLC runTime
运维·docker·容器
报错小能手9 小时前
讲讲docker
运维·docker·容器
万里侯10 小时前
K8s和我:一人一狗的日常冒险
微服务·容器·k8s