软件
版本
keda
2.3.0
Kubernetes
1.20.7
目前在Kubernetes中做POD弹性伸缩HPA有基于CPU、memory这种资源指标实现和通过custom-metrics-apiserver和Prometheus-adapter实现的自定义业务监控指标的弹性伸缩,但这些都不是很灵活有效,基于cpu、memory实际对业务带来价值并不大,并不能很准确代表业务实际是否需要扩缩容。基于自定义业务监控指标配置起来相当繁琐。所以社区这些问题背景下开发了KEDA,基于事件的伸缩
KEDA是什么?
KEDA是红帽和微软联合开发的一个开源项目,后面贡献给了CNCF基金会,目前处于sandbox阶段,实现KEDA的目的主要为了更好和更加灵活使用HPA。
项目地址
https://github.com/kedacore/keda
文档地址
https://keda.sh/
什么是事件驱动?
举个简单例子,常见的消息队列系统,有生产者和消费者,生产者往消息队列中吐数据,消费者从消息队列中消费数据,当出现消息堆积时,此时是消费者处理不过来了,应该及时扩容消费者。这就是keda可以实现的,通过对应的接口去查看消息队列系统的情况,进行判断,调用HPA进行扩缩容。
keda能做什么?
图片来源:https://developer.ibm.com/technologies/messaging/articles/introduction-to-keda/
图片来源:https://keda.sh/docs/1.4/concepts/
KEDA 监控定义的事件源,并定期检查是否有任何事件。达到设置的阈值后,KEDA 会根据部署的复制件计数设置为 1 或 0,根据配置最小副本计数,激活或停用POD,具体取决于是否有任何事件。
通过上面两幅架构图可以看见keda和HPA是相辅相成的,keda实现的是事件收集和pod副本数0->1,1->0的调整,HPA实现1->n,n->1的POD副本调整.
keda组成
keda由两个组件组成:
keda-operator:创建维护hpa资源对象,同时激活hpa伸缩(0->1,1->0)。
keda-metrics-apiserver: 实现了hpa中external metrics,根据事件源配置返回计算结果,推动hpa进行。
keda定义的CRD对象主要有三个
- ScaledObjects:定义事件源和资源映射以及控制的范围。
- ScaledJobs:定义事件源和job资源映射以及控制的范围。
- TriggerAuthentication:监控事件源的认证配置
keda部署非常简单,有三种方式
- Helm charts
- Operator Hub
- YAML declarations
这里,我们直接用yaml进行,一个yaml即可搞定
kubectl apply -f https://github.com/kedacore/keda/releases/download/v2.3.0/keda-2.3.0.yaml
部署完后检查
kubectl get pod -n keda
NAME READY STATUS RESTARTS AGE
keda-metrics-apiserver-84d8fc689d-62kc2 1/1 Running 0 5h23m
keda-operator-54f95d8598-l5vjg 1/1 Running 0 5h23m
看状态是否正常,也建议看看这两个组件的log是否有报错。
接下来进行测试使用,直接使用官方github里面的例子。
RabbitMQ弹性
实现效果
图片来源:(https://jstobigdata.com/rabbitmq/direct-exchange-in-amqp-rabbitmq/)
当rabbimq队列达到设定的长度后扩容consumer副本数,当队列长度降下去后将副本数缩小为对应的配置值。
部署Rabbimq-server
helm repo add bitnami https://charts.bitnami.com/bitnami
部署rabbitmq
helm install rabbitmq --set auth.username=user --set auth.password=PASSWORD bitnami/rabbitmq
查看是否部署成功
kubectl get pod
NAME READY STATUS RESTARTS AGE
rabbitmq-0 1/1 Running 0 7h37m
部署 RabbitMQ consumer
repo里面是配置rabbimq-consumer和keda规则
git clone https://github.com/kedacore/sample-go-rabbitmq.git
cd sample-go-rabbitmq
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
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: rabbitmq-consumer
namespace: default
spec:
scaleTargetRef:
name: rabbitmq-consumer
pollingInterval: 5 # Optional. Default: 30 seconds
cooldownPeriod: 30 # Optional. Default: 300 seconds
maxReplicaCount: 30 # Optional. Default: 100
triggers:
- type: rabbitmq
metadata:
queueName: hello
queueLength: "5"
authenticationRef:
name: rabbitmq-consumer-trigger
参数
含义
pollingInterval
定时获取scaler的时间间隔,默认30s
cooldownPeriod
上次active至缩容为0需要等待的时间,默认300s
maxReplicaCount
最大POD副本数
minReplicaCount
最小POD副本数,默认为0
triggers.type
事件类型是keda支持的哪种,如是redis就写redis,是kafka是写kafka
trigger.metadata.queueName
这个根实际事件类型有关的触发器指标了,这里定义的是rabbitmq的队列名
trigger.metadata.queueLength
触发器定义的队列长度
trigger.authenticationRef
认证关联,关联TriggerAuthentication
部署后会发现rabbitmq-consumer副本数会自动变为0,因为此时队列是空的
kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
rabbitmq-consumer 0/0 0 0 1h53m
此时get hpa也创建出来了
kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
keda-hpa-rabbitmq-consumer Deployment/rabbitmq-consumer <unknown>/5 (avg) 1 30 0 1h
部署produce往Rabbitmq里面推数据制造拥堵
这个job将推送 300信息到 “hello” 这个队列 keda将在2分种扩容 deployment到30个
kubectl apply -f deploy/deploy-publisher-job.yaml
对应的我们也可以观察hpa和pod的扩缩容
已经在迅速扩容了
ubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-68df844cc-dclwb 1/1 Running 0 8h
rabbitmq-0 1/1 Running 0 8h
rabbitmq-consumer-5c486c869c-4pwxj 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-5wd9k 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-6zgs9 1/1 Running 0 56s
rabbitmq-consumer-5c486c869c-78lx9 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-7g4wf 1/1 Running 0 71s
rabbitmq-consumer-5c486c869c-7qhqn 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-8rj6l 1/1 Running 0 56s
rabbitmq-consumer-5c486c869c-bmjqx 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-db2ts 1/1 Running 0 71s
rabbitmq-consumer-5c486c869c-ddzhp 1/1 Running 0 56s
rabbitmq-consumer-5c486c869c-dgwn4 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-f4k8l 1/1 Running 0 87s
rabbitmq-consumer-5c486c869c-jqbhl 1/1 Running 0 87s
rabbitmq-consumer-5c486c869c-k2mdw 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-kpgc2 0/1 ContainerCreating 0 56s
rabbitmq-consumer-5c486c869c-kzlwl 0/1 ContainerCreating 0 56s
rabbitmq-consumer-5c486c869c-ls4dm 1/1 Running 0 56s
rabbitmq-consumer-5c486c869c-lvtx8 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-ngmnj 1/1 Running 0 71s
rabbitmq-consumer-5c486c869c-nxp4n 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-p27lk 1/1 Running 0 71s
rabbitmq-consumer-5c486c869c-p4d59 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-q9wdl 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-qqgdw 1/1 Running 0 56s
rabbitmq-consumer-5c486c869c-rpghb 1/1 Running 0 89s
rabbitmq-consumer-5c486c869c-sr7hd 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-sxl8t 1/1 Running 0 87s
rabbitmq-consumer-5c486c869c-vk9wp 0/1 ContainerCreating 0 56s
rabbitmq-consumer-5c486c869c-xgnbf 0/1 ContainerCreating 0 40s
rabbitmq-consumer-5c486c869c-xn76k 0/1 ContainerCreating 0 40s
rabbitmq-publish-rxjpl 0/1 Completed 0 109s
等待队列数据消费完了,等待冷却期,pod会自行销毁。
基于Prometheus自定义监控指标弹性
使用自定义HPA监控的例子测试
clone代码
git clone https://github.com/stefanprodan/k8s-prom-hpa
切换到k8s-prom-hpa目录
kubectl create namespace monitoring
kubectl create -f ./prometheus
查看prometheus
kubectl get pod -n monitoring
NAME READY STATUS RESTARTS AGE
prometheus-64bc56989f-qcs4p 1/1 Running 1 22h
kubectl get svc -n monitoring
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
prometheus NodePort 10.104.215.207 <none> 9090:31190/TCP 22h
访问prometheus
http://node_ip:31190
prometheus内prometheus-cfg.yaml 配置了自动发生规则,会自动将组件注册。
部署Podinfo应用测试custom-metric autoscale
kubectl create -f ./podinfo/podinfo-svc.yaml,./podinfo/podinfo-dep.yaml
prometheus配置了自动发现规则,在podinfo-dep.yaml里面配置了对应的规则
annotations:
prometheus.io/scrape: 'true'
所以应用一启动就能直接在prometheus-target中发现。
配置keda
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: prometheus-scaledobject
namespace: default
spec:
scaleTargetRef:
name: podinfo
pollingInterval: 5# Optional. Default: 30 seconds
cooldownPeriod: 30 # Optional. Default: 300 seconds
maxReplicaCount: 30 # Optional. Default: 100
triggers:
- type: prometheus
metadata:
serverAddress: http://192.168.0.32:31190/
metricName: http_requests_total
threshold: '10'
query: sum(rate(http_requests_total[1m]))
这里10指的是每秒10个请求,按照定义的规则metricsQuery中的时间范围1分钟,这就意味着过去1分钟内每秒如果达到10个请求则会进行扩容。
配置完后使用ab进行压力测试
使用ab进行压力测试,模拟1000个并发量
apt install apache2-utils -y
ab命令最基本的参数是-n
和-c
:
-n 执行的请求数量
-c 并发请求个数
其他参数:
-t 测试所进行的最大秒数
-p 包含了需要POST的数据的文件
-T POST数据所使用的Content-type头信息
-k 启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求,默认时,不启用KeepAlive功能
ab -n 10000 -c 1000 http://192.168.0.32:31198/
查看是否进行弹性伸缩。
kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-68df844cc-dclwb 1/1 Running 3 3d8h
podinfo-56874dc7f8-4n9m4 0/1 Running 4 74m
podinfo-56874dc7f8-g89vr 0/1 Running 0 43s
podinfo-56874dc7f8-v2pn8 1/1 Running 4 74m
podinfo-56874dc7f8-xgrz6 0/1 ContainerCreating 0 12s
rabbitmq-0 1/1 Running 0 3d8h
rabbitmq-publish-rxjpl 0/1 Completed 0 2d23h
keda会根据实际的值计算需要弹性的副本数,保证业务可用性。
root@cka01:~# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
keda-hpa-prometheus-scaledobject Deployment/podinfo 13/10 (avg) 1 30 3 3m3s
总的感受下来,还是非常好用的,像之前配一些业务自定义指标的HPA监控还需要配置Prometheus-adapter
配置规则,但通过keda直接可以对接Prometheus,配置对应表达式尽快。其他一些集成的事件触发器也直接使用就可以了。
keda支持的业务事件触发器
参考链接:
https://keda.sh