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工作原理

kubernetes 垂直扩容 kubernetes动态扩容_容器

 

  • 自动检测周期由 kube-controller-manager 的 --horizontal-pod-autoscaler-sync-period 参数设置(默认间隔为 15 秒)。
  • metrics-server 提供 metrics.k8s.io API 为pod资源的使用提供支持。
  • 15s/周期 -> 查询metrics.k8s.io API -> 算法计算 -> 调用scale 调度 -> 特定的扩缩容策略执行。

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

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

kubernetes 垂直扩容 kubernetes动态扩容_Pod_02

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,不断循环

关于HPA的概述

Horizontal Pod Autoscaler(HPA,Pod水平自动伸缩),根据平均 CPU 利用率、平均内存利用率或你指定的任何其他自定义指标自动调整 Deployment 、ReplicaSet 或 StatefulSet 或其他类似资源,实现部署的自动扩展和缩减,让部署的规模接近于实际服务的负载。HPA不适用于无法缩放的对象,例如DaemonSet。

官方文档:https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale/

实际生产中,一般使用这四类指标:

  • Resource metrics——CPU核 和 内存利用率指标。
  • Pod metrics——例如网络利用率和流量。
  • Object metrics——特定对象的指标,比如Ingress, 可以按每秒使用请求数来扩展容器。
  • Custom metrics——自定义监控,比如通过定义服务响应时间,当响应时间达到一定指标时自动扩容。

安装 metrics-server

HAP 前提条件

默认情况下,Horizontal Pod Autoscaler 控制器会从一系列的 API 中检索度量值。集群管理员需要确保下述条件,以保证 HPA 控制器能够访问这些 API:

  • 对于资源指标,将使用 metrics.k8s.io API,一般由 metrics-server 提供。它可以作为集群插件启动。
  • 对于自定义指标,将使用 custom.metrics.k8s.io API。它由其他度量指标方案厂商的“适配器(Adapter)” API 服务器提供。检查你的指标管道以查看是否有可用的 Kubernetes 指标适配器。
  • 对于外部指标,将使用 external.metrics.k8s.io API。可能由上面的自定义指标适配器提供。

Kubernetes Metrics Server:

  • Kubernetes Metrics Server 是 Cluster 的核心监控数据的聚合器,kubeadm 默认是不部署的。
  • Metrics Server 供 Dashboard 等其他组件使用,是一个扩展的 APIServer,依赖于 API Aggregator。所以,在安装 Metrics Server 之前需要先在 kube-apiserver 中开启 API Aggregator。
  • Metrics API 只可以查询当前的度量数据,并不保存历史数据。
  • Metrics API URI 为 /apis/metrics.k8s.io/,在 k8s.io/metrics 下维护。
  • 必须部署 metrics-server 才能使用该 API,metrics-server 通过调用 kubelet Summary API 获取数据。

开启 API Aggregator

# 添加这行
# --enable-aggregator-routing=true
### 修改每个 API Server 的 kube-apiserver.yaml 配置开启 Aggregator Routing:修改 manifests 配置后 API Server 会自动重启生效。
cat /etc/kubernetes/manifests/kube-apiserver.yaml

kubernetes 垂直扩容 kubernetes动态扩容_Pod_03

 

开始安装 metrics-server

GitHub地址:https://github.com/kubernetes-sigs/metrics-server/releases

下载

wget https://github.com/kubernetes-sigs/metrics-server/releases/download/metrics-server-helm-chart-3.8.2/components.yaml

修改

...
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=4443
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
        - --kubelet-use-node-status-port
        - --kubelet-insecure-tls                    #   加上该启动参数,不加可能会报错
        image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1   # 镜像地址根据情况修改
        imagePullPolicy: IfNotPresent
...
metrics-server pod无法启动,出现日志unable to fully collect metrics: ... x509: cannot validate certificate for because ... it doesn't contain any IP SANs ...

解决方法:在metrics-server中添加--kubelet-insecure-tls参数跳过证书校验

