0%

k8s弹性伸缩

k8s弹性伸缩

k8s弹性伸缩主要针对k8s中容器的资源使用率来对其进行自动调整,k8s的弹性伸缩一共有三种:

  • CA(Cluster Autoscaler):Node级别自动扩/缩容

    cluster-autoscaler组件

  • HPA(Horizontal Pod Autoscaler):Pod个数自动扩/缩容

  • VPA(Vertical Pod Autoscaler):Pod配置自动扩/缩容,主要是CPU、内存

    addon-resizer组件

(k8s的HPA和VPA都需要先了解limitrange,其扩容缩容都需要根据limitrange来进行调整)

Cluster AutoScaler

CA是node级别的弹性伸缩

扩容:Cluster AutoScaler 定期检测是否有充足的资源来调度新创建的 Pod,当资源不足时会调用 Cloud Provider 创建新的 Node。

缩容:Cluster AutoScaler 也会定期监测 Node 的资源使用情况,当一个 Node 长时间资源利用率都很低时(低于 50%)自动将其所在虚拟机从云服务商中删除。此时,原来的 Pod 会自动调度到其他 Node 上面。

支持的云提供商:

1
2
3
4
5
6
7
8
9
10
11
12
13
该功能一般用在云k8s上,云服务厂商只要支持该功能就可以实现。如果是内部k8s的话比较麻烦,只能自己编写脚本进行监控(监控pod),达到阈值时触发扩容操作(包括创建新的节点并加入节点等操作),其实流程还是很麻烦的,而且内部使用的k8s一般也没有会出现pod激增的情况,所以都是手动扩容。

如果需要缩容的话可以根据以下步骤缩容:
1、获取节点列表
kubectl get node
2、设置不可调度
kubectl cordon $node_name
3、驱逐节点上的Pod
kubectl drain $node_name --ignore-daemonsets
4、移除节点
该节点上已经没有任何资源了,可以直接移除节点:
kubectl delete node $node_name
这样,我们平滑移除了一个 k8s 节点。

Pod自动扩容/缩容(HPA)

Horizontal Pod Autoscaler(HPA,Pod水平自动伸缩),根据资源利用率或者自定义指标自动调整replication controller, deployment 或 replica set,实现部署的自动扩展和缩减,让部署的规模接近于实际服务的负载。HPA不适于无法缩放的对象,例如DaemonSet。

HPA基本原理

Kubernetes 中的 Metrics Server 持续采集所有 Pod 副本的指标数据。HPA 控制器通过 Metrics Server 的 API(Heapster 的 API 或聚合 API)获取这些数据,基于用户定义的扩缩容规则进行计算,得到目标 Pod 副本数量。当目标 Pod 副本数量与当前副本数量不同时,HPA 控制器就向 Pod 的副本控制器(Deployment、RC 或 ReplicaSet)发起 scale 操作,调整 Pod 的副本数量,完成扩缩容操作。如图所示。

在弹性伸缩中,冷却周期是不能逃避的一个话题, 由于评估的度量标准是动态特性,副本的数量可能会不断波动。有时被称为颠簸, 所以在每次做出扩容缩容后,冷却时间是多少。

在 HPA 中,默认的扩容冷却周期是 3 分钟,缩容冷却周期是 5 分钟。

可以通过调整kube-controller-manager组件启动参数设置冷却时间:

  • –horizontal-pod-autoscaler-downscale-delay :扩容冷却
  • –horizontal-pod-autoscaler-upscale-delay :缩容冷却
1
2
这里首先要知道hpa要通过Metrics Server来采集pod的数据,再通过采集的pod数据例如CPU,来对pod进行弹性伸缩。
比如以最常用的cpu指标为例子(假设这里是deployment):首先,pod(deployment)在被创建时需要定义它的resources,也就是容器资源限制(定义其可以使用的cpu和内存资源上限)。定义完毕以后,创建hpa,hpa中规定了该deployment中pod的资源使用阈值,假如我们设置为cpu的阈值为60%,那么在达到60%时,就会自动扩容其pod,当然,当cpu阈值下来的时候,也会自动缩容。缩容和扩容的上下限pod也是hpa定义好的。

Metrics Server

metrics介绍

