Pod的扩缩容

Pod的扩缩容

实际生产系统, 会遇到某个服务需要扩容的场景,也可能会遇到由于资源紧张或者工作负载降低而需要减少服务实例数量的场景。

此时可以利用Deployment/RCScale机制来完成这些工作。

Kubernetes对Pod的扩缩容操作提供了手动自动两种模式.

手动模式通过执行kubectl scale命令或通过RESTful API对一个Deployment/RC进行Pod副本数量的设置,即可一键完成

自动模式则需要用户根据某个性能指标或者自定义业务指标,并指定Pod副本数量的范围,系统将自动在这个范围内根据性能指标的变化进行调整。

手动扩缩容机制

以Deployment nginx为例:

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
[root@k8s-master01 pod]# kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-56bbb744cc-lb28h   1/1     Running   1          24h
nginx-deployment-56bbb744cc-nwhgk   1/1     Running   1          24h
nginx-deployment-56bbb744cc-z2k5h   1/1     Running   1          24h

# 通过kubectl scale命令可以将Pod副本数量从初始的3个更新为5个:
[root@k8s-master01 pod]# kubectl scale deployment/nginx-deployment --replicas 5
deployment.apps/nginx-deployment scaled
[root@k8s-master01 pod]# kubectl get pods
NAME                                READY   STATUS              RESTARTS   AGE
nginx-deployment-56bbb744cc-5sr67   0/1     ContainerCreating   0          1s
nginx-deployment-56bbb744cc-lb28h   1/1     Running             1          24h
nginx-deployment-56bbb744cc-nwhgk   1/1     Running             1          24h
nginx-deployment-56bbb744cc-wxn5c   0/1     ContainerCreating   0          1s
nginx-deployment-56bbb744cc-z2k5h   1/1     Running             1          24h

# 将--replicas设置为比当前Pod副本数量更小的数字,系统将会“杀掉”一些运行中的Pod,以实现应用集群缩容:
[root@k8s-master01 pod]# kubectl scale deployment/nginx-deployment --replicas 1
deployment.apps/nginx-deployment scaled
[root@k8s-master01 pod]# kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-56bbb744cc-z2k5h   1/1     Running   1          24h

自动扩缩容机制

Kubernetes从1.1版本开始,新增了名为Horizontal Pod Autoscaler(HPA)的控制器,用于实现基于CPU使用率进行自动Pod扩缩容的功能。

HPA控制器基于Masterkube-controller-manager服务启动参数--horizontal-pod-autoscaler-sync-period定义的探测周期(默认值为15s),周期性地监测目标Pod的资源性能指标,并与HPA资源对象中的扩缩容条件进行对比,在满足条件时对Pod副本数量进行调整。

HPA的工作原理

Kubernetes中的某个Metrics ServerHeapster自定义Metrics Server)持续采集所有Pod副本的指标数据

HPA控制器通过Metrics ServerAPI(Heapster的API或聚合API)获取这些数据,基于用户定义的扩缩容规则进行计算,得到目标Pod副本数量

当目标Pod副本数量与当前副本数量不同时,HPA控制器就向Pod的副本控制器DeploymentRCReplicaSet)发起scale操作,调整Pod的副本数量,完成扩缩容操作。

image.png
指标的类型

Master的kube-controller-manager服务持续监测目标Pod的某种性能指标,以计算是否需要调整副本数量。

目前Kubernetes支持的指标类型如下。

  • Pod资源使用率:Pod级别的性能指标,通常是一个比率值,例如CPU使用率
  • Pod自定义指标:Pod级别的性能指标,通常是一个数值,例如接收的请求数量。
  • Object自定义指标或外部自定义指标:通常是一个数值,需要容器应用以某种方式提供,例如通过HTTP URL“/metrics”提供,或者使用外部服务提供的指标采集URL。

Kubernetes从1.11版本开始,弃用!!! 基于Heapster组件完成Pod的CPU使用率采集的机制,全面转向基于Metrics Server完成数据采集

Metrics Server将采集到的Pod性能指标数据通过聚合API(Aggregated API)如metrics.k8s.io、custom.metrics.k8s.io和external.metrics.k8s.io提供给HPA控制器进行查询。

