zoukankan      html  css  js  c++  java
  • 第22章:kubernetes弹性伸缩(HPA)

    2 弹性伸缩

    k8s版本v1.20

    2.1 传统弹性伸缩的困境

    从传统意义上,弹性伸缩主要解决的问题是容量规划与实际负载的矛盾。

    scaling-vs

    蓝色水位线表示集群资源容量随着负载的增加不断扩容,红色曲线表示集群资源实际负载变化。

    弹性伸缩就是要解决当实际负载增大,而集群资源容量没来得及反应的问题。

    1 Kubernetes中弹性伸缩存在的问题

    常规的做法是给集群资源预留保障集群可用,通常20%左右。这种方式看似没什么问题,但放到Kubernetes中,就会发现如下2个问题。

    (1) 机器规格不统一造成机器利用率百分比碎片化

    在一个Kubernetes集群中,通常不只包含一种规格的机器,假设集群中存在4C8G与16C32G两种规格的机器,对于10%的资源预留,这两种规格代表的意义是完全不同的。

    scaling-machine-config

    特别是在缩容的场景下,为了保证缩容后集群稳定性,我们一般会一个节点一个节点从集群中摘除,那么如何判断节点是否可以摘除其利用率百分比就是重要的指标。此时如果大规则机器有较低的利用率被判断缩容,那么很有可能会造成节点缩容后,容器重新调度后的争抢。如果优先缩容小规则机器,则可能造成缩容后资源的大量冗余。

    (2) 机器利用率不单纯依靠宿主机计算

    在大部分生产环境中,资源利用率都不会保持一个高的水位,但从调度来讲,调度应该保持一个比较高的水位,这样才能保障集群稳定性,又不过多浪费资源。

    2 弹性伸缩概念的延伸

    不是所有的业务都存在峰值流量,越来越细分的业务形态带来更多成本节省和可用性之间的跳转。

    (1) 在线负载型:微服务、网站、API (2) 离线任务型:离线计算、机器学习 (3) 定时任务型:定时批量计算 不同类型的负载对于弹性伸缩的要求有所不同,在线负载对弹出时间敏感,离线任务对价格敏感,定时任务对调度敏感。

    2.2 kubernetes 弹性伸缩布局

    1 在 Kubernetes 的生态中,在多个维度、多个层次提供了不同的组件来满足不同的伸缩场景

    有三种弹性伸缩:

    (1) CA(Cluster Autoscaler): Node级别自动扩/缩容cluster-autoscaler组件。 (2) HPA(Horizontal Pod Autoscaler): Pod个数自动扩/缩容。 (3) VPA(Vertical Pod Autoscaler): Pod配置自动扩/缩容,主要是CPU、内存。addon-resizer组件

    如果在云上建议 HPA 结合 cluster-autoscaler 的方式进行集群的弹性伸缩管理。

    2 在Kubernetes平台中,资源分为两个维度 (1) Node级别:K8s将多台服务器抽象一个集群资源池,每个Node提供这些资源 (2) Pod级别:Pod是K8s最小部署单元,运行实际的应用程序,使用request和limit为Pod配额 因此,K8s实现弹性伸缩也是这两个级别,当Node资源充裕情况下,Pod可任意弹性,当不足情况下需要弹性增加节 点来扩容资源池。 (3) 针对Pod负载:当Pod资源不足时,使用HPA(Horizontal Pod Autoscaler)自动增加Pod副本数量 (4) 针对Node负载:当集群资源池不足时,使用CA(Cluster Autoscaler)自动增加Node

    3 Node弹性伸缩有两种方案 (1) Cluster Autoscaler:是一个自动调整Kubernetes集群大小的组件,需要与公有云一起使用,例如AWS、Azure、Aliyun 项目地址:https://github.com/kubernetes/autoscaler (2) 自研发:根据Node监控指标或者Pod调度状态判断是否增加Node,需要一定开发成本

    2.3 Node 自动扩容/缩容

    1 Cluster AutoScaler

    扩容:Cluster AutoScaler 定期检测是否有充足的资源来调度新创建的 Pod,当资源不足时会调用 Cloud Provider 创建新的 Node。

    cluster-autoscaler-up

    缩容:Cluster AutoScaler 也会定期监测 Node 的资源使用情况,当一个 Node 长时间资源利用率都很低时(低于 50%)自动将其所在虚拟机从云服务商中删除。此时,原来的 Pod 会自动调度到其他 Node 上面。

    cluster-autoscaler-down

    Cluster Autoscaler支持的云提供商(阿里云、aws、azure ......): https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler/cloudprovider/ GCE:https://kubernetes.io/docs/concepts/cluster-administration/cluster-management/ GKE:https://cloud.google.com/container-engine/docs/cluster-autoscaler/

    2 自研发-基于Ansible自动增加Node

    ansible-node-scaler

    (1) 触发新增Node (2) 调用Ansible脚本部署组件 (3) 检查服务是否可用 (4) 调用API将新Node加入集群或者启用Node自动加入 (5) 观察新Node状态 (6) 完成Node扩容,接收新Pod

    3 自研发-基于Ansible自动增加Node

    (1) 自动增加Node

    https://github.com/HyjyLc/ansible-install-k8s/

    1)在k8s主节点添加新增节点的解析(kubectl操作节点时使用的是主机名)

    # echo '172.16.1.85 k8s-node3' >> /etc/hosts

    2)扩容node

    # cd /root/ansible-install-k8s-master/
    # vim hosts
    [newnode]
    172.16.1.85 node_name=k8s-node3
    注: /root/ansible-install-k8s-master/roles/node/templates/
    bootstrap.kubeconfig.j2、kube-proxy.kubeconfig.j2
    文件对多master进行了判断,如果是多master,kubelet、kube-proxy的kubeconfig使用的是VIP,否则则相反。

    # ansible-playbook -i hosts add-node.yml -uroot -k
    # kubectl get node
    # kubectl get pod -n kube-system -o wide

    (2) 自动减少Node

    如果你想从Kubernetes集群中删除节点,正确流程如下
    1) 获取节点列表
    kubectl get node
    2) 设置不可调度
    kubectl cordon <node_name>
    3) 驱逐节点上的Pod
    kubectl drain <node_name> --ignore-daemonsets
    4) 移除节点
    kubectl delete node <node_name>

    注:
    如果这块自动化的话,前提要获取长期空闲的Node,然后执行这个步骤。
    我这里是二进制部署的k8s,在下线的node节点重新启动kubelet、kube-proxy服务后就可以重新将下线的node节点注册上了。
    如果是kubeadm部署的k8s,需要在master节点上重新生成node加入k8s集群的token即可。

    2.4 Pod自动扩容/缩容(HPA)

    1 HPA介绍

    Horizontal Pod Autoscaler(HPA,Pod水平自动伸缩),根据资源利用率或者自定义指标自动调整replication controller, deployment 或 replica set,实现部署的自动扩展和缩减,让部署的规模接近于实际服务的负载。HPA不适用于无法缩放的对象,例如DaemonSet。

    hpa-1

    2 使用HPA前提条件

    (1) 使用HPA,确保满足以下条件 1)启用Kubernetes API聚合层 2)相应的API已注册 对于资源指标(例如CPU、内存),将使用metrics.k8s.io API,一般由metrics-server提供。 对于自定义指标(例如QPS),将使用custom.metrics.k8s.io API,由相关适配器(Adapter)服务提供。 已知适配器列表:https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api

    (2) Kubernetes API Aggregation

    在 Kubernetes 1.7 版本引入了聚合层,允许第三方应用程序通过将自己注册到kube-apiserver上,仍然通过 API Server 的 HTTP URL 对新的 API 进行访问和操作。为了实现这个机制,Kubernetes 在 kube-apiserver 服务中引入了一个 API 聚合层(API Aggregation Layer),用于将扩展 API 的访问请求转发到用户服务的功能。

    aggergation

    当你访问 apis/metrics.k8s.io/v1beta1 的时候,实际上访问到的是一个叫作 kube-aggregator 的代理。而 kube-apiserver,正是这个代理的一个后端;而 Metrics Server,则是另一个后端 。通过这种方式,我们就可以很方便地扩展 Kubernetes 的 API 了。 如果你使用kubeadm部署的,默认已开启。如果你使用二进制方式部署的话,需要在kube-APIServer中添加启动参数,增加以下配置:

    # vim /opt/kubernetes/cfg/kube-apiserver.conf
    ......
    --requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem
    --proxy-client-cert-file=/opt/kubernetes/ssl/server.pem
    --proxy-client-key-file=/opt/kubernetes/ssl/server-key.pem
    --requestheader-allowed-names=kubernetes
    --requestheader-extra-headers-prefix=X-Remote-Extra-
    --requestheader-group-headers=X-Remote-Group
    --requestheader-username-headers=X-Remote-User
    --enable-aggregator-routing=true
    ......

    在设置完成重启 kube-apiserver 服务,就启用 API 聚合功能了。

    3 HPA冷却周期

    在弹性伸缩中,冷却周期是不能逃避的一个话题, 由于评估的度量标准是动态特性,副本的数量可能会不断波动。有时被称为颠簸, 所以在每次做出扩容缩容后,冷却时间是多少。在 HPA 中,默认的扩容冷却周期是 3 分钟,缩容冷却周期是 5 分钟。 可以通过调整 kube-controller-manager 组件启动参数设置冷却时间。 --horizontal-pod-autoscaler-downscale-delay // 扩容冷却 --horizontal-pod-autoscaler-upscale-delay // 缩容冷却

    4 HPA的演进历程

    目前 HPA 已经支持了 autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2 三个大版本 。 目前大多数人比较熟悉是autoscaling/v1,这个版本只支持CPU一个指标的弹性伸缩。 而autoscaling/v2beta1增加了支持自定义指标,autoscaling/v2beta2又额外增加了外部指标支持。 而产生这些变化不得不提的是Kubernetes社区对监控与监控指标的认识与转变。从早期Heapster到Metrics Server再到将指标边界进行划分,一直在丰富监控生态。 (1) autoscaling/v1版本

    apiVersion: autoscaling/v1
    kind: HorizontalPodAutoscaler
    metadata:
      name: web
      namespace: lc
    spec:
      maxReplicas: 10
      minReplicas: 2
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: web
      targetCPUUtilizationPercentage: 80

    (2) autoscaling/v2beta2(多指标)

    # kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml

    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类型的目标值。

    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    metadata:
      name: php-apache
      namespace: default
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: php-apache
      minReplicas: 1
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 50
      - type: Pods
        pods:
          metric:
            name: packets-per-second
          target:
            type: AverageValue
            averageValue: 1k
      - type: Object
        object:
          metric:
            name: requests-per-second
          describedObject:
            apiVersion: networking.k8s.io/v1beta1
            kind: Ingress
            name: main-route
          target:
            type: Value
            value: 10k
      - type: External
        external:
          metric:
            name: queue_messages_ready
            selector: "queue=worker_tasks"
          target:
            type: AverageValue
            averageValue: 30

    5 资源指标与自定义指标工作流程

    image-20211012102418830

    (1) 资源指标工作流程: hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor) (2) 自定义资源指标工作流程: hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods

    2.5 基于CPU资源指标缩放

    1 基本工作原理

    Kubernetes 中的 Metrics Server 持续采集所有 Pod 副本的指标数据。HPA 控制器通过 Metrics Server 的 API(Heapster 的 API 或聚合 API)获取这些数据,基于用户定义的扩缩容规则进行计算,得到目标 Pod 副本数量。当目标 Pod 副本数量与当前副本数量不同时,HPA 控制器就向 Pod 的副本控制器(Deployment、RC 或 ReplicaSet)发起 scale 操作,调整 Pod 的副本数量,完成扩缩容操作。

    hpa-2

    2 部署 Metrics Server

    Metrics Server是一个集群范围的资源使用情况的数据聚合器,作为一个应用部署在集群中。 Metric server从每个节点上Kubelet公开的摘要API(cadvisor)收集指标。 Metrics server通过Kubernetes聚合器注册在Master APIServer中。

    hpa-3

    hpa/kubectl get --raw/kubectl top -> apiserver -> metrics-server(不效验证书) -> kubelet/cadvisor(https自签)

    兼容性:

    hpa

    (1) 项目地址
    https://github.com/kubernetes-sigs/metrics-server/
    https://github.com/kubernetes-sigs/metrics-server/releases/
    (2) 下载yaml
    # wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.5.1/components.yaml
    (3) 修改yml文件
    # vim components.yaml

    image-20211011180121661

    # 修改的参数如下
    - --kubelet-insecure-tls
    image: registry.aliyuncs.com/google_containers/metrics-server:v0.5.1
    (4) 部署
    # kubectl apply -f components.yaml
    (5) 查看容器
    # kubectl get pod -n kube-system -o wide | grep metrics-server
    metrics-server-6f6f7948b9-w98vc 1/1 Running 0 41s 172.27.224.7 k8s-master2

    可通过Metrics API在Kubernetes中获得资源使用率指标,例如容器CPU和内存使用率。这些度量标准既可以由用户直接访问(例如,通过使用kubectl top命令),也可以由集群中的控制器(例如,Horizontal Pod Autoscaler)用于进行决策。

    (6) 测试
    1) 查看注册到apiserver上的metrics-server
    # kubectl get apiservices |grep metrics
    v1beta1.metrics.k8s.io kube-system/metrics-server True 23m

    2) 获取node,pod的cpu、内存使用量指标
    # kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
    # kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods

    3) 查看node资源消耗
    # kubectl top node
    NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
    k8s-master1 205m 10% 995Mi 25%
    k8s-master2 237m 11% 965Mi 25%
    k8s-node1 131m 6% 635Mi 16%
    k8s-node2 87m 4% 410Mi 10%

    4) 查看pod资源消耗(区分命名空间)
    # kubectl top pod -n kube-system
    NAME CPU(cores) MEMORY(bytes)
    calico-kube-controllers-97769f7c7-fnxpb 1m 13Mi
    calico-node-4hngl 25m 65Mi
    calico-node-5kwnr 29m 69Mi
    calico-node-h46tb 25m 65Mi
    calico-node-qchbv 25m 62Mi
    coredns-6cc56c94bd-cwtgf 3m 12Mi
    metrics-server-6f6f7948b9-fwss4 4m 20Mi

    5) 以上测试能正常显示资源消耗,说明Metrics Server服务工作正常。

    3 autoscaling/v1(CPU指标实践)

    autoscaling/v1版本只支持CPU一个指标。

    (1) 部署应用
    # kubectl create namespace lc
    # kubectl create deployment web --image=nginx -n lc --dry-run=client -o yaml > deployment-web-lc.yaml
    
    # cat deployment-web-lc.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: web
      name: web
      namespace: lc
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: web
      template:
        metadata:
          labels:
            app: web
        spec:
          containers:
          - image: nginx
            name: nginx
            resources:
              requests:
                memory: "300Mi"
                cpu: "300m"
              limits:
                memory: "450Mi"
                cpu: "450m"
    # 注意:修改yaml,增加resources.requests.cpu
    
    # kubectl apply -f deployment-web-lc.yaml
    
    # kubectl expose deployment web --port=80 --target-port=80 --type=NodePort -n lc 
    --dry-run=client -o yaml > service-web-lc.yaml
    
    # cat service-web-lc.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: web
      name: web
      namespace: lc
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: web
      type: NodePort
    
    # kubectl apply -f service-web-lc.yaml
    
    (2) 创建HPA
    # kubectl autoscale deployment web -n lc --min=2 --max=10 --cpu-percent=80 
    --dry-run=client -o yaml > deployment-web-lc-hpa.yaml
    
    # cat deployment-web-lc-hpa.yaml
    apiVersion: autoscaling/v1
    kind: HorizontalPodAutoscaler
    metadata:
      name: web
      namespace: lc
    spec:
      maxReplicas: 10
      minReplicas: 2
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: web
      targetCPUUtilizationPercentage: 80
    # scaleTargetRef:表示当前要伸缩对象是谁
    # targetCPUUtilizationPercentage:当整体的资源利用率超过80%的时候,会进行扩容。
    
    # kubectl apply -f deployment-web-lc-hpa.yaml
    
    # kubectl get hpa -n lc
    NAME   REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
    web    Deployment/web   0%/80%    2         10        2          78s
    # 说明:为名为web的deployment创建一个HPA对象,目标CPU使用率为80%,副本数量配置为2到10之间。
    
    (3) 压测
    # yum install httpd-tools
    # ab -n 2000000 -c 100 http://172.28.34.23/index.html
    # 总200w请求,并发100,172.28.34.23为ClusterIP
    
    (4) 观察扩容状态
    # kubectl get hpa -n lc
    NAME   REFERENCE        TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
    web    Deployment/web   106%/80%   2         10        8          21m
    # 可以看到deployment/web的副本数加到了8,由于node节点cpu的资源不够了,不能够继续创建pod了。
    
    # kubectl top pods -n lc
    NAME                   CPU(cores)   MEMORY(bytes)
    web-86c68d4466-khvqg   253m         4Mi
    web-86c68d4466-ksfkz   221m         5Mi
    web-86c68d4466-kwldc   250m         4Mi
    web-86c68d4466-ltpbf   258m         7Mi
    web-86c68d4466-mbflm   173m         4Mi
    web-86c68d4466-mchtg   272m         4Mi
    web-86c68d4466-px8cv   262m         4Mi
    web-86c68d4466-rsqg4   258m         7Mi
    
    # kubectl get pods -n lc
    NAME                   READY   STATUS    RESTARTS   AGE
    web-86c68d4466-khvqg   1/1     Running   0          7m31s
    web-86c68d4466-ksfkz   1/1     Running   0          11m
    web-86c68d4466-kwldc   1/1     Running   0          8m21s
    web-86c68d4466-ltpbf   1/1     Running   1          27m
    web-86c68d4466-mbflm   1/1     Running   0          7m31s
    web-86c68d4466-mchtg   1/1     Running   0          8m21s
    web-86c68d4466-px8cv   1/1     Running   0          11m
    web-86c68d4466-rsqg4   1/1     Running   1          35m
    
    (5) 关闭压测,过5分钟后检查缩容状态,发现pod数量变为了2
    # kubectl get hpa -n lc
    NAME   REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
    web    Deployment/web   0%/80%    2         10        2          32m
    
    # kubectl get pods -n lc
    NAME                   READY   STATUS    RESTARTS   AGE
    web-86c68d4466-ltpbf   1/1     Running   1          33m
    web-86c68d4466-rsqg4   1/1     Running   1          41m



    2.6 基于Prometheus自定义指标缩放

    资源指标只包含CPU、内存,一般来说也够了。但如果想根据自定义指标:如请求qps/5xx错误数来实现HPA,就需要使用自定义指标了,目前比较成熟的实现是 Prometheus Custom Metrics。自定义指标由Prometheus来提供,再利用k8s-prometheus-adpater聚合到apiserver,实现和核心指标(metric-server)同样的效果。 为满足更多的需求,HPA也支持自定义指标,例如QPS、5xx错误状态码等,实现自定义指标由autoscaling/v2版本提供,而v2版本又分为beta1和beta2两个版本。 这两个版本的区别是autoscaling/v2beta1支持了Resource Metrics(资源指标)、Custom Metrics(自定义指标)。 在autoscaling/v2beta2的版本中额外增加了External Metrics(扩展指标)的支持。 对于自定义指标(例如QPS),将使用custom.metrics.k8s.io API,由相关适配器(Adapter)服务提供。 已知适配器列表:https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api

    hpa-4

    hpa/kubectl get --raw/kubectl top -> apiserver -> prometheus-adpater -> prometheus -> pod(自定义暴露指标)

    假设我们有一个网站,想基于每秒接收到的HTTP请求对其Pod进行自动缩放,实现HPA大概步骤如下: (1) 部署Prometheus (2) 对应用暴露指标,部署应用,并让Prometheus采集暴露的指标 (3) 部署Prometheus Adapter (4) 为指定HPA配置Prometheus Adapter (5) 创建HPA (6) 压测、验证

    1 部署Prometheus

    Prometheus(普罗米修斯)是一个最初在SoundCloud上构建的监控系统。自2012年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus于2016年加入云原生云计算基金会(CNCF),成为继Kubernetes之后的第二个托管项目。

    (1) Prometheus 特点 1)多维数据模型:由度量名称和键值对标识的时间序列数据 2)PromSQL:一种灵活的查询语言,可以利用多维数据完成复杂的查询 3)不依赖分布式存储,单个服务器节点可直接工作 4)基于HTTP的pull方式采集时间序列数据 5)推送时间序列数据通过PushGateway组件支持 6)通过服务发现或静态配置发现目标 7)多种图形模式及仪表盘支持(grafana)

    (2) Prometheus组成及架构

    prometheus-arch

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

    (3) 部署(采用deployment方式部署)

    # unzip prometheus.zip
    # cd prometheus/
    # ls -l
    prometheus-configmap.yaml # 部署Prometheus
    prometheus-deployment.yaml # Prometheus配置文件,主要配置基于Kubernetes服务发现
    prometheus-rules.yaml # Prometheus告警规则

    # kubectl apply -f .
    # kubectl get pods -n kube-system
    NAME READY STATUS RESTARTS AGE
    (省略的内容)......
    prometheus-8474f8559d-zrpg8 2/2 Running 0 2m19s

    # kubectl get svc -n kube-system
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    (省略的内容)......
    prometheus NodePort 172.28.46.226 <none> 9090:30090/TCP 2m43s

    访问Prometheus UI: http://NodeIP:30090

    2 部署一个应用并暴露Prometheus采集的指标

    对应用暴露指标,部署应用,并让Prometheus采集暴露的指标。在做这步之前先了解下Prometheus如何监控应用的。 如果要想监控,前提是能获取被监控端指标数据,并且这个数据格式必须遵循Prometheus数据模型,这样才能识别和采集,一般使用exporter提供监控指标数据。但对于自己开发的项目,是需要自己实现类似于exporter的指标采集程序。 exporter列表:https://prometheus.io/docs/instrumenting/exporters

    image-20211012133939633

    先模拟自己开发一个网站,采用Python Flask Web框架,写两个页面,/ 首页,/metrics 指标、然后使用Dockefile制作成镜像并部署 到Kubernetes平台。

    # cat metrics-flask-app.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: metrics-flask-app
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: flask-app
      template:
        metadata:
          labels:
            app: flask-app
          # 声明Prometheus采集
          annotations:
            prometheus.io/scrape: "true"
            prometheus.io/port: "80"
            prometheus.io/path: "/metrics"
        spec:
          containers:
          - image: lc/metrics-flask-app
            name: web
            resources:
              requests:
                memory: "300Mi"
                cpu: "300m"
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: metrics-flask-app 
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: flask-app
    
    # kubectl apply -f metrics-flask-app.yaml
    
    (1) flask-app.py
    # cat main.py
    import prometheus_client
    from prometheus_client import Counter
    from flask import Response, Flask
    
    app = Flask(__name__)
    
    requests_total = Counter("request_count","统计HTTP请求")
    
    @app.route("/metrics")
    def requests_count():
        requests_total.inc()
        return Response(prometheus_client.generate_latest(requests_total),
                        mimetype="text/plain")
    
    @app.route('/')
    def index():
        requests_total.inc()
        return "Hello World"
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0",port=80)
    
    (2) Dockerfile
    # cat Dockerfile
    FROM python
    RUN pip install flask -i https://mirrors.aliyun.com/pypi/simple/ && 
        pip install prometheus_client -i https://mirrors.aliyun.com/pypi/simple/
    COPY main.py /
    CMD python main.py



    该metrics-app暴露了一个Prometheus指标接口,可以通过访问service看到

    # kubectl get svc -n default
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    kubernetes ClusterIP 172.28.0.1 <none> 443/TCP 23d
    metrics-flask-app ClusterIP 172.28.128.88 <none> 80/TCP 10m

    # curl 172.28.128.88/metrics
    # HELP request_count_total 统计HTTP请求
    # TYPE request_count_total counter
    request_count_total 9.0
    # HELP request_count_created 统计HTTP请求
    # TYPE request_count_created gauge
    request_count_created 1.63419377682031e+09
    # 说明: 由于是svc起到了负载均衡的作用,每次统计到的request_count_total值都不一样。

    由于我们Prometheus配置了基于Kubernetes服务发现,会自动采集Pod暴露的指标,在prometheus UI界面中查看被采集到指标的pod。

    image-20211014145243894

    image-20211014145415079

    3 部署 Custom Metrics Adapter

    但是prometheus采集到的metrics并不能直接给k8s用,因为两者数据格式不兼容,还需要另外一个组件(k8s-prometheus-adpater),将prometheus的metrics 数据格式转换成k8s API接口能识别的格式,转换以后,因为是自定义API,所以还需要用Kubernetes aggregator在主APIServer中注册,以便直接通过/apis/来访问。

    https://github.com/DirectXMan12/k8s-prometheus-adapter 注: 由于官方推荐使用的helm安装,我在国内拉不下来,我这里直接使用yaml进行不出,yaml也是从helm中拿到的。

    (1) prometheus-adapter.yaml配置文件注意点
    prometheus-adapter部署在kube-system命名空间下(configmap配置文件在kube-system命名空间),并添加prometheus-adapter连
    接prometheus的参数prometheus-url=http://prometheus.kube-system:9090。
    (省略内容)......
    containers:
    - name: prometheus-adapter
    image: "directxman12/k8s-prometheus-adapter-amd64:v0.7.0"
    imagePullPolicy: IfNotPresent
    args:
    - /adapter
    - --secure-port=6443
    - --cert-dir=/tmp/cert
    - --logtostderr=true
    - --prometheus-url=http://prometheus.kube-system:9090
    - --metrics-relist-interval=1m
    - --v=4
    - --config=/etc/adapter/config.yaml
    ports:
    (省略内容)......

    (2) 部署
    # kubectl apply -f prometheus-adapter.yaml

    # kubectl get pod -n kube-system
    NAME READY STATUS RESTARTS AGE
    (省略的内容......)
    prometheus-8474f8559d-zrpg8 2/2 Running 0 18m
    prometheus-adapter-7f94cc997d-qhpcf 1/1 Running 0 50s

    # kubectl get svc -n kube-system
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    kube-dns ClusterIP 172.28.0.2 <none> 53/UDP,53/TCP,9153/TCP 23d
    prometheus NodePort 172.28.46.226 <none> 9090:30090/TCP 18m
    prometheus-adapter ClusterIP 172.28.10.137 <none> 443/TCP 93s

    (3) 验证适配器注册到APIServer
    # kubectl get apiservices |grep custom
    v1beta1.custom.metrics.k8s.io kube-system/prometheus-adapter True 3m26s

    # kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"

    4 指定prometheus-adapter从prometheus中查询指标的配置(configmap)

    (1) 配置内容配置
    # cat prometheus-adapter-configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: prometheus-adapter
      labels:
        app: prometheus-adapter
        chart: prometheus-adapter-2.5.1
        release: prometheus-adapter
        heritage: Helm
      namespace: kube-system
    data:
      config.yaml: |
        rules:
        - seriesQuery: 'request_count_total{app="flask-app"}'
          resources:
            overrides:
              kubernetes_namespace: {resource: "namespace"}
              kubernetes_pod_name: {resource: "pod"}
          name:
            matches: "request_count_total"
            as: "qps"
          metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
    
    (2) 配置说明
    seriesQuery        # Prometheus查询语句,查询应用系列指标。
    resources        # Kubernetes资源标签映射到Prometheus标签。
    name            # 将Prometheus指标名称在自定义指标API中重命名,
    matches            # 正则匹配,as指定新名称。
    metricsQuery    # 一个Go模板,对调用自定义指标API转换为Prometheus查询语句。
    
    (3) 应用配置
    # kubectl apply -f prometheus-adapter-configmap.yaml
    # 删除prometheus-adapter pod使配置生效
    # kubectl delete pod/prometheus-adapter-7f94cc997d-qhpcf -n kube-system
    
    (4) 向自定义指标API访问
    # kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/qps"
    注: 如果配置没问题,会返回JSON数据,注意里面的value字段,HPA控制器会拿这个值计算然后比对阈值。这个值单位是m,表示毫秒,千分之一,
    例如值为500m是每秒0.5个请求,10000m是每秒10个请求(并发)。
    Adapter向Prometheus查询语句最终是由于HTTP请求统计是累计的,对HPA自动缩放不是特别有用,因此将其转为速率指标。
    这条语句意思是:查询每个Pod在2分钟内访问速率,即QPS(每秒查询率)
    sum(rate(request_count_total{app="flask-app", kubernetes_namespace="default", kubernetes_pod_name=~"pod1|pod2"}[2m])) by (kubernetes_pod_name)



    image-20211014150750015

    image-20211014151407702

    5 创建HPA策略

    # cat hpa-v2-qps.yaml
    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    metadata:
      name: metrics-flask-app
      namespace: default
    spec:
      minReplicas: 1
      maxReplicas: 10
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: metrics-flask-app
      metrics:
      - type: Pods
        pods:
          metric:
            name: qps
          target:
            type: AverageValue
            averageValue: 10000m
    # 所有Pod平均值为10000m触发扩容,即每秒10个请求
    
    # kubectl apply -f hpa-v2-qps.yaml
    # kubectl get hpa -n default
    NAME                REFERENCE                      TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
    metrics-flask-app   Deployment/metrics-flask-app   16m/10    1         10        3          41s



    6 压测

    # yum install httpd-tools -y
    # ab -n 100000 -c 100 http://172.28.128.88/
    # 172.28.128.88 是 deployment/metrics-flask-app svc 的 cluster-ip 地址

    7 查看HPA状态

    # 可以看到pod副本数扩充到了10个
    # kubectl get hpa -n default
    NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
    metrics-flask-app Deployment/metrics-flask-app 202072m/10 1 10 10 4m17s

    # kubectl get pod -n default
    NAME READY STATUS RESTARTS AGE
    metrics-flask-app-5475d5f794-4n9sw 1/1 Running 0 2m10s
    metrics-flask-app-5475d5f794-6cm4c 1/1 Running 0 2m26s
    metrics-flask-app-5475d5f794-9gwzp 1/1 Running 0 80m
    metrics-flask-app-5475d5f794-9jlt2 1/1 Running 0 2m26s
    metrics-flask-app-5475d5f794-chwrl 1/1 Running 0 2m10s
    metrics-flask-app-5475d5f794-gnvm7 1/1 Running 0 2m10s
    metrics-flask-app-5475d5f794-jvl26 1/1 Running 0 2m10s
    metrics-flask-app-5475d5f794-lnj4q 1/1 Running 0 80m
    metrics-flask-app-5475d5f794-px6pg 1/1 Running 0 80m
    metrics-flask-app-5475d5f794-ws42t 1/1 Running 0 2m26s

    # kubectl describe hpa metrics-flask-app


  • 相关阅读:
    npm 5.4.2 更新后就不能用了
    Node.js 被分叉出一个项目 — Ayo.js,肿么了
    页面缓存之Meta http-equiv属性详解
    Javascript 浮点计算问题分析与解决
    详解 Cookie 纪要(vue.cookie,jquery.cookie简化)
    Cookie 基本操作
    HTML5上传图片预览
    location.href跳转测试
    ios中iframe的scroll滚动事件替代方法
    JS数组API
  • 原文地址:https://www.cnblogs.com/LiuChang-blog/p/15410541.html
Copyright © 2011-2022 走看看