1.metrics是一个监控系统资源使用的插件,可以监控node节点上的CPU、内存的使用率,或pod对资源的占用率,通过读资源占用的了解,可以合理的部署容器应用
2.metrics从Kubernetes 1.8开始,资源使用情况的监控可以通过Metrics API的形式获取,具体组件为Metcics Server,用来替换之前的heapster。

Kubernetes API Aggregation

在 Kubernetes 1.7 版本引入了聚合层,允许第三方应用程序通过将自己注册到kube-apiserver上,仍然通过 API Server 的 HTTP URL 对新的 API 进行访问和操作。为了实现这个机制,Kubernetes 在 kube-apiserver 服务中引入了一个 API 聚合层(API Aggregation Layer),用于将扩展 API 的访问请求转发到用户服务的功能。

当你访问 apis/metrics.k8s.io/v1beta1 的时候,实际上访问到的是一个叫作 kube-aggregator 的代理。而 kube-apiserver,正是这个代理的一个后端;而 Metrics Server,则是另一个后端 。通过这种方式,我们就可以很方便地扩展 Kubernetes 的 API 了。

如果你使用kubeadm部署的,默认已开启。如果你使用二进制方式部署的话,需要在kube-APIServer中添加启动参数,增加该配置(–enable-aggregator-routing=true):

1
2
3
4
5
6
7
8
9
10
11
# vi /opt/kubernetes/cfg/kube-apiserver.conf
...
--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
--proxy-client-cert-file=/opt/kubernetes/ssl/server.pem \
--proxy-client-key-file=/opt/kubernetes/ssl/server-key.pem \
--requestheader-allowed-names=kubernetes \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
--enable-aggregator-routing=true \
...

在设置完成重启 kube-apiserver 服务,就启用 API 聚合功能了。

部署
1
metrics server的github地址:https://github.com/kubernetes-sigs/metrics-server
直接通过yaml清单部署
1
2
3
4
5
6
7
8
9
10
11
12
13
14
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
vim components.yaml # 添加2条启动参数
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls #添加这行
- --kubelet-preferred-address-types=InternalIP #添加这行
####
kubectl apply -f components.yaml
helm部署
1
2
3
4
5
6
7
8
9
10
11
12
13
git clone https://github.com/kubernetes-incubator/metrics-server
cd metrics-server/charts/metrics-server
vim values.yaml
####
defaultArgs:
- --cert-dir=/tmp
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls #添加这行
- --kubelet-preferred-address-types=InternalIP #添加这行
####
helm install metrics-server .
测试
1
2
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
kubectl top node
HPA的演进历程

目前 HPA 已经支持了 autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2 三个大版本 。

目前大多数人比较熟悉是autoscaling/v1,这个版本只支持CPU一个指标的弹性伸缩。

而autoscaling/v2beta1增加了支持自定义指标,autoscaling/v2beta2又额外增加了外部指标支持。

autoscaling/v1(CPU指标实践)

autoscaling/v1版本只支持CPU一个指标。

首先部署一个应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: nginx-php
template:
metadata:
labels:
app: nginx-php
spec:
containers:
- image: lizhenliang/nginx-php
name: java
resources:
requests:
memory: "300Mi"
cpu: "250m"

---

apiVersion: v1
kind: Service
metadata:
name: web
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-php

创建HPA策略:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: web
spec:
maxReplicas: 5
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
targetCPUUtilizationPercentage: 60

scaleTargetRef:表示当前要伸缩对象是谁

targetCPUUtilizationPercentage:当整体的资源利用率超过50%的时候,会进行扩容。

开启压测:

1
2
# yum install httpd-tools
# ab -n 100000 -c 100 http://10.1.206.176/status.php

10.0.0.147 为ClusterIP。

检查扩容状态:

1
2
3
# kubectl get hpa
# kubectl top pods
# kubectl get pods

关闭压测,过一会检查缩容状态。

工作流程:hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor)

autoscaling/v2beta2(多指标)

为满足更多的需求, HPA 还有 autoscaling/v2beta1和 autoscaling/v2beta2两个版本。
这两个版本的区别是 autoscaling/v1beta1支持了 Resource Metrics(CPU)和 Custom Metrics(应用程序指标),而在 autoscaling/v2beta2的版本中额外增加了 External Metrics的支持。

