基于事件驱动的自动伸缩工具 KEDA 简单使用

2020-12-23 18:00:18 浏览数 (1)

KEDA 是 Kubernetes 基于事件驱动的自动伸缩工具,通过 KEDA 我们可以根据需要处理的事件数量来驱动 Kubernetes 中任何容器的扩展。KEDA 可以直接部署到任何 Kubernetes 集群中和标准的组件一起工作。

在 Kubernetes 中 KEDA 有两个关键的角色:

  • 扩展客户端:用于激活和停用 Deployments 来扩展到配置的副本,并在没有事件的情况下将副本缩减回零。
  • Metrics Server:一种 Metrics 指标服务,暴露了大量与事件相关的数据,例如队列长度,允许基于事件的扩展,消耗特定类型的事件数据。

Metrics Server 与 HPA 进行通信,以驱动 Kubernetes 部署副本的扩展。然后由 Deployments 直接从源头消费事件。这样可以保留丰富的事件集成,让完成或丢弃队列消息之类的可以立即使用。Metrics Server 是安装 KEDA 时运行的 keda-operator-metrics-apiserver 容器的主要作用。

KEDA 有广泛的扩展器,既可以检测部署是否应该被激活或停用,也可以为特定事件源提供自定义指标。

当我们安装 KEDA 后,它会创建3个 CRD 资源,这些 CRD 可以使你能够将事件源(以及对该事件源的认证)映射到 Deployment、StatefulSet、自定义资源或 Job 上进行缩放。

  • scaledobjects.keda.shScaledObjects 表示事件源(例如 RabbitMQ)与 Kubernetes Deployment、StatefulSet 或定义 /scale 子资源的任何自定义资源之间的所需映射。
  • scaledjobs.keda.shScaledJobs 表示事件源和 Kubernetes Job 之间的映射。
  • triggerauthentications.keda.shScaledObject/ScaledJob 也可以引用 TriggerAuthentication,其中包含了监控事件源的认证配置或 Secret。

安装

安装 KEDA 有很多方式,这里我们直接使用 Helm 来进行安装,首先添加对应的 Helm 仓库:

代码语言:txt复制
➜ helm repo add kedacore https://kedacore.github.io/charts
➜ helm repo update

然后直接使用下面的命令安装即可:

代码语言:txt复制
➜ kubectl create namespace keda
➜ helm install keda kedacore/keda --namespace keda
NAME: keda
LAST DEPLOYED: Wed Dec 23 11:45:02 2020
NAMESPACE: keda
STATUS: deployed
REVISION: 1
TEST SUITE: None

安装完成后在 keda 命名空间下面会运行两个 KEDA 相关的 Pod:

代码语言:txt复制
➜ kubectl get pods -n keda
NAME                                               READY   STATUS    RESTARTS   AGE
keda-operator-8488964969-d4svr                     1/1     Running   0          14m
keda-operator-metrics-apiserver-5b488bc7f6-zrzzm   1/1     Running   0          14m

简单示例

这里我们使用一个简单的 golang 结合 rabbitmq 的示例进行演示,该示例应用将接收来自 RabbitMQ 队列的消息并通过 KEDA 进行扩展。接收方一次(每个实例)将收到一条消息,并 sleep 1秒钟以模拟执行工作,当添加大量队列消息时,KEDA 将驱动容器根据事件源(RabbitMQ)进行扩展。

首先我们需要在 Kubernetes 集群上部署 RabbitMQ 队列,同样我们使用 Helm 来快速安装:

代码语言:txt复制
➜ helm repo add bitnami https://charts.bitnami.com/bitnami
➜ helm repo update
➜ helm install rabbitmq --set auth.username=user --set auth.password=PASSWORD,persistence.enabled=false bitnami/rabbitmq
➜ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
rabbitmq-0                   1/1     Running   0          7m52s
......

