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 或内存资源

k8sconfigmap 模板 k8s vpa_linux

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工作流程

k8sconfigmap 模板 k8s vpa_kubernetes_02

  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 将使用其建议值更新工作负载的 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>