为了满足更多的需求,hpa还有v2beat1和v2beat2两个版本,这个跨度也比较大,这个可以实现自定义指标

cpu hpa:

1
# kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

与上面v1版本效果一样,只不过这里格式有所变化。

内存hpa:

1
2
3
4
5
6
- type: Resource
resource:
name: memory
target:
averageValue: 50Mi
type: AverageValue

v2还支持其他另种类型的度量指标,:Pods和Object。

1
2
3
4
5
6
7
type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
1
2
3
4
5
6
7
8
9
10
11
type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 2k

metrics中的type字段有四种类型的值:Object、Pods、Resource、External。
• Resource:指的是当前伸缩对象下的pod的cpu和memory指标,只支持Utilization和AverageValue类型的目标值。这里hpa(metrics server)本身只支持Resource下cpu和内存两种方式,其他的都需要通过prometheus等第三方监控系统采集数据后交给hpa.

• Object:指的是指定k8s内部对象的指标,数据需要第三方adapter提供,只支持Value和AverageValue类型的目标值。

• Pods:指的是伸缩对象Pods的指标,数据需要第三方的adapter提供,只允许AverageValue类型的目标值。另外就是pod暴露的指标,比如http的请求数,吞吐量,也就是http它本身暴露的出来的,但是暴露出来,它不能拿到这些指标,还需要借助一些第三方的监控,也就是使用hpa这里面值的判断,这个提前是要通过kubectl apiservices里面看到注册进去,到聚合层,所有的hpa都是通过聚合层去拿到的,它其实是请求的api到聚合层,然后聚合层帮你代理到后面的组件,比如像metics-service ,它去帮你拿的,然后每个kubelet帮你收集的(cadvisor每个pod的资源利用率,它帮你做一个聚合,聚合之后通过聚合器暴露出来,然后来查询设定的pod的资源利用率,并且做了一个平均,这样就能通过hpa就能拿到之后的目标值,然后hpa再帮你判断,是否达到这个预值,到的话,帮你扩容。
基于pod的实例,pod本身暴露的指标,比较吞吐量,qps,如果目标是1k也会触发
Hpa ->apiserver->agg->聚合层->prometheus-adapter然后它注册到聚合层里面来,prometheus本身就是一个监控系统,它能采集到所有pod暴露的指标,自己存储起来,并且展示,adapter主要将自己注册到聚合层里面并且它能转换这个监控指标apiserver相应的数据接口和prometheus的接口是不一样的,adapter在这里存在的关键是数据格式的转化,对接的不单纯的是prometheus或者其他的监控系统,要想实现自定义指标完成数据的转化和注册,然后prometheus将每个pod展示出来

• External:指的是k8s外部的指标,数据同样需要第三方的adapter提供,只支持Value和AverageValue类型的目标值。

• 工作流程:hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods

基于Prometheus自定义指标缩放

这里因为Prometheus监控需要指定metrics,例如监控一个pod,需要在其yaml文件中现制定metrics,如下:

1
2
3
4
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
prometheus.io/path: "/metrics"

但很多应用服务并没有该指标,无法通过该方式拿到pod的指标信息,所以也不好做,这里就不细讲。

VPA

简介

  • kubernetes(VPA Vertical Pod Autoscaler)垂直 Pod 自动扩缩容, VPA 会基于 Pod 的资源使用情况自动为集群设置资源占用的限制,从而让集群将 Pod 调度到有足够资源的最佳节点上。 VPA 也会保持最初容器定义中资源 request 和 limit 的占比。它会 根据容器资源使用率自动设置 pod 的 CPU 和内存的 requests ,从而允许在节点上进行适当的调度,以便为每个 Pod 提供适当的 可用的节点 。它既可以缩小过度请求资源的容器,也可以根据其使用情况随时提升资源不足的容量。
  • Vertical Pod Autoscaler (VPA):垂直 Pod 自动扩缩容, 用户无需为其 pods 中的容器设置最新的资源 request 。配置后,它将根据使用情况自动设置 request ,从而允许在节点上进行适当的调度,以便为每个 pod 提供适当的资源量
  • HPA 通过添加或删除pod进行扩展,从而水平扩展容量。然而,VPA 通过增加或减少现有 pod 容器内的 CPU 和内存资源来进行扩展,从而垂直扩展容量。下表更详细地解释了 Kubernetes VPA 和 HPA 之间的区别
1
2
3
所需的容量调整  	水平缩放 (HPA)	          垂直缩放 (VPA)
更多资源 Add more pods 增加现有 pod 容器的 CPU 或内存资源
更少的资源 Remove pods 减少现有 pod 容器的 CPU 或内存资源

总结来说VPC也是通过metrics server的监控指标(CPU,内存)来调整pod的requests值(VPA不会改变Pod的资源limits值),但是其调整的方式是重建pod(删除重新创建)。

image-20220920171157694

VPC工作流程图:

在这里插入图片描述

  1. 用户配置 VPA
  2. VPA Recommender 从指标服务器读取 VPA 配置和资源利用率指标
  3. VPA Recommender 提供 pod 资源推荐
  4. VPA 更新程序读取 pod 资源建议
  5. VPA 更新程序启动 pod 终止
  6. 部署意识到 pod 已终止,并将重新创建 pod 以匹配其副本配置
  7. 当 Pod 处于重新创建过程中时,VPA 准入控制器获取 Pod 资源推荐。由于 Kubernetes 不支持动态更改正在运行的 pod 的资源限制,因此 VPA 无法使用新的限制更新现有 pod。它终止使用过时限制的 pod。当 pod 的控制器从 Kubernetes API 服务请求替换时,VPA 准入控制器将更新的资源请求和限制值注入到新的 pod 的规范中
  8. 最后,VPA 准入控制器将建议覆盖到 pod。在我们的示例中,VPA 准入控制器向 pod 添加了一个“250m”的 CPU

VPA组件

VPA Recommender

监视资源利用率并计算目标值
查看指标历史记录、OOM 事件和 VPA 部署规范并建议公平请求。根据定义的限制请求比例提高/降低限制

VPA Updater

驱逐那些需要新资源限制的 pod
如果定义了“updateMode: Auto”,则实现 Recommender 推荐的任何内容

VPA Admission Controller

每当 VPA 更新程序驱逐并重新启动 pod 时,在新 pod 启动之前更改 CPU 和内存设置(使用 webhook)
当 Vertical Pod Autoscaler 设置为 updateMode 为“Auto”时,如果需要更改 pod 的资源请求,则驱逐 pod。由于 Kubernetes 的设计,修改正在运行的 Pod 的资源请求的唯一方法是重新创建 Pod

VPC部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
git clone https://github.com/kubernetes/autoscaler.git
./autoscaler/vertical-pod-autoscaler/hack/vpa-up.sh #安装脚本(在有kubectl create权限的服务器执行)
######
customresourcedefinition.apiextensions.k8s.io/verticalpodautoscalercheckpoints.autoscaling.k8s.io created
customresourcedefinition.apiextensions.k8s.io/verticalpodautoscalers.autoscaling.k8s.io created
clusterrole.rbac.authorization.k8s.io/system:metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:vpa-actor created
clusterrole.rbac.authorization.k8s.io/system:vpa-checkpoint-actor created
clusterrole.rbac.authorization.k8s.io/system:evictioner created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-actor created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-checkpoint-actor created
clusterrole.rbac.authorization.k8s.io/system:vpa-target-reader created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-target-reader-binding created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-evictionter-binding created
serviceaccount/vpa-admission-controller created
clusterrole.rbac.authorization.k8s.io/system:vpa-admission-controller created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-admission-controller created
clusterrole.rbac.authorization.k8s.io/system:vpa-status-reader created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-status-reader-binding created
serviceaccount/vpa-updater created
deployment.apps/vpa-updater created
serviceaccount/vpa-recommender created
deployment.apps/vpa-recommender created
Generating certs for the VPA Admission Controller in /tmp/vpa-certs.
Generating RSA private key, 2048 bit long modulus (2 primes)
..............................................................+++++
.....................................+++++
e is 65537 (0x010001)
Generating RSA private key, 2048 bit long modulus (2 primes)
..............+++++
........+++++
e is 65537 (0x010001)
Signature ok
subject=CN = vpa-webhook.kube-system.svc
Getting CA Private Key
Uploading certs to the cluster.
secret/vpa-tls-certs created
Deleting /tmp/vpa-certs.
deployment.apps/vpa-admission-controller created
service/vpa-webhook created

# 关闭命令
./hack/vpa-down.sh

# 注意:如果您在此步骤中看到以下错误,请将 openssl 升级到 1.1.1 或更高版本(需要支持 -addext 选项)或在0.8 发布分支上使用 ./hack/vpa-up.sh
unknown option -addext

# 查看部署的yaml文件内容
./hack/vpa-process-yamls.sh print

# 查看运行情况
[root@k8s-master-1 hack]# kubectl get pods -A | grep vpa
kube-system vpa-admission-controller-657857bfb7-s72df 1/1 Running 0 32s
kube-system vpa-recommender-77dccb87b8-nx9gd 1/1 Running 0 32s
kube-system vpa-updater-5f574b5d57-vsjpv 1/1 Running 0 34s

metrics-server也需要部署,上面hpa已经讲了,这里就不再做一遍部署流程了。

VPA实例

安装后,系统已准备好为您的 pod 推荐和设置资源请求。为了使用它,您需要为要自动计算资源需求的每个控制器插入一个Vertical Pod Autoscaler资源。这将是最常见的Deployment。VPA有三种运行模式

  • “Auto”:VPA 在创建 pod 时分配资源请求,并使用首选更新机制在现有 pod 上更新它们。目前这相当于”Recreate”(见下文)。一旦 pod 请求的免重启(“就地”)更新可用,它可能会被该”Auto”模式用作首选的更新机制。注意: VPA 的此功能是实验性的,可能会导致您的应用程序停机,当目前运行的pod的资源达不到VPA的推荐值,就会执行pod驱逐,重新部署新的足够资源的服务
  • “Recreate”:VPA 在创建 Pod 时分配资源请求,并在现有 Pod 上更新它们,当请求的资源与新建议有很大差异时(尊重 Pod 中断预算,如果定义)。这种模式应该很少使用,只有当您需要确保在资源请求发生变化时重新启动 Pod 时。否则,更喜欢这种”Auto”模式,一旦它们可用,就可以利用重新启动免费更新。注意: VPA 的此功能是实验性的,可能会导致您的应用程序停机
  • “Initial”:VPA 仅在创建 pod 时分配资源请求,以后不会更改它们
  • “Off”:VPA 不会自动更改 Pod 的资源需求。这些建议是经过计算的,并且可以在 VPA 对象中进行检查。这种模式仅获取资源推荐 值,但是不更新Pod

updateMode: Off

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 测试yaml内容如下
[root@k8s-master-1 VPA]# cat vpa-off.yaml
apiVersion: v1
kind: Namespace
metadata:
name: vpa
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: vpa
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 150Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: vpa
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 45425
selector:
app: nginx
---
apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
name: nginx-vpa
namespace: vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: nginx
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "nginx"
minAllowed:
cpu: "100m"
memory: "150Mi"
maxAllowed:
cpu: "2000m"
memory: "2600Mi"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# 查看pod和SVC
[root@k8s-master-1 VPA]# kubectl get pods -n vpa
NAME READY STATUS RESTARTS AGE
nginx-5f598bd784-bsxqp 1/1 Running 0 99s
nginx-5f598bd784-f2dnx 1/1 Running 0 99s
[root@k8s-master-1 VPA]# kubectl get svc -n vpa
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.0.68.114 <none> 80:45425/TCP 105s

# 查看vpa
[root@k8s-master-1 VPA]# kubectl describe vpa nginx-vpa -n vpa
Name: nginx-vpa
Namespace: vpa
Labels: <none>
Annotations: <none>
API Version: autoscaling.k8s.io/v1
Kind: VerticalPodAutoscaler
Metadata:
Creation Timestamp: 2022-04-10T10:23:51Z
Generation: 2
Managed Fields:
API Version: autoscaling.k8s.io/v1beta2
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:resourcePolicy:
.:
f:containerPolicies:
f:targetRef:
.:
f:apiVersion:
f:kind:
f:name:
f:updatePolicy:
.:
f:updateMode:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2022-04-10T10:23:51Z
API Version: autoscaling.k8s.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
.:
f:conditions:
f:recommendation:
.:
f:containerRecommendations:
Manager: recommender
Operation: Update
Time: 2022-04-10T10:24:32Z
Resource Version: 729060
UID: c09b2670-d443-4f44-8c13-87971cc7bf3e
Spec:
Resource Policy:
Container Policies:
Container Name: nginx
Max Allowed:
Cpu: 2000m
Memory: 2600Mi
Min Allowed:
Cpu: 100m
Memory: 150Mi
Target Ref:
API Version: apps/v1
Kind: Deployment
Name: nginx
Update Policy:
Update Mode: Off
Status:
Conditions:
Last Transition Time: 2022-04-10T10:24:32Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound: # 下限值
Cpu: 100m
Memory: 262144k
Target: # 推荐值
Cpu: 296m
Memory: 262144k
Uncapped Target: # 如果没有为VPA提供最小或最大边界,则表示目标利用率
Cpu: 296m
Memory: 262144k
Upper Bound: # 上限值
Cpu: 2
Memory: 728383116
Events: <none>
# 上面结果表示,推荐的Pod的CPU 请求为296m,推荐的内存请求为 262144k字节

# 压测 nginx
[root@k8s-master-1 VPA]# yum -y install httpd-tools ab
[root@k8s-master-1 VPA]# ab -c 3000 -n 10000000 http://192.168.0.10:45425/

# 查看Pod负载
[root@k8s-master-1 ~]# kubectl top pods -n vpa
NAME CPU(cores) MEMORY(bytes)
nginx-c94c9f468-5gf7l 312m 5Mi
nginx-c94c9f468-5tx45 324m 5Mi

[root@k8s-master-1 VPA]# kubectl describe vpa nginx-vpa -n vpa
Name: nginx-vpa
Namespace: vpa
Labels: <none>
Annotations: <none>
API Version: autoscaling.k8s.io/v1
Kind: VerticalPodAutoscaler
...............................................................
Spec:
...............................................................
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound:
Cpu: 100m
Memory: 262144k
Target:
Cpu: 323m
Memory: 262144k
Uncapped Target:
Cpu: 323m
Memory: 262144k
Upper Bound:
Cpu: 2
Memory: 561361649
Events: <none>

# 从以上信息可以看出, VPA对Pod给出了推荐值: Cpu: 323m ,因为我们这里设置了 updateMode: "Off" Off",所以不会更新 Pod
#OFF模式只会给出推荐值,但不会去更改pod的request值。

updateMode: On

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 测试yaml,将updateMode:off中POD的requests 改为 CPU:50m,Memory: 50Mi,同时将updateMode修改为Auto

# 查看pod和svc
[root@k8s-master-1 VPA]# kubectl get pods -n vpa
NAME READY STATUS RESTARTS AGE
nginx-5dbcbbdfcf-8lqfj 1/1 Running 0 9s
nginx-5dbcbbdfcf-hprgm 1/1 Running 0 9s
[root@k8s-master-1 VPA]# kubectl get svc -n vpa
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.0.200.5 <none> 80:45425/TCP 15s

# 进行压测,压测到一半时,突然连接断了,说明POD被重新创建了
[root@k8s-master-1 VPA]# ab -c 1000 -n 10000000 http://192.168.0.10:45425/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.0.10 (be patient)
apr_socket_recv: Connection reset by peer (104)
Total of 187078 requests completed

# 查看vpa
[root@k8s-master-1 VPA]# kubectl describe vpa nginx-vpa -n vpa | tail -n 20
Conditions:
Last Transition Time: 2022-04-10T10:41:32Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound:
Cpu: 100m
Memory: 262144k
Target:
Cpu: 350m
Memory: 262144k
Uncapped Target:
Cpu: 350m
Memory: 262144k
Upper Bound:
Cpu: 2
Memory: 405160855
Events: <none>


# 查看event,从输出信息可以看到,vpa 执行了EvictedBy VPA ,自动停掉了 nginx ,然后使用VPA推荐的资源启动了新的 nginx
[root@k8s-master-1 VPA]# kubectl get event -n vpa
LAST SEEN TYPE REASON OBJECT MESSAGE
4m17s Normal Scheduled pod/nginx-5dbcbbdfcf-8lqfj Successfully assigned vpa/nginx-5dbcbbdfcf-8lqfj to k8s-node-1
4m16s Normal Pulled pod/nginx-5dbcbbdfcf-8lqfj Container image "nginx" already present on machine
4m16s Normal Created pod/nginx-5dbcbbdfcf-8lqfj Created container nginx
4m16s Normal Started pod/nginx-5dbcbbdfcf-8lqfj Started container nginx
2m24s Normal Killing pod/nginx-5dbcbbdfcf-8lqfj Stopping container nginx
2m24s Normal EvictedByVPA pod/nginx-5dbcbbdfcf-8lqfj Pod was evicted by VPA Updater to apply resource recommendation.
2m24s Normal Scheduled pod/nginx-5dbcbbdfcf-d8pxz Successfully assigned vpa/nginx-5dbcbbdfcf-d8pxz to k8s-node-1
2m22s Normal Pulled pod/nginx-5dbcbbdfcf-d8pxz Container image "nginx" already present on machine
2m22s Normal Created pod/nginx-5dbcbbdfcf-d8pxz Created container nginx
2m22s Normal Started pod/nginx-5dbcbbdfcf-d8pxz Started container nginx
84s Normal Scheduled pod/nginx-5dbcbbdfcf-f9bfp Successfully assigned vpa/nginx-5dbcbbdfcf-f9bfp to k8s-node-1
82s Normal Pulled pod/nginx-5dbcbbdfcf-f9bfp Container image "nginx" already present on machine
82s Normal Created pod/nginx-5dbcbbdfcf-f9bfp Created container nginx
82s Normal Started pod/nginx-5dbcbbdfcf-f9bfp Started container nginx
4m17s Normal Scheduled pod/nginx-5dbcbbdfcf-hprgm Successfully assigned vpa/nginx-5dbcbbdfcf-hprgm to k8s-node-1
4m16s Normal Pulled pod/nginx-5dbcbbdfcf-hprgm Container image "nginx" already present on machine
4m16s Normal Created pod/nginx-5dbcbbdfcf-hprgm Created container nginx
4m16s Normal Started pod/nginx-5dbcbbdfcf-hprgm Started container nginx
84s Normal Killing pod/nginx-5dbcbbdfcf-hprgm Stopping container nginx
84s Normal EvictedByVPA pod/nginx-5dbcbbdfcf-hprgm Pod was evicted by VPA Updater to apply resource recommendation. ######## 这里执行了更新操作
4m17s Normal SuccessfulCreate replicaset/nginx-5dbcbbdfcf Created pod: nginx-5dbcbbdfcf-8lqfj
4m17s Normal SuccessfulCreate replicaset/nginx-5dbcbbdfcf Created pod: nginx-5dbcbbdfcf-hprgm
2m24s Normal SuccessfulCreate replicaset/nginx-5dbcbbdfcf Created pod: nginx-5dbcbbdfcf-d8pxz
84s Normal SuccessfulCreate replicaset/nginx-5dbcbbdfcf Created pod: nginx-5dbcbbdfcf-f9bfp
4m18s Normal ScalingReplicaSet deployment/nginx Scaled up replica set nginx-5dbcb

# 查看pod,可以看到pod的名称发生变化了,可见被重新创建了
[root@k8s-master-1 VPA]# kubectl get pods -n vpa
NAME READY STATUS RESTARTS AGE
nginx-5dbcbbdfcf-d8pxz 1/1 Running 0 4m
nginx-5dbcbbdfcf-f9bfp 1/1 Running 0 3m

# 查看pod的request,可以重新生成了新的资源限制,随着服务的负载的变化, VPA的推荐值也会不断变化。当目前运行的pod的资源达不到VPA的推荐值,就会执行pod驱逐,重新部署新的足够资源的服务。
[root@k8s-master-1 VPA]# kubectl describe pods nginx-5dbcbbdfcf-d8pxz -n vpa | grep -A 3 -i requests
Requests:
cpu: 350m
memory: 262144k
Environment: <none>

VPA使用限制

  • 不能与HPA(Horizontal Pod Autoscaler )一起使用
  • Pod比如使用副本控制器,例如属于Deployment或者StatefulSet

VPA有啥好处

  • Pod 资源用其所需,所以集群节点使用效率高。
  • Pod 会被安排到具有适当可用资源的节点上。
  • 不必运行基准测试任务来确定 CPU 和内存请求的合适值。
  • VPA 可以随时调整 CPU 和内存请求,无需人为操作,因此可以减少维护时间。