kubernetes 中如何实现 Pod 自动扩缩容

Posted 笨小孩@GF 知行合一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubernetes 中如何实现 Pod 自动扩缩容相关的知识,希望对你有一定的参考价值。

  • k8s 应用自动扩缩容的方案

  • 为什么要自动扩缩容?

  • 在实际的业务场景中,我们经常会遇到某个服务需要扩容的场景(例如:测试对服务压测、电商平台秒杀、大促活动、或由于资源紧张、工作负载降低等都需要对服务实例数进行扩缩容操作)。
  • 在 k8s 中扩缩容分为两种:

    1、Node 层面:在使用 kubernetes 集群经常问到的一个问题是,我应该保持多大的节点规模来满足应用需求呢?

    cluster-autoscaler 的出现解决了这个问题, 可以通过 cluster-autoscaler 实现节点级别的动态添加与删除,动态调整容器资源池,应对峰值流量

    2、Pod 层面:我们一般会使用 Deployment 中的 replicas 参数,设置多个副本集来保证服务的高可用,但是这是一个固定的值,比如我们设置 10 个副本,就会启 10 个 pod 同时 running 来提供服务。如果这个服务平时流量很少的时候,也是 10 个 pod 同时在 running,而流量突然暴增时,又可能出现 10 个 pod 不够用的情况。
     
  • 针对这种情况怎么办?就需要自动扩缩容:

  • Kubernetes 对 Pod 的扩缩容分为:手动和自动两种

    1、手动模式:通过 kubectl scale 命令,这样需要每次去手工操作一次,而且不确定什么时候业务请求量就很大了,所以如果不能做到自动化的去扩缩容的话,这也是一个很麻烦的事情

    2、自动模式:如果 Kubernetes 系统能够根据 Pod 当前的负载的变化情况来自动的进行扩缩容就好了,因为这个过程本来就是不固定的,频繁发生的,所以纯手工的方式不是很现实
  • 自动扩缩容的方案有哪些?

  • kubernetes HPA(Horizontal Pod Autoscaling)
    通过此功能,只需简单的配置,便可以利用监控指标(cpu 使用率、磁盘、自定义的等)自动的扩容或缩容服务中 Pod 数量,当业务需求增加时,系统将无缝地自动增加适量 pod 容器,提高系统稳定性。
  • kubernetes KPA(Knative Pod Autoscaler)
    基于请求数对 Pod 自动扩缩容,KPA 的主要限制在于它不支持基于 CPU 的自动扩缩容。
  • kubernetes VPA(Vertical Pod Autoscaler)
    垂直 Pod 自动扩缩容,VPA 会基于 Pod 的资源使用情况自动为集群设置资源占用的限制,从而让集群将 Pod 调度到有足够资源的最佳节点上。VPA 也会保持最初容器定义中资源 request 和 limit 的占比。


    它会根据容器资源使用率自动设置 pod 的 CPU 和内存的 requests,从而允许在节点上进行适当的调度,以便为每个 Pod 提供适当的可用的节点。它既可以缩小过度请求资源的容器,也可以根据其使用情况随时提升资源不足的容量。
  • 如何实现 k8s 中的应用自动扩缩容?

  • 基于 HPA
    要想实现自动扩缩容,需要先考虑如下几点:
    1.通过哪些指标决定扩缩容?
    HPA v1 版本可以根据 CPU 使用率来进行自动扩缩容:
    但是并非所有的系统都可以仅依靠 CPU 或者 Memory 指标来扩容,对于大多数 Web 应用的后端来说,基于每秒的请求数量进行弹性伸缩来处理突发流量会更加的靠谱,所以对于一个自动扩缩容系统来说,我们不能局限于 CPU、Memory 基础监控数据,每秒请求数 RPS 等自定义指标也是十分重要。

    HPA v2 版本可以根据自定义的指标进行自动扩缩容

    注意:

    hpa v1 只能基于 cpu 做扩容所用
    hpa v2 可以基于内存和自定义的指标做扩容和缩容

    2.如何采集资源指标?
    如果我们的系统默认依赖 Prometheus,自定义的 Metrics 指标则可以从各种数据源或者exporter 中获取,基于拉模型的 Prometheus 会定期从数据源中拉取数据。 也可以基于 metricsserver 自动获取节点和 pod 的资源指标


    3.如何实现自动扩缩容?
    K8s 的 HPA controller 已经实现了一套简单的自动扩缩容逻辑,默认情况下,每 30s 检测一次指标,只要检测到了配置 HPA 的目标值,则会计算出预期的工作负载的副本数,再进行扩缩容操作。同时,为了避免过于频繁的扩缩容,默认在 5min 内没有重新扩缩容的情况下,才会触发扩缩容。


    HPA 本身的算法相对比较保守,可能并不适用于很多场景。例如,一个快速的流量突发场景,如果正处在 5min 内的 HPA 稳定期,这个时候根据 HPA 的策略,会导致无法扩容。
  • 基于 KPA

    1、根据并发请求数实现自动扩缩容

    2、设置扩缩容边界实现自动扩缩容

    扩缩容边界指应用程序提供服务的最小和最大 Pod 数量。通过设置应用程序提供服务的最小和最大Pod 数量实现自动扩缩容。

    相比 HPA,KPA 会考虑更多的场景,其中一个比较重要的是流量突发的时候

  • 基于 VPA
    当目前运行 pod 的节点资源达不到 VPA 的推荐值,就会执行 pod 驱逐,重新部署新的足够资源的服务。VPA 是 Kubernetes 比较新的功能,还没有在生产环境大规模实践过,不建议在线上环境使用自动更新模式,但是使用推荐模式你可以更好了解服务的资源使用情况。


    注:K8s 节点默认最多跑几个 pod:110 个


  • 利用 HPA 基于 CPU 指标实现 pod 自动扩缩容

  • HPA 全称是 Horizontal Pod Autoscaler,翻译成中文是 POD 水平自动伸缩, HPA 可以基于CPU 利用率对 deployment 中的 pod 数量进行自动扩缩容(除了 CPU 也可以基于自定义的指标进行自动扩缩容)。pod 自动缩放不适用于无法缩放的对象,比如 DaemonSets。

  • HPA 由 Kubernetes API 资源和控制器实现。控制器会周期性的获取平均 CPU 利用率,并与目标值相比较后调整 deployment 中的副本数量。

  • HPA 工作原理

     HPA 是根据指标来进行自动伸缩的,目前 HPA 有两个版本 v1 和 v2beta

  • HPA 的 API 有三个版本,通过 kubectl api-versions | grep autoscal 可看到

    autoscaling/v1            只支持基于 CPU 指标的缩放;
    autoscaling/v2beta1   支持 Resource Metrics(资源指标,如 pod 的内存)和 Custom Metrics(自定义指标)的缩放;
    autoscaling/v2beta2    支持 Resource Metrics(资源指标,如 pod 的内存)和 Custom Metrics(自定义指标)和 ExternalMetrics(额外指标)的缩放,但是目前也仅仅是处于 beta 阶段

  • 指标从哪里来?
    K8S 从 1.8 版本开始,CPU、内存等资源的 metrics 信息可以通过 Metrics API 来获取,用户可以直接获取这些 metrics 信息(例如通过执行 kubect top 命令),HPA 使用这些 metics 信息来实现动态伸缩。

  • Metrics server:
    1、Metrics server 是 K8S 集群资源使用情况的聚合器
    2、从 1.8 版本开始,Metrics server 可以通过 yaml 文件的方式进行部署
    3、Metrics server 收集所有 node 节点的 metrics 信息

  • HPA 如何运作?
    HPA 的实现是一个控制循环,由 controller manager 的--horizontal-pod-autoscaler-syncperiod 参数指定周期(默认值为 15 秒)。每个周期内,controller manager 根据每个HorizontalPodAutoscaler 定义中指定的指标查询资源利用率。controller manager 可以从resource metrics API(pod 资源指标)和 custom metrics API(自定义指标)获取指标。然后,通过现有 pods 的 CPU 使用率的平均值(计算方式是最近的 pod 使用量(最近一分钟的平均值,从 metrics-server 中获得)除以设定的每个 Pod 的 CPU 使用率限额)跟目标使用率进行比较,并且在扩容时,还要遵循预先设定的副本数限制:MinReplicas <= Replicas <= MaxReplicas。


    计算扩容后 Pod 的个数:sum(最近一分钟内某个 Pod 的 CPU 使用率的平均值)/CPU 使用上限的整数+1

    流程:
    1、创建 HPA 资源,设定目标 CPU 使用率限额,以及最大、最小实例数
    2、收集一组中(PodSelector)每个 Pod 最近一分钟内的 CPU 使用率,并计算平均值
    3、读取 HPA 中设定的 CPU 使用限额
    4、计算:平均值之和/限额,求出目标调整的实例个数
    5、目标调整的实例数不能超过 1 中设定的最大、不能少于最小实例数,如果没有超过,则扩容;超过,则扩容至最大的实例个数
    6、回到 2,不断循环

  • 安装数据采集组件 metrics-server

  • metrics-server 是一个集群范围内的资源数据集和工具,同样的,metrics-server 也只是显示数据,并不提供数据存储服务,主要关注的是资源度量 API 的实现,比如 CPU、文件描述符、内存、请求延时等指标,metric-server 收集数据给 k8s 集群内使用,如 kubectl,hpa,scheduler 等

  • 1.部署 metrics-server 组件
    #通过离线方式获取镜像
    需要的镜像是:k8s.gcr.io/metrics-server-amd64:v0.3.6 和 k8s.gcr.io/addon-resizer:1.8.4
    镜像所在地址在课件,可自行下载,如果大家机器不能访问外部网络,可以把镜像上传到 k8s 的各个节点,按如下方法手动解压:
    docker load -i metrics-server-amd64-0-3-6.tar.gz
    docker load -i addon.tar.gz

    #部署 metrics-server 服务
    #在/etc/kubernetes/manifests 里面改一下 apiserver 的配置
    注意:这个是 k8s 在 1.17 的新特性,如果是 1.16 版本的可以不用添加,1.17 以后要添加。这个参数的作用是 Aggregation 允许在不修改 Kubernetes 核心代码的同时扩展 Kubernetes API。
    vim /etc/kubernetes/manifests/kube-apiserver.yaml
    增加如下内容:
    - --enable-aggregator-routing=true

    重新更新 apiserver 配置:
    kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
    kubectl delete pods kube-apiserver -n kube-system
    kubectl apply -f metrics.yaml

    #测试 kubectl top 命令
    kubectl top nodes
    kubectl top po -n kube-system


      


  • 创建 php-apache 服务,利用 HPA 进行自动扩缩容。

  • #基于 dockerfile 构建一个 PHP-apache 项目
    1)创建并运行一个 php-apache 服务
    使用 dockerfile 构建一个新的镜像,在 k8s-master1 节点构建
    mkdir php
    cd php/
    vim dockerfile

     vim index.php

     #构建镜像
    docker build -t k8s.gcr.io/hpa-example:v1 .


    #打包镜像
    docker save -o hpa-example.tar.gz k8s.gcr.io/hpa-example:v1



    #解压镜像
    可以把镜像传到 k8s 的各个工作节点,通过 docker load -i hpa-example.tar.gz 进行解压:
    scp hpa-example.tar.gz k8s-01:/root/
    scp hpa-example.tar.gz k8s-02:/root/



    #通过 deployment 部署一个 php-apache 服务
    vim php-apache.yaml



     

  • 创建 HPA

  • php-apache 服务正在运行,使用 kubectl autoscale 创建自动缩放器,实现对 php-apache 这个deployment 创建的 pod 自动扩缩容,下面的命令将会创建一个 HPA,HPA 将会根据 CPU,内存等资源指标增加或减少副本数

    创建一个可以实现如下目的的 hpa:
    1)让副本数维持在 1-10 个之间(这里副本数指的是通过 deployment 部署的 pod 的副本数)
    2)将所有 Pod 的平均 CPU 使用率维持在 50%(通过 kubectl run 运行的每个 pod 如果是 200毫核,这意味着平均 CPU 利用率为 100 毫核)

  • 给上面 php-apache 这个 deployment 创建 HPA

    kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
    #上面命令解释说明
    kubectl autoscale deployment php-apache (php-apache 表示 deployment 的名字)
    --cpu-percent=50(表示 cpu 使用率不超过 50%)
    -min=1(最少一个 pod)
    --max=10(最多 10 个 pod)

  • #验证 HPA 是否创建成功
    kubectl get hpa 

    注:由于我们没有向服务器发送任何请求,因此当前 CPU 消耗为 0%(TARGET 列显示了由相应的 deployment 控制的所有 Pod 的平均值)。

  • 压测 php-apache 服务,只是针对 CPU 做压测
     

  • 启动一个容器,并将无限查询循环发送到 php-apache 服务,打开一个新的终端窗口):
    kubectl run v1 -it --image=busybox --image-pull-policy=IfNotPresent /bin/sh

    登录到容器之后,执行如下命令
    / # while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done

    在一分钟左右的时间内,我们通过执行以下命令来看到更高的 CPU 负载
    kubectl get hpa

    上面可以看到,CPU 消耗已经达到 215%,每个 pod 的目标 cpu 使用率是 50%,所以,phpapache 这个 deployment 创建的 pod 副本数将调整为 4 个副本,为什么是 4 个副 本,因为 215/50=4,REPLICAS 列显示为 4

    注意:需要几分钟来稳定副本数。由于不以任何方式控制负载量,因此最终副本数可能会与此示例不同。这里发现稳定副本为 7 个

  • 停止对 php-apache 服务压测,HPA 会自动对 php-apache 这个 deployment 创建的 pod 做缩容

  • 停止向 php-apache 这个服务发送查询请求,在 busybox 镜像创建容器的终端中,通过<Ctrl>+ C 把刚才 while 请求停止,然后,验证结果状态(大约五分钟后   视硬件配置我这里大概等了五分钟): 


    通过上面可以看到,CPU 利用率下降到 0,因此 HPA 自动将副本数缩减到 1。
    注意:自动缩放副本需要几分钟。
     

  • 利用 HPA 基于内存指标实现 pod 自动扩缩容

  • 创建一个 nginx 的 pod
    vim nginx.yaml

     注意:
    nginx 的 pod 里需要有如下字段,否则 hpa 会采集不到内存指标
    resources:
    requests:
    cpu: 0.01
    memory: 25Mi
    limits:
    cpu: 0.05
    memory: 60Mi


    创建一个 hpa
    vim hpa-v1.yaml

    压测 nginx 的内存,hpa 会对 pod 自动扩缩容
    登录到上面通过 pod 创建的 nginx,并生成一个文件,增加内存
    kubectl exec -it nginx-hpa-6675977fc6-dcxfs -- sh
    #压测
    # dd if=/dev/zero of=/tmp/a



    上面的 targets 列可看到 238%/60%,238%表示当前 cpu 使用率,60%表示所有 pod 的 cpu 使用率维持在 60%,现在 cpu 使用率达到 238%,所以 pod 增加到 4 个 

    取消对 nginx 内存的压测,hpa 会对 pod 自动缩容 

    deployment 的 pod 又恢复到了 1 个

    扩展:查看 v2 版本的 hpa 如何定义?
    kubectl get hpa.v2beta2.autoscaling -o yaml > 1.yaml

       

  • kubernetes cluster-autoscaler

  • 什么是 cluster-autoscaler

  • Cluster Autoscaler (CA)是一个独立程序,是用来弹性伸缩 kubernetes 集群。它可以自动根据部署应用所请求的资源量来动态的伸缩集群。当集群容量不足时,它会自动去 Cloud Provider (支持GCE、GKE 和 AWS)创建新的 Node,而在 Node 长时间资源利用率很低时自动将其删除以节省开支。
    项目地址:https://github.com/kubernetes/autoscaler

     

  • Cluster Autoscaler 什么时候伸缩集群?
    在以下情况下,集群自动扩容或者缩放:
    扩容:由于资源不足,某些 Pod 无法在任何当前节点上进行调度
    缩容: Node 节点资源利用率较低时,且此 node 节点上存在的 pod 都能被重新调度到其他 node节点上运行

  • 什么时候集群节点不会被 CA 删除?
    1)节点上有 pod 被 PodDisruptionBudget 控制器限制。
    2)节点上有命名空间是 kube-system 的 pods。
    3)节点上的 pod 不是被控制器创建,例如不是被 deployment, replica set, job, stateful set 创建。
    4)节点上有 pod 使用了本地存储
    5)节点上 pod 驱逐后无处可去,即没有其他 node 能调度这个 pod
    6)节点有注解:"cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"(在 CA 1.0.3 或更高版本中受支持)

  • 扩展:什么是 PodDisruptionBudget?
    通过 PodDisruptionBudget 控制器可以设置应用 POD 集群处于运行状态最低个数,也可以设置应用 POD 集群处于运行状态的最低百分比,这样可以保证在主动销毁应用 POD 的时候,不会一次性销毁太多的应用 POD,从而保证业务不中断

  • Horizontal Pod Autoscaler 如何与 Cluster Autoscaler 一起使用?
    Horizontal Pod Autoscaler 会根据当前 CPU 负载更改部署或副本集的副本数。如果负载增加,则 HPA 将创建新的副本,集群中可能有足够的空间,也可能没有足够的空间。如果没有足够的资源,CA将尝试启动一些节点,以便 HPA 创建的 Pod 可以运行。如果负载减少,则 HPA 将停止某些副本。结果,某些节点可能变得利用率过低或完全为空,然后 CA 将终止这些不需要的节点。

    扩展:如何防止节点被 CA 删除?
    节点可以打上以下标签:
    "cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"
    可以使用 kubectl 将其添加到节点(或从节点删除):
    $ kubectl annotate node <nodename> cluster-autoscaler.kubernetes.io/scale-downdisabled=true

  • Cluster Autoscaler 支持那些云厂商?
    GCE https://kubernetes.io/docs/concepts/cluster-administration/cluster-management/

    GKE https://cloud.google.com/container-engine/docs/cluster-autoscaler

    AWS(亚马逊) https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/aws/README.md
    Azure(微软) https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/azure/README.md
    Alibaba Cloud https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/alicloud/README.md
    OpenStack Magnum https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/magnum/README.md
    DigitalOcean https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/digitalocean/README.md
    CloudStack https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/cloudstack/README.md
    Exoscale https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/exoscale/README.md
    Packet https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/packet/README.md
    OVHcloud https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/ovhcloud/README.md
    Linode https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/linode/README.md
    Hetzner https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/hetzner/README.md
    Cluster API https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/clusterapi/README.md

     

以上是关于kubernetes 中如何实现 Pod 自动扩缩容的主要内容,如果未能解决你的问题,请参考以下文章

[kubernetes] HPA实现自动水平伸缩POD

3个自动伸缩机制,帮你降低Kubernetes的成本

Kubernetes水平自动扩缩容Hpa-超详细文档

Pod的扩缩容

Kubernetes对象之Pod详解(附安装部署方法)

Kubernetes HPA 动态弹性扩缩容