什么是HPA

我们的k8s集群 如果是 针对node层面是有Cluster Autoscaler弹性伸缩来做高可用和成本控制的优化的。

也就是说 我们一开始 没有pod任务在运行的时候 不需要node节点时,k8s的集群可以只启动少量node节点来做常驻服务pod的部署。 当 有大批量的任务pod 需要运行时, k8s集群会根据 每个pod需要的资源状态来 申请启动新的node节点。 当任务高峰期过后,pod运行的数量减少,node的数量就会收缩,不使用的node会被回收,保证 k8s集群的高可用低成本运行。

那么问题来了,常驻服务用来提供给外部的pod又怎么实现高可用呢? 我们一般会使用Deployment中的replicas参数,设置多个副本集来保证 服务的高可用,但是 这是一个固定的值,比如 我们设置10个副本,这个常驻服务就会 启动10个pod 同时running来提供服务。

如果 这个服务 平时流量很少的时候,也是10个pod同时在running,而 流量突然暴增时,又可能出现10个pod不够用的情况。

针对这样的场景,k8s有一个组件可以解决这个问题。

Horizontal Pod Autoscaling(POD水平自动伸缩)可以根据指标自动伸缩一个Replication Controller、Deployment 或者Replica Set中的Pod数量

HPA(Horizontal Pod Autoscaler)是kubernetes(以下简称k8s)的一种资源对象,能够根据某些指标对在statefulSet、replicaController、replicaSet等集合中的pod数量进行动态伸缩,使运行在上面的服务对指标的变化有一定的自适应能力,实现pod层面的自动伸缩。pod自动缩放不适用于无法缩放的对象,比如DaemonSets。

HPA目前支持四种类型的指标,分别是Resource、Object、External、Pods。其中在稳定版本autoscaling/v1中只支持对CPU指标的动态伸缩,在测试版本autoscaling/v2beta2中支持memory和自定义指标的动态伸缩,并以annotation的方式工作在autoscaling/v1版本中。

HPA的原理

在这里插入图片描述

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

支持的指标

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

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

指标从哪里来

资源监控系统是容器编排系统必不可少的组件,它为用户提供了快速了解系统资源分配和利用状态的有效途径,同时也是系统编排赖以实现的基础要件。

老的版本使用Heapster进行集群各项资源指标数据的采集,从kubernetes1.11开始Heapster被废弃不在使用,metrics-server 替代了heapster。

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

本文介绍K8S集群基于metric server的HPA。在开始之前我们需要了解一下Metrics API和Metrics Server

Metrics API:
1、通过Metrics API我们可以获取到指定node或者pod的当前资源使用情况,API本身不存储任何信息,所以我们不可能通过API来获取资源的历史使用情况。
2、Metrics API的获取路径位于:/apis/metrics.k8s.io/
3、获取Metrics API的前提条件是metrics server要在K8S集群中成功部署
4、更多的metrics资料请参考:https://github.com/kubernetes/metrics

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

HPA如何运作

Horizontal Pod AutoScaler被实现为一个控制循环,周期由控制器管理器的–Horizontal Pod AutoScaler sync period标志(默认值为15秒)控制。

在每个期间,控制器管理器都会根据每个HorizontalPodAutoScaler定义中指定的度量来查询资源利用率。控制器管理器从资源度量api(针对每个pod的资源度量)或自定义度量api(针对所有其他度量)获取度量。

对于每个pod的资源度量(如cpu),控制器从horizontalpodautoscaler针对每个pod的资源度量api获取度量。然后,如果设置了目标利用率值,则控制器将利用率值计算为每个pod中容器上等效资源请求的百分比。如果设置了目标原始值,则直接使用原始度量值。然后,控制器获取所有目标pod的利用率平均值或原始值(取决于指定的目标类型),并生成用于缩放所需副本数量的比率。

HPA自动伸缩的过程:

HPA伸缩过程叙述
HPA的伸缩主要流程如下:

1、判断当前pod数量是否在HPA设定的pod数量区间中,如果不在,过小返回最小值,过大返回最大值,结束伸缩。

