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 之间的区别
所需的容量调整 | 水平缩放 (HPA) | 垂直缩放 (VPA) |
更多资源 | Add more pods | 增加现有 pod 容器的 CPU 或内存资源 |
更少的资源 | Remove pods | 减少现有 pod 容器的 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
VPA工作流程
- 用户配置 VPA
- VPA Recommender 从指标服务器读取 VPA 配置和资源利用率指标
- VPA Recommender 提供 pod 资源推荐
- VPA 更新程序读取 pod 资源建议
- VPA 更新程序启动 pod 终止
- 部署意识到 pod 已终止,并将重新创建 pod 以匹配其副本配置
- 当 Pod 处于重新创建过程中时,VPA 准入控制器获取 Pod 资源推荐。由于 Kubernetes 不支持动态更改正在运行的 pod 的资源限制,因此 VPA 无法使用新的限制更新现有 pod。它终止使用过时限制的 pod。当 pod 的控制器从 Kubernetes API 服务请求替换时,VPA 准入控制器将更新的资源请求和限制值注入到新的 pod 的规范中
- 最后,VPA 准入控制器将建议覆盖到 pod。在我们的示例中,VPA 准入控制器向 pod 添加了一个“250m”的 CPU
我们也可以在推荐模式下运行 VPA。在这种模式下,VPA Recommender 将使用其建议值更新工作负载的 Vertical Pod Autoscaler 资源的状态字段,但不会终止 pod 或更改 pod API 请求
VPA 的局限性
VPA 在许多应用程序中都很有用,但要记住几个重要的限制
-
不要将 Vertical Pod Autoscaler 与 Horizontal Pod Autoscaler 一起使用
,后者基于相同的资源指标(例如 CPU 和 MEMORY 使用率)进行缩放。这是因为当指标 (CPU/MEMORY) 达到其定义的阈值时,VPA 和 HPA 将同时发生缩放事件,这可能会产生未知的副作用并可能导致问题 - VPA 可能会推荐比集群中可用的资源更多的资源,从而导致 pod 未分配给节点(由于资源不足),因此永远不会运行。为了克服这个限制,
最好将LimitRange 设置为最大可用资源。这将确保 pod 不会要求超过 LimitRange 定义的资源
- VPA 不会驱逐不在控制器下运行的 pod。对于这样的 pods
Auto
模式目前相当于Initial
VPA部署
anjia0532使用方法链接:https://github.com/anjia0532/gcr.io_mirror
# 镜像无法拉取解决
# 原始镜像
image: k8s.gcr.io/autoscaling/vpa-updater:0.10.0
image: k8s.gcr.io/autoscaling/vpa-recommender:0.10.0
image: k8s.gcr.io/autoscaling/vpa-admission-controller:0.10.0
# 拉取镜像
docker pull anjia0532/google-containers.autoscaling.vpa-updater:0.10.0
docker pull anjia0532/google-containers.autoscaling.vpa-recommender:0.10.0
docker pull anjia0532/google-containers.autoscaling.vpa-admission-controller:0.10.0
# 修改tag
docker tag anjia0532/google-containers.autoscaling.vpa-admission-controller:0.10.0 k8s.gcr.io/autoscaling/vpa-admission-controller:0.10.0
docker tag anjia0532/google-containers.autoscaling.vpa-recommender:0.10.0 k8s.gcr.io/autoscaling/vpa-recommender:0.10.0
docker tag anjia0532/google-containers.autoscaling.vpa-updater:0.10.0 k8s.gcr.io/autoscaling/vpa-updater:0.10.0
# 删除下载的
docker rmi anjia0532/google-containers.autoscaling.vpa-updater:0.10.0
docker rmi anjia0532/google-containers.autoscaling.vpa-recommender:0.10.0
docker rmi anjia0532/google-containers.autoscaling.vpa-admission-controller:0.10.0
# 查看镜像
[root@k8s-master-1 hack]# docker image ls | grep vpa
k8s.gcr.io/autoscaling/vpa-admission-controller 0.10.0 0c437f333c80 2 months ago 45MB
k8s.gcr.io/autoscaling/vpa-updater 0.10.0 f7996212cdf9 2 months ago 47.2MB
k8s.gcr.io/autoscaling/vpa-recommender 0.10.0 05040f9c0dfd 2 months ago 46.1MB
# 将image拉取策略从Always改为IfNotPresent,防止每次重新部署的时候都会拉取镜像,让其使用本地镜像
[root@k8s-master-1 deploy]# pwd
/root/cluster/vpa/autoscaler/vertical-pod-autoscaler/deploy
[root@k8s-master-1 deploy]# grep "image" admission-controller-deployment.yaml
image: k8s.gcr.io/autoscaling/vpa-admission-controller:0.10.0
imagePullPolicy: IfNotPresent
[root@k8s-master-1 deploy]# grep image recommender-deployment.yaml
image: k8s.gcr.io/autoscaling/vpa-recommender:0.10.0
imagePullPolicy: IfNotPresent
[root@k8s-master-1 deploy]# grep image updater-deployment.yaml
image: k8s.gcr.io/autoscaling/vpa-updater:0.10.0
imagePullPolicy: IfNotPresent
# 下载安装包
git clone https://github.com/kubernetes/autoscaler.git
# 并在目录中运行以下命令vertical-pod-autoscaler
[root@k8s-master-1 hack]# ./vpa-up.sh
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
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
# 测试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"
# 查看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
updateMode: On
# 测试yaml,将updateMode:off中的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>