使用NSX高级负载均衡度量值水平扩缩(HPA)容器实例

2021-06-25 17:04:03 浏览数 (1)

tags: Avi

承接上一篇, 使用NSX高级负载均衡(以下简称ALB)度量值触发后端虚拟机池水平扩缩, 本篇讲讲容器环境中使用ALB度量值触发容器的水平扩缩(HPA: Horizontal Pod Autoscaler). 我们的目标是监控ALB上某个L7 VS(Virtual Service)或Pool的度量值, 当度量值达到某个预设值时, 触发HPA, 扩展Pod实例.

可行性方案

关于ALB度量值:

查询ALB文档

代码语言:javascript复制
https://avinetworks.com/docs/20.1/avi-vantage-prometheus-integration/

发现ALB很早就支持将控制器 / 虚拟服务(VS) / 后端池(Pool) / 服务引擎(SE or LB) 的各度量值以Prometheus格式暴露. 文档中也描述了抓取的API路径和方法, 另外所有的度量值分类都在Metrics List文档中有详细描述:

代码语言:javascript复制
https://avinetworks.com/docs/20.1/metrics-list/#vmware-metrics

关于HPA:

查询HPA文档, 发现HPA V1并不支持自定义度量值, 只能通过Metrics-Server提供的CPU / Men使用率来做水平扩缩策略. 但文档中有提到HPA V2beta2可以支持custom.metrics & external.metrics. 那么我们的思路就变成了, 如果使用Prometheus将抓取的ALB度量值暴露到K8s的custom.metrics中去, 让HPA V2beta2查询到.

关于Prometheus: 经过一轮搜索, 得知了Prometheus Adapter这个项目可以将Prometheus抓取的度量值暴露在custom.metrics & external.metrics. 该项目描述如下:

This repository contains an implementation of the Kubernetes resource metrics, custom metrics, and external metrics APIs. This adapter is therefore suitable for use with the autoscaling/v2 Horizontal Pod Autoscaler in Kubernetes 1.6 . It can also replace the metrics server on clusters that already run Prometheus and collect the appropriate metrics.

另外还好社区里有kube-prometheus这样的项目来简化安装与集成, 同时可以使用Prometheus Operator来简化配置Prometheus抓取配置.(不然我可能坚持不下去, 原生的抓取规则看了一眼就头大.)

逻辑导图

  • ALB承担K8s集群负载均衡(LB)和服务入口(Ingress)
  • ALB默认对服务引擎(SE)进行度量值采样, 并以Prometheus格式暴露
  • ALB设置为基本认证模式, 方便Prometheus使用用户名密码认证后抓取度量值
  • 制作ServiceMonitor(Prometheus Opretor的CRD)配置Prometheus抓取参数, 如认证, 目标地址, 度量值, 间隔等.
  • 查看v1beta1.metrics.k8s.io, 检查Prometheus Adapter是否成功暴露自定义度量值
  • 制作HPA, 预设扩缩阀值
  • 压力测试

测试拓扑

特点:

  • 使用NSX-T作为CNI, 为容器提供可路由环境. 服务引擎(SE)路由可达Pod避免了Kube-Proxy SNAT的参与, 更好的健康检测.
  • AKO(ALB K8s Operator)监听K8s集群内LB和Ingress的请求, 自动配置服务引擎实现发布.

准备工作

CNI当然推荐NSX-T, 毕竟Pod可路由省去很多麻烦. 如果觉得NSX-T集成有难度可以考虑使用VMware开源CNI Antrea, 独有的NodeportLocal也能很好的规避Kube-Proxy的NAT, 也能实现LB对Pod的健康检查(可以考虑下篇做个简短的Demo).

安装K8s(废话)

安装AKO:

配置ALB控制器API采用基础认证:

安装Prometheus Operator:

安装Prometheus Operator微信公众号文章:

集成过程相当折磨, Prometheus体系也是很大的, 还好Operator对其操作做了简化. 过程需要趟坑的话欢迎小窗.

配置环节

找一个你喜欢的Web应用发布成Ingress, SVC Type LB也行. 我使用的是Kuard.

代码语言:javascript复制
root@ubuk8s-c3-vm01:/# kubectl get ingress -n routing-ns1
NAME            CLASS    HOSTS                       ADDRESS          PORTS   AGE
kuard-ingress   <none>   kuard.nsx.rockhomelab.org   192.168.30.103   80      13d