扩缩容算法详解

Autoscaler控制器聚合API获取到Pod性能指标数据之后,基于下面的算法计算出目标Pod副本数量,与当前运行的Pod副本数量进行对比,决定是否需要进行扩缩容操作:

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desireMetricValue)]

当前副本数 ×(当前指标值/期望的指标值),将结果向上取整

CPU请求数量为例,如果用户设置的期望指标值为100m,当前实际使用的指标值为200m,则计算得到期望的Pod副本数量应为两个(200/100=2)。如果设置的期望指标值为50m,计算结果为0.5,则向上取整值为1,得到目标Pod副本数量应为1个。

当计算结果与1非常接近时,可以设置一个容忍度让系统不做扩缩容操作。容忍度通过kube-controller-manager服务的启动参数--horizontal-pod-autoscaler-tolerance进行设置,默认值为0.1(即10%),表示基于上述算法得到的结果在[-10% - +10%]区间内,即[0.9 - 1.1],控制器都不会进行扩缩容操作。

也可以将期望指标值(desiredMetricValue)设置为指标的平均值类型,例如targetAverageValuetargetAverageUtilization,此时当前指标值(currentMetricValue)的算法为所有Pod副本当前指标值的总和除以Pod副本数量得到的平均值。

此外,存在几种Pod异常的情况,如下所述。

  • Pod正在被删除(设置了删除时间戳):将不会计入目标Pod副本数量。
  • Pod的当前指标值无法获得:本次探测不会将这个Pod纳入目标Pod副本数量,后续的探测会被重新纳入计算范围。
  • 如果指标类型是CPU使用率,则对于正在启动但是还未达到Ready状态的Pod,也暂时不会纳入目标副本数量范围。可以通过kube-controller-manager服务的启动参数--horizontal-pod-autoscaler-initial-readiness-delay设置首次探测Pod是否Ready的延时时间,默认值为30s。另一个启动参数--horizontal-pod-autoscaler-cpuinitialization-period设置首次采集Pod的CPU使用率的延时时间。

在计算“当前指标值/期望的指标值”(currentMetricValue / desiredMetricValue)时将不会包括上述这些异常Pod

当存在缺失指标的Pod时,系统将更保守地重新计算平均值。系统会假设这些Pod在需要缩容(Scale Down)时消耗了期望指标值的100%,在需要扩容(Scale Up)时消耗了期望指标值的0%,这样可以抑制潜在的扩缩容操作。

此外,如果存在未达到Ready状态的Pod,并且系统原本会在不考虑缺失指标或NotReady的Pod情况下进行扩展,则系统仍然会保守地假设这些Pod消耗期望指标值的0%,从而进一步抑制扩容操作。

如果在HorizontalPodAutoscaler中设置了多个指标,系统就会对每个指标都执行上面的算法,在全部结果中以期望副本数的最大值为最终结果。如果这些指标中的任意一个都无法转换为期望的副本数(例如无法获取指标的值),系统就会跳过扩缩容操作。

最后,在HPA控制器执行扩缩容操作之前,系统会记录扩缩容建议信息(Scale Recommendation)。控制器会在操作时间窗口(时间范围可以配置)中考虑所有的建议信息,并从中选择得分最高的建议。这个值可通过kube-controller-manager服务的启动参数--horizontal-pod-autoscaler-downscale-stabilization-window进行配置,默认值为5min。这个配置可以让系统更为平滑地进行缩容操作,从而消除短时间内指标值快速波动产生的影响。

HorizontalPodAutoscaler配置详解

Kubernetes将HorizontalPodAutoscaler资源对象提供给用户来定义扩缩容的规则。

HorizontalPodAutoscaler资源对象处于Kubernetes的API组“autoscaling”中,目前包括v1v2两个版本

其中autoscaling/v1仅支持基于CPU使用率自动扩缩容autoscaling/v2则用于支持基于任意指标的自动扩缩容配置,包括基于资源使用率、Pod指标、其他指标等类型的指标数据,当前版本为autoscaling/v2beta2

