本文最后编辑于   前,其中的内容可能需要更新。
                
                
                    
                
                 
                背景 Kubernetes的应用扩缩指标仅有CPU,通过这种单一指标来指导单一应用进行扩缩相对比较低效而且滞后。
在部分场景(大促营销/奖品开奖/定时秒杀)下,应用常态负载不高,出现扩容的情况多数为请求量激增导致的CPU使用率上升。而CPU负载飙高的情况下,应用多半已经难以正常运行开始报错退出了,此时再开始慢吞吞的扩容,等待扩容完成后,大量的流量也已经消失了。
另一个问题是HPA的独立性导致的:   举个例子,在流量激增的情况下,流量会先经过应用A的鉴权接口,此时A可能负载上升,发生扩容,而其余流量在这之后进入B应用,此时的流量可能有一部分已经由于A的网关限流功能被限制了,但对于其他应用来说依然存在较高的压力,此时CPU出现上升,才会出现这部分应用的扩容操作,也是一个问题。
存在的问题 
应用扩缩指标单一,不能准确反应负载 
各个应用扩缩策略相对独立,在应用有需求的时候无法做到根据其他应用的需求进行上下游的应用同时扩缩 
 
针对性解决方案 为解决这些问题,我们有下面两种选择:
prometheus-adapter 先来说说prometheus-adapter,prometheus在配置中指定单一prometheus的地址,我们可以通过helm来拉取helm chart,修改参数后进行部署。
1 2 3 $  helm repo add prometheus-community https://prometheus-community.github.io/helm-charts $  helm repo update $  helm pull --untar prometheus-community/prometheus-adapter 
 
由于默认镜像在github的镜像仓库中,推荐同步到私有库后更换镜像地址:
1 2 3 4 5 6 repository:  PRIVATE_REGISTRY/prometheus-adapter tag:  "v0.11.2" pullPolicy:  IfNotPresent pullSecrets:    -  acr-registry-token  
 
我们还需要配置prometheus的地址:
1 2 3 4 5 prometheus:      url:  http://xxxxxxx.arms.aliyuncs.com    port:  9090    path:  "xxxxxxxxxxxxx"  
 
规则配置 以下是重头戏:
我们此处以应用QPS为例:
查询应用QPS的promql为:
1 sum(irate(envoy_vhost_route_upstream_rq{envoy_clusterid="<YPUR_GW_ID>",route="<YOUR_ROUTE_NAME>"}[2m])) 
 
由于我们通过envoy_clusterid以及route来匹配规则,而prometheus-adapter的custom目前只匹配pod_name和namespace两个标签,所以我们采用external rules
1 2 3 4 5 6 7 8 9 10 11 12 13 external:         -  seriesQuery:  'envoy_vhost_route_upstream_rq'       resources:               namespaced:  false      name:               matches:  "^(.*)"               as:  "${1}_per_second"             metricsQuery:  'sum(irate(<<.Series>>{<<.LabelMatchers>>}[1m]))'  
 
注: 在最终的查询PromQL中,seriesQuery会替换metricsQuery中的<<.Series>>,而<<.LabelMatchers>>则会根据HPA中配置的值来替换。
设置好后直接应用
1 $ helm install  prometheus-adapter  ./prometheus-adapter  -n prometheus-adapter --create-namespace  
 
安装完成后可通过命令查看对应的resource:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/envoy_vhost_route_upstream_rq_per_second" |jq .  {   "kind": "MetricValueList",   "apiVersion": "external.metrics.k8s.io/v1beta1",   "metadata": {     "selfLink": "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/envoy_vhost_route_upstream_rq_per_second"   },   "items": [     {       "metricName": "nginx_vts_server_requests_per_second",       "timestamp": "2023-12-20T11:30:47Z",       "value": "644230m",       "selector": null     }   ] } 
 
然后我们可以通过HPA来定义这个规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 apiVersion:  autoscaling/v2beta2 kind:  HorizontalPodAutoscaler metadata:   name:  my-hpa  spec:   scaleTargetRef:      apiVersion:  apps/v1      kind:  Deployment      name:  nginx-static    minReplicas:  1    maxReplicas:  10    metrics:    -  type:  External      external:        metric:          name:  envoy_vhost_route_upstream_rq_per_second          selector:            matchLabels:              route:  "xxxxx-router"               envoy_clusterid:  "gw-xxxxxxxxx"          target:          type:  Value          value:  5  
 
当这个值超过5的时候就会触发扩容。
KEDA KEDA和prometheus-adapter不同,针对prometheus的配置放在HPA中,所以直接安装即可,1.22以及1.24版本的集群安装2.8.1版本
1 2 $ helm repo add kedacore https://kedacore.github.io/charts $ helm install keta kedacore/keda -n keda --versio 2.8.1 
 
规则配置 自定义指标扩缩容配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion:  keda.sh/v1alpha1 kind:  ScaledObject metadata:   name:  prometheus-scaledobject    namespace:  test  spec:   scaleTargetRef:      name:  www-static-base     minReplicaCount:  2          maxReplicaCount:  20 			   triggers:       -  type:  prometheus      metadata:        metricName:  envoy_vhost_route_upstream_rq        serverAddress:  xxx            threshold:  '10'        query:  sum(irate(envoy_vhost_route_upstream_rq{envoy_clusterid="gw-xxxxxxx",route="xxxxxxx"}[2m]))        
 
其中triggers支持配置多种规则,KEDA内置了多种不同的scaler,如kafka,prometheus,CPU以及根据其他应用等比扩缩,一个示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 triggers: -  type:  prometheus   metadata:      metricName:  envoy_vhost_route_upstream_rq      serverAddress:  <PROMETHEUS_ADDRESS>      threshold:  '10'      query:  <PROMQL>  -  type:  cpu   metricType:  Utilization     metadata:      type:  Utilization       value:  "600"  -  type:  cron   metadata:      timezone:  Asia/Shanghai        start:  0  0   *  *  *            end:  45  0  *  *  *               desiredReplicas:  "10"  -  type:  kubernetes-workload   metadata:      podSelector:  'app=backend'       value:  '0.5'   -  type:  kafka   metadata:      bootstrapServers:  kafka.svc:9092      consumerGroup:  my-group      topic:  test-topic      lagThreshold:  '5'      activationLagThreshold:  '3'      offsetResetPolicy:  latest      allowIdleConsumers:  false      scaleToZeroOnInvalidOffset:  false      excludePersistentLag:  false      version:  1.0 .0      partitionLimitation:  '1,2,10-20,31'      sasl:  plaintext      tls:  enable      unsafeSsl:  false