ALB相应后获得VIP: 192.168.30.103, 可以在ALB控制器界面中确认. 同时也可以发现, 后端池成员就是Pod IP.

获取目标Pool Name. 其实这一步也可以直接用VS Name, 但当时我没有设置每个Ingress生成独立的VS, 所以就选择了用Pool级别的度量值.

然后配置Prometheus抓取该Pool的度量值, 我这里选择了Pool级别的度量值: l4_server.avg_open_conns.

  1. 制作伪SVC: avilb, 与发布的Pod在同一Namespace. 手工为伪SVC添加Endpoint, 即ALB控制器地址
代码语言:javascript复制
apiVersion: v1
kind: Service
metadata:
  labels:
    lbaas: avi
  name: avilb
  namespace: routing-ns1
spec:
  clusterIP: None
  ports:
  - name: metrics
    port: 443
    targetPort: 443
  selector: null

---
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    lbaas: avi
  name: avilb
  namespace: routing-ns1
subsets:
- addresses:
  - ip: 192.168.31.246
  ports:
  - name: metrics
    port: 443
    protocol: TCP

制作完后可以查询确认: SVC中selector为空时, 会选择与SVC名字一样的Endpoint作为成员.

代码语言:javascript复制
root@ubuk8s-c3-vm01:/# kubectl get svc -n routing-ns1
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
avilb           ClusterIP   None             <none>        443/TCP   16d
kuard-service   ClusterIP   10.100.172.103   <none>        80/TCP    16d
root@ubuk8s-c3-vm01:/# kubectl get endpoints -n routing-ns1
NAME            ENDPOINTS            AGE
avilb           192.168.31.246:443   16d
kuard-service   192.169.32.5:8080    16d
root@ubuk8s-c3-vm01:/#
  1. 制作Secret, 写入ALB控制器用户名密码, 待会Prometheus抓取时需要:
代码语言:javascript复制
kubectl create secret -n routing-ns1 generic avi-basic-auth --from-literal=username='admin' --from-literal=password='VMware1!VMware1!'
  1. 制作ServiceMonitor
代码语言:javascript复制
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: avilb-servicemonitor
  namespace: routing-ns1
  labels:
    lbaas: avi # This is what the prometheus1 CR looking for match
spec:
  endpoints:
  - path: '/api/analytics/prometheus-metrics/pool/'
    params:
      entity_name:
        - k8s-03-cluster--kuard.nsx.rockhomelab.org_-routing-ns1-kuard-ingress
      metric_id: 
        - l4_server.avg_open_conns
    scheme: https
    port: metrics
    tlsConfig:
      insecureSkipVerify: true 
    basicAuth:
      password:
        name: avi-basic-auth
        key: password
      username:
        name: avi-basic-auth
        key: username
  jobLabel: lbaas
  namespaceSelector:
    matchNames:
    - routing-ns1
  selector:
    matchLabels:
      lbaas: avi

登录到Prometheus, 在Targets中查看自定义抓取的ALB度量值状态是否正常. 可选将该度量值图表添加到Grafana中.

确保Prometheus Adaptor 已经将该自定义度量值暴露了在 custom.metrics.k8s.io/v1beta1中, 使用kubectl get --raw来验证. 由于Prometheus的时区是UTC0, 并且是Hard code在程序里的, 显示的时间戳会有8小时“时差”. Grafana中可以在UI中设置本地时区, 可以解决现实问题.

代码语言:javascript复制
kubectl get --raw="/apis/custom.metrics.k8s.io/v1beta1/namespaces/routing-ns1/services/avilb/avi_l4_server_avg_open_conns/" |jq
{
  "kind": "MetricValueList",
  "apiVersion": "custom.metrics.k8s.io/v1beta1",
  "metadata": {
    "selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/routing-ns1/services/avilb/avi_l4_server_avg_open_conns/"
  },
  "items": [
    {
      "describedObject": {
        "kind": "Service",
        "namespace": "routing-ns1",
        "name": "avilb",
        "apiVersion": "/v1"
      },
      "metricName": "avi_l4_server_avg_open_conns",
      "timestamp": "2021-05-30T05:54:25Z",
      "value": "0"
    }
  ]
}
  1. 制作HPA

根据文档提供的水平扩展的公式:

代码语言:javascript复制
期望副本数 = ceil[当前副本数 * (当前指标 / 期望指标)]