下面对HorizontalPodAutoscaler的配置和用法进行说明。

(1)基于autoscaling/v1版本的HorizontalPodAutoscaler配置,仅可以设置CPU使用率

apiVersion: autoscaling/v1 
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
 spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

主要参数如下

  • scaleTargetRef目标作用对象,可以是DeploymentReplicationControllerReplicaSet
  • targetCPUUtilizationPercentage:期望每个PodCPU使用率都为50%,该使用率基于Pod设置的CPU Request值进行计算,例如该值为200m,那么系统将维持Pod的实际CPU使用值为100m。
  • minReplicasmaxReplicas:Pod副本数量的最小值和最大值,系统将在这个范围内进行自动扩缩容操作,并维持每个Pod的CPU使用率为50%。

为了使用autoscaling/v1版本的HorizontalPodAutoscaler,需要预先安装Heapster组件Metrics Server,用于采集Pod的CPU使用率

Heapster从Kubernetes 1.11版本开始进入弃用阶段,不再对Heapster进行详细说明。

(2)基于autoscaling/v2beta2的HorizontalPodAutoscaler配置:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
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

主要参数如下。

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

可以将metrics中的type(指标类型)设置为以下三种,可以设置一个或多个组合,如下所述。

(1)Resource:基于资源的指标值,可以设置的资源为CPU内存

(2)Pods:基于Pod的指标,系统将对全部Pod副本的指标值进行平均值计算

(3)Object:基于某种资源对象(如Ingress)的指标或应用系统的任意自定义指标。

Resource类型的指标可以设置CPU内存

  • 对于CPU使用率,在target参数中设置averageUtilization定义目标平均CPU使用率
  • 对于内存资源,在target参数中设置AverageValue定义目标平均内存使用值

指标数据可以通过API“metrics.k8s.io”进行查询,要求预先启动Metrics Server服务

Pods类型Object类型都属于自定义指标类型,指标的数据通常需要搭建自定义Metrics Server和监控工具进行采集和处理。指标数据可以通过API“custom.metrics.k8s.io”进行查询,要求预先启动自定义Metrics Server服务。

类型为Pods的指标数据来源于Pod对象本身,其target指标类型只能使用AverageValue,示例如下:

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

其中,设置Pod的指标名packets-per-second,在目标指标平均值为1000时触发扩缩容操作。

类型为Object的指标数据来源于其他资源对象任意自定义指标,其target指标类型可以使用ValueAverageValue(根据Pod副本数计算平均值)进行设置。下面对几种常见的自定义指标给出示例和说明。

例1,设置指标的名称为requests-per-second,其值来源于Ingress “main-route”,将目标值(value)设置为2000,即在Ingress的每秒请求数量达到2000个时触发扩缩容操作:

metrics:
- type: Object
  object:
    metric:
      name: requests-per-second
    describedObject:
      apiVersion: extensions/v1beta1
      kind: Ingress
      name: main-route
    target:
      type: Value
      value: 2k

例2,设置指标的名称为http_requests,并且该资源对象具有标签“verb=GET”,在指标平均值达到500时触发扩缩容操作

metrics:
- type: Object
  object:
    metric:
      name: 'http_requests'
      selector: 'verb=GET'
    target:
      type: AverageValue
      AverageValue: 500

还可以在同一个HorizontalPodAutoscaler资源对象中定义多个类型的指标,系统将针对每种类型的指标都计算Pod副本的目标数量,以最大值为准进行扩缩容操作。例如:

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: extensions/v1beta1
        kind: Ingress
        name: main-route
      target:
        kind: Value
        value: 10k

从1.10版本开始,Kubernetes引入了对外部系统指标的支持。例如,用户使用了公有云服务商提供的消息服务或外部负载均衡器,希望基于这些外部服务的性能指标(如消息服务的队列长度、负载均衡器的QPS)对自己部署在Kubernetes中的服务进行自动扩缩容操作。这时,就可以在metrics参数部分设置type为External来设置自定义指标,然后就可以通过API“external.metrics.k8s.io”查询指标数据了。当然,这同样要求自定义Metrics Server服务已正常工作。