注意:对于 RabbitMQ Helm Chart 版本 6.xx 或更早版本,应使用 Rabbitmq.username 和 rabbitmq.password` 参数指定用户名和密码。

安装完成后 Clone 示例项目:

代码语言:txt复制
➜ git clone https://github.com/cnych/sample-go-rabbitmq.git
➜ cd sample-go-rabbitmq

首先我们部署一个 consumer:

代码语言:txt复制
➜ kubectl apply -f deploy/deploy-consumer.yaml
secret/rabbitmq-consumer-secret created
deployment.apps/rabbitmq-consumer created
scaledobject.keda.sh/rabbitmq-consumer created
triggerauthentication.keda.sh/rabbitmq-consumer-trigger created

其中最主要的就是 ScaledObject 这个 CRD 对象的定义:

代码语言:txt复制
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: rabbitmq-consumer
  namespace: default
spec:
  scaleTargetRef:  # scale 的目标引用
    name: rabbitmq-consumer
  pollingInterval: 5 # 可选. 默认: 30 seconds
  cooldownPeriod: 30 # 可选. 默认: 300 seconds
  maxReplicaCount: 30 # 可选. 默认: 100
  triggers:
  - type: rabbitmq  # 基于 rabbitmq 进行伸缩
    metadata:
      queueName: hello   # 监听的队列名
      queueLength: "5"
    authenticationRef:
      name: rabbitmq-consumer-trigger
---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: rabbitmq-consumer-trigger
  namespace: default
spec:
  secretTargetRef:
    - parameter: host
      name: rabbitmq-consumer-secret
      key: RabbitMqHost

这个消费者被设置为每个实例消耗一条消息,sleep 1秒,然后确认消息的完成。上面的 ScaledObject 被设置为在无事件的情况下最小可扩展到0个副本,最大可扩展到30个副本(优化为每个副本5条消息的队列长度)。在30秒的无事件后,副本将被缩减(冷却期)。这些设置可以根据需要在 ScaledObject 上进行更改。

上面的消费者部署完成后可以看到现在是0个副本,这是因为现在没有任何事件产生,所以最小缩放到0个副本:

代码语言:txt复制
➜ kubectl get deploy rabbitmq-consumer
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
rabbitmq-consumer   0/0     0            0           27s
➜ kubectl get rs
NAME                           DESIRED   CURRENT   READY   AGE
rabbitmq-consumer-5c486c869c   0         0         0       52s
➜ kubectl describe rs rabbitmq-consumer-5c486c869c
Name:           rabbitmq-consumer-5c486c869c
Namespace:      default
Selector:       app=rabbitmq-consumer,pod-template-hash=5c486c869c
......
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  88s   replicaset-controller  Created pod: rabbitmq-consumer-5c486c869c-xnx47
  Normal  SuccessfulDelete  87s   replicaset-controller  Deleted pod: rabbitmq-consumer-5c486c869c-xnx47

然后接下来我们部署生产者来产生消息:

代码语言:txt复制
➜ kubectl apply -f deploy/deploy-publisher-job.yaml
job.batch/rabbitmq-publish created

上面的 Job 任务会向正在监听 RabbitMQ 的 "hello" 队列发布300条消息,随着队列的建立,KEDA 将进行自动水平伸缩,直到队列在大约 2 分钟后耗尽,并发 Pod 最多 30 个。我们可以通过下面的命令来观察消费者的变化:

代码语言:txt复制
➜ kubectl get deploy -w
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
rabbitmq-consumer   6/30    30           6           7m6s

我们也可以看到 Pods 在开始扩容处理队列消息了。随着消息长度的不断增加,更多的 Pods 将被主动创建出来。同样这个时候我们也可以查看 HPA 资源对象的变化:

代码语言:txt复制
➜ kubectl get hpa
NAME                         REFERENCE                      TARGETS             MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-rabbitmq-consumer   Deployment/rabbitmq-consumer   <unknown>/5 (avg)   1         30        0          8m23s
➜ kubectl describe hpa keda-hpa-rabbitmq-consumer
Name:                                       keda-hpa-rabbitmq-consumer
Namespace:                                  default
......
Conditions:
  Type            Status  Reason             Message
  ----            ------  ------             -------
  AbleToScale     True    SucceededGetScale  the HPA controller was able to get the target's current scale
  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
Events:
  Type     Reason             Age    From                       Message
  ----     ------             ----   ----                       -------
  Warning  FailedRescale      3m47s  horizontal-pod-autoscaler  New size: 4; reason: external metric rabbitmq-hello(&LabelSelector{MatchLabels:map[string]string{scaledObjectName: rabbitmq-consumer,},MatchExpressions:[]LabelSelectorRequirement{},}) above target; error: Operation cannot be fulfilled on deployments.apps "rabbitmq-consumer": the object has been modified; please apply your changes to the latest version and try again
  Normal   SuccessfulRescale  3m30s  horizontal-pod-autoscaler  New size: 4; reason: external metric rabbitmq-hello(&LabelSelector{MatchLabels:map[string]string{scaledObjectName: rabbitmq-consumer,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
  Normal   SuccessfulRescale  3m15s  horizontal-pod-autoscaler  New size: 8; reason: external metric rabbitmq-hello(&LabelSelector{MatchLabels:map[string]string{scaledObjectName: rabbitmq-consumer,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
  Normal   SuccessfulRescale  2m58s  horizontal-pod-autoscaler  New size: 16; reason: external metric rabbitmq-hello(&LabelSelector{MatchLabels:map[string]string{scaledObjectName: rabbitmq-consumer,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
  Normal   SuccessfulRescale  2m43s  horizontal-pod-autoscaler  New size: 30; reason: external metric rabbitmq-hello(&LabelSelector{MatchLabels:map[string]string{scaledObjectName: rabbitmq-consumer,},MatchExpressions:[]LabelSelectorRequirement{},}) above target

在队列清空和指定的冷却期(ScaledObject 的一个属性,默认为300秒)后,最后一个副本将缩减为零。通过查看 HPA 的事件也可以清楚地看到缩放的过程。

0 人点赞