Kubernetes autoscaling 弹性伸缩

作者: Ju4t

弹性伸缩

默认的扩容冷却周期是 3 分钟,缩容冷却周期是 5 分钟。

kube-controller-manager:

  • –horizontal-pod-autoscaler-downscale-delay:扩容冷却
  • -horizontal-pod-autoscaler-upscale-delay :缩容冷却
# test
$ kubectl top node

$ kubectl api-versions | grep autoscal
autoscaling/v1
autoscaling/v2beta1
autoscaling/v2beta2

$ kubectl top pod -A

CPU指标 - autoscaling/v1

安装 Metrics Server https://github.com/kubernetes-sigs/metrics-server/

# 弹性伸缩,需要安装 metrics service
$ kubectl autoscale rc movie-api --max=8 --min=1 --cpu-percent=5
$ kubectl get hpa

工作流程:hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor)

多指标 - autoscaling/v2

HPA 还有 autoscaling/v2beta1和 autoscaling/v2beta2

区别是 autoscaling/v1beta1支持了 Resource Metrics(CPU)和 Custom Metrics(应用程序指标),而在 autoscaling/v2beta2的版本中额外增加了 External Metrics的支持

metrics中的type字段有四种类型的值:Object、Pods、Resource、External。

  • Resource:指的是当前伸缩对象下的pod的cpu和memory指标,只支持Utilization和AverageValue类型的目标值。
  • Object:指的是指定k8s内部对象的指标,数据需要第三方adapter提供,只支持Value和AverageValue类型的目标值。
  • Pods:指的是伸缩对象Pods的指标,数据需要第三方的adapter提供,只允许AverageValue类型的目标值。
  • External:指的是k8s外部的指标,数据同样需要第三方的adapter提供,只支持Value和AverageValue类型的目标值。

工作流程:hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods

基于Prometheus监控指标

资源指标只包含CPU、内存,一般来说也够了。但如果想根据自定义指标:如请求qps/5xx错误数来实现HPA,就需要使用自定义指标了,目前比较成熟的实现是 Prometheus Custom Metrics。自定义指标由Prometheus来提供,再利用k8s-prometheus-adpater聚合到apiserver,实现和核心指标(metric-server)同样的效果。

Prometheus 特点:

  • 多维数据模型:由度量名称和键值对标识的时间序列数据

  • PromQL:一种灵活的查询语言,可以利用多维数据完成复杂的查询

  • 不依赖分布式存储,单个服务器节点可直接工作

  • 基于HTTP的pull方式采集时间序列数据

  • 推送时间序列数据通过PushGateway组件支持

  • 通过服务发现或静态配置发现目标

  • 多种图形模式及仪表盘支持(grafana)

Prometheus组成及架构:

  • Prometheus Server:收集指标和存储时间序列数据,并提供查询接口
  • ClientLibrary:客户端库
  • Push Gateway:短期存储指标数据。主要用于临时性的任务
  • Exporters:采集已有的第三方服务监控指标并暴露metrics
  • Alertmanager:告警
  • Web UI:简单的Web控制台

安装Prrometheus

参考k8s-prometheus.md

基于QPS指标的弹性伸缩

qps.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: metrics-app
  name: metrics-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: metrics-app
  template:
    metadata:
      labels:
        app: metrics-app
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "80"
        prometheus.io/path: "/metrics"
    spec:
      containers:
      - image: nginx
        name: metrics-app
        ports:
        - name: web
          containerPort: 80
        resources:
          requests:
            cpu: 200m
            memory: 256Mi
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: metrics-app
  labels:
    app: metrics-app
spec:
  ports:
  - name: web
    port: 80
    targetPort: 80
  selector:
    app: metrics-app

继续部署:http_requests_per_second

$ kubectl edit configmap prometheus-adapter -n ops  
   rules:
   - seriesQuery: 'http_requests_total{kubernetes_namespace!="",kubernetes_pod_name!=""}'
     resources:
       overrides:
         kubernetes_namespace: {resource: "namespace"}
         kubernetes_pod_name: {resource: "pod"}
     name:
       matches: "^(.*)_total"
       as: "${1}_per_second"
     metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
$ kubectl delete pod $(kubectl get pod -n ops | grep prometheus-adapter | awk '{print $1}') -n ops

测试API

kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second"

开始压测

$ ab -n 100000 -c 100 http://10.0.0.15/metrics

验证

kubectl get hpa,pod

小结:

  1. 通过/metrics收集每个Pod的http_request_total指标;
  2. prometheus将收集到的信息汇总;
  3. APIServer定时从Prometheus查询,获取request_per_second的数据;
  4. HPA定期向APIServer查询以判断是否符合配置的autoscaler规则;
  5. 如果符合autoscaler规则,则修改Deployment的ReplicaSet副本数量进行伸缩。

参考:https://blog.51cto.com/u_13812615/2521856