2、判断指标的类型,并向api server发送对应的请求,拿到设定的监控指标。一般来说指标会根据预先设定的指标从以下三个aggregated APIs中获取:metrics.k8s.io、custom.metrics.k8s.io、 external.metrics.k8s.io。其中metrics.k8s.io一般由k8s自带的metrics-server来提供,主要是cpu,memory使用率指标,另外两种需要第三方的adapter来提供。custom.metrics.k8s.io提供自定义指标数据,一般跟k8s集群有关,比如跟特定的pod相关。external.metrics.k8s.io同样提供自定义指标数据,但一般跟k8s集群无关。许多知名的第三方监控平台提供了adapter实现了上述api(如prometheus),可以将监控和adapter一同部署在k8s集群中提供服务,甚至能够替换原来的metrics-server来提供上述三类api指标,达到深度定制监控数据的目的。

3、根据获得的指标,应用相应的算法算出一个伸缩系数,并乘以目前pod数量获得期望pod数量。系数是指标的期望值与目前值的比值,如果大于1表示扩容,小于1表示缩容。指标数值有平均值(AverageValue)、平均使用率(Utilization)、裸值(Value)三种类型,每种类型的数值都有对应的算法。以下几点值得注意:如果系数有小数点,统一进一;系数如果未达到某个容忍值,HPA认为变化太小,会忽略这次变化,容忍值默认为0.1。

HPA扩容算法是一个非常保守的算法。如果出现获取不到指标的情况,扩容时算最小值,缩容时算最大值;如果需要计算平均值,出现pod没准备好的情况,平均数的分母不计入该pod。
一个HPA支持多个指标的监控,HPA会循环获取所有的指标,并计算期望的pod数量,并从期望结果中获得最大的pod数量作为最终的伸缩的pod数量。一个伸缩对象在k8s中允许对应多个HPA,但是只是k8s不会报错而已,事实上HPA彼此不知道自己监控的是同一个伸缩对象,在这个伸缩对象中的pod会被多个HPA无意义地来回修改pod数量,给系统增加消耗,如果想要指定多个监控指标,可以如上述所说,在一个HPA中添加多个监控指标。

4、检查最终的pod数量是否在HPA设定的pod数量范围的区间,如果超过最大值或不足最小值都会修改为最大值或最小值。然后向k8s发出请求,修改伸缩对象的子对象scale的pod数量,结束一个HPA的检查,获取下一个HPA,完成一个伸缩流程。

为什么v1正式版本使用的指标是 cpu?

v1的模板可能是大家平时见到最多的也是最简单的,v1版本的HPA只支持一种指标 —— CPU。传统意义上,弹性伸缩最少也会支持CPU与Memory两种指标,为什么在Kubernetes中只放开了CPU呢?其实最早的HPA是计划同时支持这两种指标的,但是实际的开发测试中发现,内存不是一个非常好的弹性伸缩判断条件。因为和CPU不同,很多内存型的应用,并不会因为HPA弹出新的容器而带来内存的快速回收,因为很多应用的内存都要交给语言层面的VM进行管理,也就是内存的回收是由VM的GC来决定的。这就有可能因为GC时间的差异导致HPA在不恰当的时间点震荡,因此在v1的版本中,HPA就只支持了CPU一种指标。

HPA与rolling update的区别

目前在kubernetes中,可以通过直接管理复制控制器来执行滚动更新,也可以使用deployment对象来管理底层副本集。HPA只支持后一种方法:HPA绑定到部署对象,设置部署对象的大小,部署负责设置底层副本集的大小。

HPA不能使用复制控制器的直接操作进行滚动更新,即不能将HPA绑定到复制控制器并进行滚动更新(例如,使用Kubectl滚动更新)。这不起作用的原因是,当滚动更新创建新的复制控制器时,HPA将不会绑定到新的复制控制器。

HPA的应用场景

HPA的特性结合第三方的监控应用,使得部署在HPA伸缩对象(statefulSet、replicaController、replicaSet)上的服务有了非常灵活的自适应能力,能够在一定限度内复制多个副本来应对某个指标的急剧飙升,也可以在某个指标较小的情况下删除副本来让出计算资源给其他更需要资源的应用使用,维持整个系统的稳定。非常适合于一些流量波动大,机器资源吃紧,服务数量多的业务场景,如:电商服务、抢票服务、金融服务等。