我们将期望指标设置在200, Pod副本最大扩展到5个.

代码语言:javascript复制
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-kuard-l4metric
  namespace: routing-ns1
spec:
  maxReplicas: 5
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: kuard-deployment
  metrics:
    - type: Object
      object:
        metric:
          name: avi_l4_server_avg_open_conns
        describedObject:
          apiVersion: v1
          kind: Service
          name: avilb
        target:
          type: Value
          value: 200

HPA是Namespace级别的对象, 所以刚才在制作伪SVC时也要放在相同的Namespace内.

  1. 压测

还是请出我们的Locust, 模拟1000个用户连接访问VIP. 这次我们对比三个图形界面观察度量值变化. 压测从下午15:08分开始, 截止时间15:30分. 1000个Users, 每秒孵化5个.

ALB控制界面, Pod实例扩展到5个, 轮询模式接受连接.

Grafana界面清楚的现实, 最开始只有一个Pod, 当HPA生效后, 5个Pod的度量值为该Pool L4 Open Connection的总值.

查看HPA所在的Namespace可以观察到事件的触发过程.

代码语言:javascript复制
32m         Normal    SuccessfulCreate               replicaset/kuard-deployment-5c55bf6c         Created pod: kuard-deployment-5c55bf6c-jnxzv
32m         Normal    SuccessfulCreate               replicaset/kuard-deployment-5c55bf6c         Created pod: kuard-deployment-5c55bf6c-khzqt
32m         Normal    SuccessfulCreate               replicaset/kuard-deployment-5c55bf6c         Created pod: kuard-deployment-5c55bf6c-78csp
31m         Normal    SuccessfulCreate               replicaset/kuard-deployment-5c55bf6c         Created pod: kuard-deployment-5c55bf6c-hndwq
2m15s       Normal    SuccessfulDelete               replicaset/kuard-deployment-5c55bf6c         Deleted pod: kuard-deployment-5c55bf6c-78csp
2m15s       Normal    SuccessfulDelete               replicaset/kuard-deployment-5c55bf6c         Deleted pod: kuard-deployment-5c55bf6c-jnxzv
2m15s       Normal    SuccessfulDelete               replicaset/kuard-deployment-5c55bf6c         Deleted pod: kuard-deployment-5c55bf6c-hndwq
2m15s       Normal    SuccessfulDelete               replicaset/kuard-deployment-5c55bf6c         Deleted pod: kuard-deployment-5c55bf6c-khzqt
2m15s       Normal    ScalingReplicaSet              deployment/kuard-deployment                  Scaled down replica set kuard-deployment-5c55bf6c to 1
32m         Normal    ScalingReplicaSet              deployment/kuard-deployment                  Scaled up replica set kuard-deployment-5c55bf6c to 4
31m         Normal    ScalingReplicaSet              deployment/kuard-deployment                  Scaled up replica set kuard-deployment-5c55bf6c to 5

ALB默认5分钟汇报一次度量值(可调,最高到实时), Prometheus每30s抓取一次(在ServiceMonitor中可调整), HPA默认冷却时间5分钟.

小结

由于篇幅的问题, 准备环境环节省略了很多过程, 实际上安装与集成的步骤有官方文档和大拿们的分享贴, 有兴趣复制该实验的同学可以搜来参考一下.

或者科学上网搜索Custom Metrics HPA也有可以参考的文章. 这些文章大多会提供一个Demo App, 该Demo App自己提供度量值然后被Prometheus抓取, 逻辑跟本文一样, 通过Adaptor提供API在被HPA查询到.

让业务应用自己输出度量值(兼容Prometheus格式)也许对于研发来说并不是难事, 也许是我站着说话不腰疼. 总体来说暴露什么样的度量值和怎么使用都需要系统的规划, 对于运维体系来说事情可大可小. 对于通过负载均衡暴露的业务来说, 除CPU/MEN外的指标外, L4/L7的指标由负载均衡器来汇报更为科学. 当然了由业务应用汇报度量值又可以更为灵活, 可以匹配业务逻辑. 可以综合使用, 比如水平扩缩采用负载均衡汇报的度量值, 业务运维统计则使用App开发时定制的度量值, 相得益彰.

Prometheus自成体系, 周边的生态也很多, 学来不易. 折射出运维管理是门大学问, 致敬每一位运维人.

0 人点赞