例3,设置指标的名称为queue_messages_ready,具有queue=worker_tasks标签在目标指标平均值为30时触发自动扩缩容操作:

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

在使用外部服务的指标时,要安装、部署能够对接到Kubernetes HPA模型的监控系统,并且完全了解监控系统采集这些指标的机制,后续的自动扩缩容操作才能完成。

Kubernetes推荐尽量使用type为ObjectHPA配置方式,这可以通过使用Operator模式,将外部指标通过CRD(自定义资源)定义为API资源对象来实现。

基于自定义指标的HPA实践

通过一个完整的示例,对如何搭建和使用基于自定义指标的HPA体系进行说明。

基于自定义指标进行自动扩缩容时,需要预先部署自定义Metrics Server,目前可以使用基于PrometheusMicrosoft AzureDatadog Cluster等系统的Adapter实现自定义Metrics Server,未来还将提供基于Google Stackdriver的实现自定义Metrics Server。读者可以参考官网 https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custommetrics-api 的说明。

基于Prometheus监控系统对HPA的基础组件部署和HPA配置进行详细说明。

基于Prometheus的HPA架构如图

image.png

关键组件包括如下:

  • Prometheus:定期采集各Pod的性能指标数据
  • Custom Metrics Server:自定义Metrics Server,用Prometheus Adapter进行具体实现。它从Prometheus服务采集性能指标数据,通过Kubernetes的Metrics Aggregation层将自定义指标API注册到Master的API Server中,以/apis/custom.metrics.k8s.io路径提供指标数据。
  • HPA Controller:Kubernetes的HPA控制器,基于用户定义的HorizontalPodAutoscaler进行自动扩缩容操作。

接下来对整个系统的部署过程进行说明。

(1)在Master的API Server启动Aggregation层,通过设置kube-apiserver服务的下列启动参数进行开启。

  • --requestheader-client-ca-file=/etc/kubernetes/ssl_keys/ca.crt:客户端CA证书。
  • --requestheader-allowed-names=:允许访问的客户端common names列表,通过header中由--requestheader-username-headers参数指定的字段获取。客户端common names的名称需要在client-ca-file中进行配置,将其设置为空值时,表示任意客户端都可以访问。
  • --requestheader-extra-headers-prefix=X-Remote-Extra-:请求头中需要检查的前缀名。
  • --requestheader-group-headers=X-Remote-Group:请求头中需要检查的组名。
  • --requestheader-username-headers=X-Remote-User:请求头中需要检查的用户名。
  • --proxy-client-cert-file=/etc/kubernetes/ssl_keys/kubelet_client.crt:在请求期间验证Aggregator的客户端CA证书。
  • --proxy-client-key-file=/etc/kubernetes/ssl_keys/kubelet_client.key:在请求期间验证Aggregator的客户端私钥。

配置kube-controller-manager服务中HPA的相关启动参数(可选配置)如下。

  • --horizontal-pod-autoscaler-sync-period=10s:HPA控制器同步Pod副本数量的时间间隔,默认值为15s。
  • --horizontal-pod-autoscaler-downscale-stabilization=1m0s:执行缩容操作的等待时长,默认值为5min。
  • --horizontal-pod-autoscaler-initial-readiness-delay=30s:等待Pod达到Ready状态的时延,默认值为30min。
  • --horizontal-pod-autoscaler-tolerance=0.1:扩缩容计算结果的容忍度,默认值为0.1,表示[-10% - +10%]。

(2)部署Prometheus,这里使用Operator模式进行部署。

首先,使用下面的YAML配置文件部署prometheus-operator:

# 1. prometheus-operator
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: prometheus-operator
  name: prometheus-operator
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: prometheus-operator
  template:
    metadata:
      labels:
        k8s-app: prometheus-operator
    spec:
      containers:
      - image: quay.io/coreos/prometheus-operator:v0.17.0
        imagePullPolicy: IfNotPresent
        name: prometheus-operator
        ports:
        - containerPort: 8080
          name: http
        resources:
          limits:
            cpu: 200m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 50Mi
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343