使用HPA的前提–部署metrics-server

尝试运行kubectl top命令

Metrics-server正常安装完成后就可以使用kubectl top命令显示节点和pod对象的资源使用信息。

# 显示各节点的资源使用信息
# kubectl top nodes
NAME                   CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
master01.dayi123.com   200m         10%    1106Mi          64%       
node01.dayi123.com     44m          4%     649Mi           46%       
node02.dayi123.com     84m          4%     929Mi           54%
# 显示符合条件的pod的资源使用信息
# kubectl top pods -n kube-system -l  k8s-app=kubernetes-dashboard
NAME                                    CPU(cores)   MEMORY(bytes)   
kubernetes-dashboard-76479d66bb-9xhkf   1m           20Mi 

如果已经能够使用kubectl top命令,则可跳过安装Metrics-server。

否则可以参考以下步骤安装:

拉取资源,替换可用镜像

# git clone https://github.com/kubernetes-incubator/metrics-server


# 替换metrics-server/deploy/1.8+/metrics-server-deployment.yaml的镜像地址为deploy/1.8+/metrics-server-deployment.yaml

# sed -i "s#k8s.gcr.io/metrics-server-amd64:v0.3.3#mirrorgooglecontainers/metrics-server-amd64:v0.3.1#g" /tmp/metrics-server/deploy/1.8+/metrics-server-deployment.yaml

去除https验证

由于metrics-server默认使用节点hostname通过kubelet 10250端口获取数据,但是coredns里面没有该数据无法解析,所以可在metrics server启动命令添加参数 --kubelet-preferred-address-types=InternalIP 直接使用节点IP地址获取数据;同时由于kubelet 的10250端口使用的是https协议,连接需要验证tls证书。可以在metrics server启动命令添加参数–kubelet-insecure-tls不验证客户端证书。

# 在配置文件metrics-server/deploy/1.8+/metrics-server-deployment.yaml添加启动参数
command:
- /metrics-server
- --metric-resolution=30s
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP

创建资源

# kubectl create -f metrics-server/deploy/1.8+/metrics-server-deployment.yaml 
serviceaccount/metrics-server created
deployment.extensions/metrics-server created

验证metrics-server是否部署成功

kubectl get pods -n kube-system

显示如下running状态说明启动成功

测试kubectl top命令

metrics-server组件安装成功之后,就可以使用kubectl top命令了

kubectl top nodes
显示如下:
NAME          CPU(cores)    CPU%     MEMORY(bytes)   MEMORY% 
k8s-master     660m          16%      1608Mi          20%      
k8s-node       348m          8%       1046Mi          28%  
 
kubectl top pods -n kube-system
显示如下:
NAME                                 CPU(cores)   MEMORY(bytes)  
calico-node-9wkmr                    100m         26Mi           
calico-node-sp5m6                    162m         35Mi           
coredns-6955765f44-j2xrl             8m           8Mi            
coredns-6955765f44-th2sb             10m          8Mi            
etcd-k8s-master                      48m          44Mi           
kube-apiserver-k8s-master            128m         286Mi          
kube-controller-manager-k8s-master   79m         38Mi           
kube-proxy-9s48h                     2m           17Mi           
kube-proxy-vcx2s                     2m           10Mi           
kube-scheduler-k8s-master            12m          15Mi           
metrics-server-5cf9669fbf-jmrdx       3m           17Mi

通过api验证metrics-server可用方式

# 让metrics api可访问
# kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080

另开一个窗口检查node节点可用性