kubernetes 垂直扩容 kubernetes动态扩容_kubernetes 垂直扩容_04

 开始安装

kubectl apply -f components.yaml
kubectl get pod -n kube-system | grep metrics-server
# 查看
kubectl get pod -n kube-system | grep metrics-server
# 查看node和pod资源使用情况
kubectl top nodes
kubectl top pods

kubernetes 垂直扩容 kubernetes动态扩容_java_05

HPA的扩缩容算法

从最基本的角度来看,Pod 水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例。

期望副本数 = ceil[当前副本数 * (当前指标 / 期望指标)]

扩容

如果计算出的扩缩比例接近 1.0, 将会放弃本次扩缩, 度量指标 / 期望指标接近1.0。

缩容

冷却/延迟: 如果延迟(冷却)时间设置的太短,那么副本数量有可能跟以前一样出现抖动。默认值是 5 分钟(5m0s)--horizontal-pod-autoscaler-downscale-stabilization

特殊处理

  • 丢失度量值:缩小时假设这些 Pod 消耗了目标值的 100%, 在需要放大时假设这些 Pod 消耗了 0% 目标值。这可以在一定程度上抑制扩缩的幅度。
  • 存在未就绪的pod的时候:我们保守地假设尚未就绪的 Pod 消耗了期望指标的 0%,从而进一步降低了扩缩的幅度。
  • 未就绪的 Pod 和缺少指标的 Pod 考虑进来再次计算使用率。如果新的比率与扩缩方向相反,或者在容忍范围内,则跳过扩缩。否则,我们使用新的扩缩比例。指定了多个指标, 那么会按照每个指标分别计算扩缩副本数,取最大值进行扩缩

HPA 对象定义

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx
spec:
  behavior:
  scaleDown:
    policies:
    - type: Pods
      value: 4
      periodSeconds: 60
    - type: Percent
      value: 10
      periodSeconds: 60
    stabilizationWindowSeconds: 300
  
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

HPA对象默认行为

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
    - type: Pods
      value: 4
      periodSeconds: 15
    selectPolicy: Max

示例演示

编排yaml

loyment
    name: hap-nginx
---
apiVersion: v1
kind: Service
metadata:
  name: hap-nginx
spec:
  type: NodePort
  ports:
    - name: "http"
      port: 80
      targetPort: 80
      nodePort: 30080
  selector:
    service: hap-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hap-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      service: hap-nginx
  template:
    metadata:
      labels:
        service: hap-nginx
    spec:
      containers:
        - name: hap-nginx
          image: nginx:latest
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
            limits:
              cpu: 200m
              memory: 200Mi

主要参数解释如下:

  • scaleTargetRef:目标作用对象,可以是Deployment、ReplicationController或ReplicaSet。
  • minReplicas和maxReplicas:Pod副本数量的最小值和最大值,系统将在这个范围内进行自动扩缩容操作,并维持每个Pod的内存使用率为40%,这个值就是上面设置的阈值averageUtilization。
  • metrics:目标指标值。在metrics中通过参数type定义指标的类型;通过参数target定义相应的指标目标值,系统将在指标数据达到目标值时(考虑容忍度的区间,见前面算法部分的说明)触发扩缩容操作。
  • 对于CPU使用率,在target参数中设置averageUtilization定义目标平均CPU使用率。
  • 对于内存资源,在target参数中设置AverageValue定义目标平均内存使用值。

执行

kubectl apply -f test.yaml

使用 ab 工具进行压测

进入apache官网 http://httpd.apache.org/ 下载apache即可,或者直接通过yum安装apache都行,这里选择最简单的方式yum安装

yum install httpd -y

开始压测

ab -n 100000 -c 800 http://local-168-161-11:30080/

#-c:并发数
#-n:总请求数

kubernetes 垂直扩容 kubernetes动态扩容_java_06

  

kubernetes 垂直扩容 kubernetes动态扩容_Pod_07