在KEDA中尝试事件驱动的自动缩放
这是什么?
Kubernetes提供了一种称为HorizontalPodAutoscaling(以下简称HPA)的机制,根据资源使用量等指标自动增减Pod的启动数量。虽然HPA在广泛使用的用例中是一种优秀的机制,但不能将Pod完全降为零。KEDA通过扩展HPA的机制,可以将Pod完全降为零。
为了确认KEDA自身的安装方法等,本文将尝试使用演示性的配置测试KEDA进行Pod的自动扩展。
我们试试看
构建集群
我认为集群可以在几乎任何环境下运行。
我正在kind集群上进行操作验证。
Prometheus 安装
为了收集指标并回答KEDA的查询,安装 Prometheus。
稍微夸张一点,但由于构建容易,我们将使用名为kube-prometheus-stack的helm图表。
helm upgrade -i \
-n prometheus \
--create-namespace \
prom-op \
kube-prometheus-stack \
--repo https://prometheus-community.github.io/helm-charts \
--version 48.4.0
请注意,设置为上述的发布名称”prom-op”将在后续的ingress-nginx配置以及ScaledObject(KEDA的自定义资源)配置中出现,因此如果要进行更改,请谨慎操作。
安装Ingress-Nginx。
我们将作为Ingress Controller引入ingress-nginx。
在当前的配置中,将使用该Ingress Controller公开的指标作为自动缩放的输入。
因为要使用Helm图表,所以我会准备以下values文件:
controller:
service:
type: ClusterIP
extraArgs:
metrics-per-host: 'false'
metrics:
enabled: true
serviceMonitor:
enabled: true
namespace: prometheus
additionalLabels:
release: prom-op
controller.extraArgs.metrics-per-host 的设置是因为在后续创建的 Ingress 资源中没有主机名。我们想要使用的指标是每个 Ingress 资源公开的指标,名为 nginx_ingress_controller_requests。但是,如果原始的 Ingress 资源没有设置主机名,那么默认情况下,与该 Ingress 资源相关联的指标将不会由 ingress-nginx 控制器公开。如官方文档所述,通过提供这个参数可以避免这个问题。
请使用以下命令进行安装:
helm upgrade -i \
-n ingress-nginx \
--create-namespace \
ingress-nginx \
ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--version 4.7.2 \
--values ingress-nginx-values.yaml
KEDA的安装
默认安装KEDA。
helm upgrade -i \
-n keda \
--create-namespace \
keda \
keda \
--repo https://kedacore.github.io/charts \
--version 2.11.2
部署示例应用程序
为了使再现变得更加简单,我们使用nginx镜像。
为了使操作简单,我们将创建一个app/目录,并将以下清单分别作为文件创建。
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
– image: nginx:mainline-alpine
name: nginx
ports:
– containerPort: 80
name: http
protocol: TCP
resources: {}
status: {}
app/nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
namespace: default
spec:
ports:
– name: http
port: 80
protocol: TCP
targetPort: http
selector:
app: nginx
type: ClusterIP
status:
loadBalancer: {}
app/nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: nginx
namespace: default
spec:
ingressClassName: nginx
rules:
– http:
paths:
– backend:
service:
name: nginx
port:
name: http
path: /
pathType: Prefix
status:
loadBalancer: {}
点击打开完整文件的清单(Manifest):
应用/nginx-部署.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
namespace: 默认
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
– image: nginx:mainline-alpine
name: nginx
ports:
– containerPort: 80
name: http
protocol: TCP
resources: {}
status: {}
应用/nginx-服务.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
namespace: 默认
spec:
ports:
– name: http
port: 80
protocol: TCP
targetPort: http
selector:
app: nginx
type: ClusterIP
status:
loadBalancer: {}
应用/nginx-Ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: nginx
namespace: 默认
spec:
ingressClassName: nginx
rules:
– http:
paths:
– backend:
service:
name: nginx
port:
name: http
path: /
pathType: Prefix
status:
loadBalancer: {}
最后,让我们在同样的app/目录中创建所需的ScaledObject清单。
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: nginx
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
idleReplicaCount: 0
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: prometheus
metadata:
serverAddress: http://prom-op-kube-prometheus-st-prometheus.prometheus.svc:9090
query: 'sum by (exported_namespace,exported_service) (irate(nginx_ingress_controller_requests[1m]))'
activationThreshold: '0'
threshold: '2'
metricType: AverageValue
在上述的ScaledObject中,我们通过以下查询从Prometheus获取指标数据。
sum by (exported_namespace,exported_service) (irate(nginx_ingress_controller_requests[1m]))
这个指标是由ingress-nginx公开的,并且包含在通过ServiceMonitor资源(Prometheus operator的自定义资源)自动设置到Prometheus中的指标中。因此,在进行操作验证时,需要发送请求通过ingress-nginx。
请将通过以下命令创建的清单全部应用:
kubectl apply -f app/
你可以通过以下命令确认是否成功进行了apply:
kubectl get so,hpa,deploy,po,svc,ep
确认动作
我会向Ingress/Nginx发送请求。
将请求传送至Ingress的方法因环境而异,但可以通过端口转发的方式在任何环境中使用。可以通过打开另一个终端并使用以下命令进行端口转发:
kubectl -n ingress-nginx port-forward service/ingress-nginx-controller 3080:80
当ScaledObject处于非激活状态时,由于没有nginx Pod,会返回503错误。然而,503错误也会计入ScaledObject的请求数中,因此我们会继续发送请求而不放弃。您可以使用以下简单命令,或者使用脚本语言。
watch -p -n 1 curl -s localhost:3080/
使用上述的命令每秒发送一个请求,应该会启动一个Pod。
首先,我们同样尝试使用普通的自动扩展进行水平扩展。
我将尝试使用以下第4个命令将请求频率增加到每秒3次左右。
watch -p -n 0.3 curl -s localhost:3080/
当监控HPA对象时,可以确认指标将达到3.3左右,并且Pod的数量应该增加到2个。
接下来,让我们尝试进行缩容操作,尤其是尝试缩减到零的情况。
只需使用Ctrl + C中断正在进行的watch命令。由于scale-in默认设置了5分钟的冷却时间,因此需要等待大约5分钟。
那么,应该会删除所有的nginx Pod。
那么,所有的nginx Pod将会被删除。
这样一来,所有的nginx Pod都应该会被删除。
通过重新发起请求,您可以确认从零开始的scale-out。
总结
我尝试了在KEDA上进行零级别的扩容/缩容。
KEDA通常使用Amazon SQS或Apache Kafka等消息代理的指标,例如队列长度和消息延迟时间等,来检测消息代理中是否积压了消息,并对Pod进行自动扩展。但本次我们选择了更容易进行操作确认的Web服务器作为应用程序配置。
ScaledObject资源的缩写是so。↩
如果watch命令无法处理小数,也可以使用watch -p -n 1 ‘for i in $(seq 3); do curl -s localhost:3080 & done’。↩
在这种配置下,当Pod为零时,请求会出现错误,需要在使用端进行重试。↩