# curl http://localhost:8080/apis/metrics.k8s.io/v1beta1/nodes
{
  "kind": "NodeMetricsList",
  "apiVersion": "metrics.k8s.io/v1beta1",
  "metadata": {
    "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes"
  },
  "items": [
    {
      "metadata": {
        "name": "master01.dayi123.com",
        "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/master01.dayi123.com",
        "creationTimestamp": "2019-06-13T11:02:57Z"
      },
      "timestamp": "2019-06-13T11:03:19Z",
      "window": "30s",
      "usage": {
        "cpu": "222451436n",
        "memory": "1129748Ki"
      }

获取集群上所有pod对象的相关资源消耗数据

# curl http://localhost:8080/apis/metrics.k8s.io/v1beta1/pods

给我们的服务加上HPA部署—以nginx为例

需要注意:部署pod时候要设置资源requests

使用HPA–v1版本控制器

HPA v1 只支持根据cpu来进行自动伸缩,使用的方式也很简单,不需要修改服务本身的yaml

使用命令如下:

# 先创建一个deployment控制器
# kubectl run mynginx --image=nginx:1.12 --replicas=2 --requests='cpu=5m,memory=128Mi' --limits='cpu=50m,memory=128Mi' --labels='app=mynginx' --expose --port=80


# 或者使用yaml 进行创建
kubectl create -f  mynginx.yaml


# 创建HPA控制器自动管控Pod副本
# kubectl autoscale deploy mynginx --min=2 --max=5 --cpu-percent=60


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

参数解释:
–cpu-percent=60(表示cpu使用率不超过60%,出现cpu超过60%时则进行自动伸缩)
–min=2(最少两个pod)
–max=5(最多5个pod)

使用HPA–v2版本控制器

测试HPA autoscaling/v2beta1版本-基于内存的自动扩缩容

创建一个nginx的Deployment

vi nginx.yaml

内容如下:

apiVersion:apps/v1
kind: Deployment
metadata:
  name:nginx-hpa
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        resources:
          requests:
            cpu: 0.01
            memory: 25Mi
          limits:
            cpu: 0.05
            memory: 60Mi
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  type: NodePort
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30080

创建nginx

kubectl apply -f nginx.yaml

验证nginx是否运行

kubectl get pods

显示如下,说明nginx的pod正常运行:

NAME                       READY  STATUS    RESTARTS   AGE
nginx-hpa-bb598885d-j4kcp 1/1     Running   0         17m

注意:nginx的pod里需要有如下字段,否则hpa会采集不到内存指标

resources:
   requests:
     cpu: 0.01
     memory: 25Mi
   limits:
      cpu: 0.05
      memory: 60Mi

创建一个hpa

创建yaml

vi hpa-v2.yaml

内容如下:

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
    maxReplicas: 10
    minReplicas: 1
    scaleTargetRef:
      apiVersion:apps/v1
      kind: Deployment
      name: nginx-hpa
    metrics:
    - type: Resource
      resource:
        name: cpu
        targetAverageUtilization: 50
    - type: Resource
      resource:
        name: memory
        targetAverageUtilization: 60

官方完整yaml示例如下:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  # HPA的伸缩对象描述,HPA会动态修改该对象的pod数量
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  # HPA的最小pod数量和最大pod数量
  minReplicas: 1
  maxReplicas: 10
  # 监控的指标数组,支持多种类型的指标共存
  metrics:
  # Object类型的指标
  - type: Object
    object:
      metric:
        # 指标名称
        name: requests-per-second
      # 监控指标的对象描述,指标数据来源于该对象
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      # Value类型的目标值,Object类型的指标只支持Value和AverageValue类型的目标值
      target:
        type: Value
        value: 10k
  # Resource类型的指标
  - type: Resource
    resource:
      name: cpu
      # Utilization类型的目标值,Resource类型的指标只支持Utilization和AverageValue类型的目标值
      target:
        type: Utilization
        averageUtilization: 50
  # Pods类型的指标
  - type: Pods
    pods:
      metric:
        name: packets-per-second
      # AverageValue类型的目标值,Pods指标类型下只支持AverageValue类型的目标值
      target:
        type: AverageValue
        averageValue: 1k
  # External类型的指标
  - type: External
    external:
      metric:
        name: queue_messages_ready
        # 该字段与第三方的指标标签相关联,(此处官方文档有问题,正确的写法如下)
        selector:
          matchLabels:
            env: "stage"
            app: "myapp"
      # External指标类型下只支持Value和AverageValue类型的目标值
      target:
        type: AverageValue
        averageValue: 30

参数解释:
spec中嵌套的个字段的说明如下:

(1)maxReplicas:自动伸缩可扩展至Pod副本数的上限
(2)minReplicas:自动伸缩pod副本数下限
(3)scaleTargetRef:要伸缩的目标资源
(4)metrics:用于计算所需的Pod副本数量的指标列表
(5)external:用于应用非附属于任何对象的全局指标
(6)object:应用描述集群中某单一对象的特定指标
(7)pods:应用被弹性伸缩的pod对象的特定指标
(8)resource:应用资源指标,即当前被弹性伸缩的pod对象中容器的requests和limits中定义的指标。
(9)type:标识指标源的类型

创建hpa

kubectl apply -f hpa-v2.yaml

查看创建状态

kubectl get hpa

显示如下:

NAME  REFERENCE TARGETS  MINPODS MAXPODS  REPLICAS AGE
nginx-hpa  Deployment/nginx-hpa   5%/60%    1      10  1      20s

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

登录到上面通过pod创建的nginx,并生成一个文件,增加内存

kubectl exec -it nginx-hpa-bb598885d-j4kcp – /bin/sh

在pod中使用命令进行压测:

ddif=/dev/zero of=/tmp/a

打开新的终端:

kubectl get hpa

显示如下:

NAME       REFERENCE              TARGETS    MINPODS  MAXPODS   REPLICAS   AGE
nginx-hpa  Deployment/nginx-hpa   200%/60%  1         10        3          12m

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

kubectl get deployment

显示如下:

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
nginx-hpa    4/4     4            4           25m

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

kubectl exec -it nginx-hpa-bb598885d-j4kcp -- /bin/sh

删除/tmp/a这个文件

rm -rf /tmp/a

在新终端中使用命令

kubectl get hpa

显示如下,可看到内存使用率已经降到5%:

NAME        REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
nginx-hpa   Deployment/nginx-hpa   5%/60%    1         10        1          26m

查看deployment

kubectl get deployment

显示如下,deployment的pod又恢复到1个了:

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
nginx-hpa    1/1     1            1           38m

基于多项指标和自定义指标的自动缩放

可以通过使用autoscaling/v2beta2 API版本 来创建 根据 其他度量指标(metrics)进行自动伸缩的deployment。

使用yaml如下:

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
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
      current:
        averageUtilization: 0
        averageValue: 0

targetCPUUtilizationPercentage字段由metrics所取代,CPU利用率这个度量指标是一个resource metric(资源度量指标),因为它表示容器上指定资源的百分比。

除CPU外,你还可以指定其他资源度量指标。

默认情况下,目前唯一支持的其他资源度量指标为内存。

只要metrics.k8s.io API存在,这些资源度量指标就是可用的,并且他们不会在不同的Kubernetes集群中改变名称。

你还可以指定资源度量指标使用绝对数值,而不是百分比,你需要将target类型AverageUtilization替换成AverageValue,同时将target.averageUtilization替换成target.averageValue并设定相应的值。

还有两种其他类型的度量指标,他们被认为是custom metrics(自定义度量指标): 即Pod度量指标和对象度量指标(pod metrics and object metrics)。

这些度量指标可能具有特定于集群的名称,并且需要更高级的集群监控设置。

使用度量指标类型—Pod度量指标

第一种可选的度量指标类型是Pod度量指标。这些指标从某一方面描述了Pod,在不同Pod之间进行平均,并通过与一个目标值比对来确定副本的数量。

它们的工作方式与资源度量指标非常相像,差别是它们仅支持target类型为AverageValue。

Pod 度量指标通过如下代码块定义

type: Pods
pods:
  metric:
    name: packets-per-second
  target:
    type: AverageValue
    averageValue: 1k

使用度量指标类型—对象度量指标

第二种可选的度量指标类型是对象度量指标。

相对于描述Pod,这些度量指标用于描述一个在相同名字空间(namespace)中的其他对象。

请注意这些度量指标用于描述这些对象,并非从对象中获取。

对象度量指标支持的target类型包括Value和AverageValue。

如果是Value类型,target值将直接与API返回的度量指标比较,而AverageValue类型,API返回的度量指标将按照Pod数量拆分,然后再与target值比较。

下面的YAML文件展示了一个表示requests-per-second的度量指标。

type: Object
object:
  metric:
    name: requests-per-second
  describedObject:
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    name: main-route
  target:
    type: Value
    value: 2k

如果你指定了多个上述类型的度量指标,HorizontalPodAutoscaler将会依次考量各个指标

HorizontalPodAutoscaler将会计算每一个指标所提议的副本数量,然后最终选择一个最高值。

比如,如果你的监控系统能够提供网络流量数据,你可以通过kubectl edit命令将上述Horizontal Pod Autoscaler的定义更改为:

apiVersion: autoscaling/v2beta1
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: AverageUtilization
        averageUtilization: 50
  - type: Pods
    pods:
      metric:
        name: packets-per-second
      targetAverageValue: 1k
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      target:
        kind: Value
        value: 10k
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
    current:
      averageUtilization: 0
      averageValue: 0
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      current:
        value: 10k

然后,你的HorizontalPodAutoscaler将会尝试确保每个Pod的CPU利用率在50%以内,每秒能够服务1000个数据包请求,并确保所有在Ingress后的Pod每秒能够服务的请求总数达到10000个。

在更多指定指标下的自动伸缩

许多度量管道允许你通过名称或附加的_labels_来描述度量指标。

对于所有非资源类型度量指标(pod、object和后面将介绍的external),可以额外指定一个标签选择器。

例如,如果你希望收集包含verb标签的http_requests度量指标, 你可以在GET请求中指定需要的度量指标,如下所示:

type:Object
object:
  metric:
    name:`http_requests`
    selector:`verb=GET`

这个选择器使用与Kubernetes标签选择器相同的语法。如果名称和标签选择器匹配到多个系列,监测管道会决定如何将多个系列合并成单个值。选择器是附加的,它不会选择目标以外的对象(类型为Pods的目标和类型为Object的目标)。

基于kubernetes对象以外的度量指标自动扩缩容

运行在Kubernetes上的应用程序可能需要基于与Kubernetes集群中的任何对象没有明显关系的度量指标进行自动伸缩,例如那些描述不在Kubernetes任何namespaces服务的度量指标。

使用外部的度量指标,需要了解你使用的监控系统,相关的设置与使用自定义指标类似。

External metrics可以使用你的监控系统的任何指标来自动伸缩你的集群。

你只需要在metric块中提供name和selector,同时将类型由Object改为External。

如果metricSelector匹配到多个度量指标,HorizontalPodAutoscaler将会把它们加和。

External metrics同时支持Value和AverageValue类型,这与Object类型的度量指标相同。

例如,如果你的应用程序处理主机上的消息队列, 为了让每30个任务有1个worker,你可以将下面的内容添加到 HorizontalPodAutoscaler 的配置中。

-type:External
  external:
    metric:
      name:queue_messages_ready
      selector:"queue=worker_tasks"
    target:
      type:AverageValue
      averageValue:30

还是推荐custom metric而不是external metrics,因为这便于让系统管理员加固custom metrics API。而external metrics API可以允许访问所有的度量指标,当暴露这些服务时,系统管理员需要仔细考虑这个问题。

HPA常用命令

kubectl get hpa

kubectl describe hpa tomcat-shopxx-hpa 


关于HPA的思考

在某些热点新闻的高流量下2分钟内就需要扩容上千台机器,k8s 默认的弹性扩容是解决不了这个问题的 (因为默认的调度机制是串行的,需要做 hack 才可以)。

之前蚂蚁的人介绍他们的双十一架构,可以很短的时间扩容几千个机器,怎么做到的呢? 把 k8s 默认的调度算法从原来的顺序的调度改为了批量的调度,满足了这个大促的场景。

另外最重要的一点是如何判断触发扩容缩容的时机,今天从网上的一个 2015 年的论文里找到了一个方法论,介绍了如何用工业界的 质量控制图 和 区间法则找出了异常的数据波段,并进行扩容或缩容。大体上微博的做法也和这个类似,因此了解下这个论文还是很有帮助的。

总之,k8s HPA 的这个功能只能处理非常简单的场景,距离真正线上应用使用还很遥远,而且这个功能和 k8s 平台关系不大,应该在非 k8s 环境下就要能够做到甄别出应用的异常流量。

参考链接

https://www.jianshu.com/p/7842437235f2
https://zhuanlan.zhihu.com/p/89453704
https://blog.csdn.net/textdemo123/article/details/100654364
https://www.cnblogs.com/zjz20/p/13397668.html

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