Deployment、ReplicaSet、Replication Controller或StatefulSet控制器资源管控的Pod副本数量⽀持⼿动⽅式的运⾏时调整,从⽽更好地匹配业务规模的实际需求。不过,⼿动调整的⽅式依赖于⽤户深度参与监控容器应⽤的资源压⼒并且需要计算出合理的值进⾏调整,存在⼀定程度的滞后性。为此,Kubernetes提供了多种⾃动弹性伸缩(Auto Scaling)⼯具。
HPA:全称Horizontal Pod Autoscaler,⼀种⽀持控制器对象下Pod规模弹性伸缩的⼯具,⽬前有两个版本的实现,分别称为HPA和HPA(v2),前⼀种仅⽀持把CPU指标数据作为评估基准,⽽新版本⽀持可从资源指标API和⾃定义指标API中获取的指标数据。
HPA⾃⾝是⼀个控制循环(control loop)的实现,其周期由controller-manager的--horizontal-pod-autoscaler-sync-period
选项来定义,默认为30秒。
在每个周期内,controller-manager将根据每个HPA定义中指定的指标查询相应的资源利⽤率。controller-manager从资源指标API(针对每个Pod资源指标)或⾃定义指标API(针对所有其他指标)中获取指标数据。
-
对于每个Pod资源指标(如CPU),控制器都将从HPA定位到的每个Pod的资源指标API中获取指标数据。若设置了⽬标利⽤率(target utilization)标准,则HPA控制器会计算其实际利⽤率(utilized/requests)。若设置的是⽬标原始值,则直接使⽤原始指标值。然后控制器获取所有⽬标Pod对象的利⽤率或原始值的均值(取决于指定的⽬标类型),并⽣成⼀个⽤于缩放所需副本数的⽐率。不过,对于未定义资源需求量的Pod对象,HPA控制器将⽆法定义该容器的CPU利⽤率,并且不会为该指标采取任何操作。
-
对于每个Pod对象的⾃定义指标,HPA控制器的功能与每个Pod资源指标的处理机制类似,只是它仅能够处理原始值⽽⾮利⽤率。
不过,使⽤HPA控制器管理Pod对象副本规模时,由于所评估指标的动态变动特性,副本数量可能会频繁波动,这种现象有时也称为“抖动”。可以通过调整kube-controller-manager的选项值定义其变动延迟时长来缓解此问题。⽬前,默认的缩容延迟时长为5分钟,⽽扩容延迟时长为3分钟。
HPA是Kubernetes autoscalingAPI群组中的API资源,当前的稳定版本仅⽀持CPU⾃动缩放,它位于autoscaling/v1群组中。⽽测试版本包含对内存和⾃定义指标的扩展⽀持,测试版本位于API群组autoscaling/v2beta1之中。
HPA控制器第⼀代仅⽀持CPU指标数据,⽽第⼆代的HPA可基于各种核⼼指标和⾃定义指标实现应⽤规模的⾃动变动。
HPA(v1)控制器
HPA是标准的Kubernetes API资源,其基于资源配置清单的管理⽅式同其他资源相同,可以通过资源配置清单定义HPA(v1)控制器资源,其spec字段嵌套使⽤的属性字段主要包含maxReplicas、minReplicas、scaleTargetRef和targetCPUUtilization-Percentage⼏个。
有⼀个特别的“kubectl autoscale”命令⽤于快速创建HPA控制器。例如,⾸先创建⼀个名为myapp的Deployment控制器,⽽后通过⼀个同名的HPA控制器⾃动管控其Pod副本规模:
~]$ kubectl run myapp --image=ikubernetes/myapp:v1 --replicas=2 --requests='cpu=50m,memory=256Mi' --limits='cpu=50m,memory=256Mi' --labels='app=myapp' --expose --port=80
~]$ kubectl autoscale deploy myapp --min=2 --max=5 --cpu-percent=60
~]$ kubectl get hpa myapp -o yaml
通过命令创建的HPA对象⾪属于“autoscaling/v1”群组,因此,它仅⽀持基于CPU利⽤率的弹性伸缩机制,可从Heapster或Metrics Service获得相关的指标数据。
HPA控制器会试图让Pod对象相应资源的占⽤率⽆限接近设定的⽬标值。例如,向myapp-svc的NodePort发起持续性的压⼒测试式访问请求,各Pod对象的CPU利⽤率将持续上升,直到超过⽬标利⽤率边界的60%,⽽后触发增加Pod对象副本数量。待其资源占⽤率下降到必须要降低Pod对象的数量以使得资源占⽤率靠近⽬标设定值时,即触发Pod副本的终⽌操作.
尽管CPU资源利⽤率可以作为规模伸缩的评估标准,但⼤多数时候,Pod对象所⾯临的访问压⼒未必会直接反映到CPU之上。
设置自动伸缩的前提:必须先设置资源请求/限制,不然自动伸缩获取不到有关cpu或内存的使用量。
查看当前容器cpu和内存使用量
# kubectl top pod jdd-parking-cloud-admin-58dd8d5b96-s9r29 -n jdd-k8s
NAME CPU(cores) MEMORY(bytes)
jdd-parking-cloud-admin-58dd8d5b96-s9r29 29m 373Mi
测试:进入到该pod中,人为执行命令:cat /dev/urandom | md5sum,观察容器的cpu使用率,查看是否触发自动伸缩
HPA(v2)控制器
HPA(v2)控制器⽀持基于核⼼指标CPU和内存资源以及基于任意⾃定义指标资源占⽤状态实现应⽤规模的⾃动弹性伸缩,它从metrics-server中请求查看核⼼指标,从k8s-prometheus-adapter⼀类的⾃定义API中获取⾃定义指标数据.
下⾯是⼀个HPA(v2)控制器的资源配置清单⽰例(hpa-v2-resources.yaml),它使⽤资源指标API获取两个指标CPU和内存资源的使⽤状况,并与其各⾃的设定⽬标进⾏⽐较,计算得出所需要的副本数量,两个指标计算的结果中数值较⼤的胜出:
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: myapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50
- type: Resource
resource:
name: memory
targetAverageValue: 50Mi
HPA(v2)尚且处于beta阶段,将来它有可能会发⽣部分改变,但⽬前的特性⾜以⽀撑起其核⼼功能。HPA(v2)控制器的创建语法遵循标准的API资源格式,由apiVersion、kind、metadata和spec字段组成,其中spec字段主要嵌套使⽤如下⼏个字段。
- minReplicas
:⾃动伸缩可缩减⾄的Pod副本数下限。 - maxReplicas
:⾃动伸缩可扩展⾄的Pod副本数上限,其值不能低于min-Replicas属性值。 - scaleTargetRef
- metrics<[]object>:⽤于计算所需Pod副本数量的指标列表,每个指标单独计算其所需的副本数,将所有指标计算结果中的最⼤值作为最终采⽤的副本数量。计算时,以资源占⽤率为例,所有现有Pod对象的资源占⽤率之和除以⽬标占⽤率所得的结果即为⽬标Pod副本数,因此增加Pod副本数量必然地会降低各Pod对象的资源占⽤率。
metrics字段值是对象列表,它由要引⽤的各指标的数据源及其类型构成的对象组成。
- external:⽤于引⽤⾮附属于任何对象的全局指标,甚⾄可以基于集群之外的组件的指标数据,如消息队列的长度等。
- object:引⽤描述集群中某单⼀对象的特定指标,如Ingress对象上的hits-per-second等。定义时,嵌套使⽤metricName、target和targetValue分别⽤于指定引⽤的指标名称、⽬标对象及指标的⽬标值。
- pods:引⽤当前被弹性伸缩的Pod对象的特定指标,如transactions-processed-per-second等,各Pod对象的指标数据取平均值后与⽬标值进⾏⽐较。定义时,嵌套使⽤metricName和targetAverageValue分别指定引⽤的指标名称和⽬标平均值。
- resource:引⽤资源指标,即当前被弹性伸缩的Pod对象中容器的requests和limits中定义的指标(CPU或内存资源)。定义时,嵌套使⽤name、targetAverageUtilization和targetAverageValue分别⽤于指定资源的名称、⽬标平均利⽤率和⽬标平均值。
- type:表⽰指标源的类型,其值可为Objects、Pods或Resource。
基于⾃定义指标API中的指标配置HPA对象时,其指标的来源途径还包括pods、object和external等,这其中又以Pod或引⽤的特定object的指标调⽤居多。下⾯通过⼀个⽰例来说明其⽤法,并测试其扩缩容的效果。
镜像⽂件ikubernetes/metrics-app在运⾏时会启动⼀个简单的Web服务器,它通过/metrics路径输出了http_requests_total和http_requests_per_second两个指标。下⾯是使⽤此镜像⽂件创建的Deployment控制器资源配置清单⽰例(metrics-app.yaml),它与此前正常使⽤的Deployment资源定义并⽆⼆致,除了特别附加的注解信息,包括其中的“prometheus.io/scrape:"true"”是使Pod对象能够被Prometheus采集相关指标的关键配置:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: metrics-app
name: metrics-app
spec:
replicas: 2
selector:
matchLabels:
app: metrics-app
template:
metadata:
labels:
app: metrics-app
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
prometheus.io/path: "/metrics"
spec:
containers:
- image: ikubernetes/metrics-app
name: metrics-app
ports:
- name: web
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: metrics-app
labels:
app: metrics-app
spec:
ports:
- name: web
port: 80
targetPort: 80
selector:
app: metrics-app
创建资源于集群中,启动⼀个专⽤的测试客户端Pod,在命令⾏中向创建出的Service端点的/metrics发起访问请求即可看到它输出的Prometheus兼容格式的指标及数据:
~]$ kubectl run client -it --image=cirros --rm -- /bin/sh
/ # curl metrics-app/metrics
# HELP http_requests_total The amount of requests in total
# TYPE http_requests_total counter
http_requests_total 660
# HELP http_requests_per_second The amount of requests per second the latest ten
seconds
# TYPE http_requests_per_second gauge
http_requests_per_second 0.5
/ #
命令结果中返回了所有的指标及其数据,每个指标还附带了通过注释⾏提供的帮助(HELP)信息和类型(TYPE)说明。Prometheus通过服务发现机制发现新创建的Pod对象,根据注解提供的配置信息或默认配置识别各个指标并纳⼊采集对象,⽽后由k8s-prometheus-adapter将这些指标注册到Kubernetes的⾃定义指标API中,提供给HPA(v2)控制器和Kubernetes调度器等作为调度评估参数使⽤。当然,也可以直接向⾃定义指标API接⼜发起请求。
下⾯的资源配置清单⽰例(metrics-app-hpa.yaml)⽤于⾃动弹性伸缩前⾯基于metrics-app.yaml创建的metrics-app相关的Pod对象副本数量,其伸缩标准是接⼊HTTP请求报⽂的速率,具体的数据则经由各现有相关Pod对象的http_requests指标的平均数据同⽬标速率800m(即0.8个/秒)的⽐较来进⾏判定:
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
metadata:
name: metrics-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: metrics-app
# autoscale between 2 and 10 replicas
minReplicas: 2
maxReplicas: 10
metrics:
# use a "Pods" metric, which takes the average of the
# given metric across all pods controlled by the autoscaling target
- type: Pods
pods:
# use the metric that you used above: pods/http_requests
metricName: http_requests
# target 500 milli-requests per second,
# which is 1 request every two seconds
targetAverageValue: 800m
创建资源于集群中,⽽后启动⼀个测试客户端发起持续性测试请求,模拟压⼒访问以便其指标数据能够满⾜扩展规模之需:
~]$ kubectl run client -it --image=cirros --rm -- /bin/sh
/ # while true; do curl http://metrics-app; let i++; sleep 0.$RANDOM; done
持续测试⼗⼏分钟,结束后再等上⼀段时间,待平均请求速率降下来之后即可通过HPA控制器的详细信息了解其规模变动状况,然后将会得到类似如下规模变动的相关信息:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 18m horizontal-pod-autoscaler New size: 3; reason:
pods metric http_requests above target
Normal SuccessfulRescale 14m horizontal-pod-autoscaler New size: 5; reason:
pods metric http_requests above target
Normal SuccessfulRescale 11m horizontal-pod-autoscaler New size: 6; reason:
pods metric http_requests above target
Normal SuccessfulRescale 5m horizontal-pod-autoscaler New size: 5; reason:
All metrics below target
Normal SuccessfulRescale 2s horizontal-pod-autoscaler New size: 4; reason:
All metrics below target