请启用 Javascript 以查看内容

深入解析 Kubernetes VPA 调优:动态资源分配与压测实战

 ·  ☕ 10 分钟  ·  ✍ CNSRE · 👀... 阅读

作者:SRE运维博客
博客地址:https://www.cnsre.cn/
文章地址:https://www.cnsre.cn/posts/241205123704/
相关话题:https://www.cnsre.cn/tags/k8s/

在现代云原生应用中,合理地分配和调整容器的资源是保障应用性能和成本效益的关键。Kubernetes 的 Vertical Pod Autoscaler(VPA)提供了根据实际资源使用情况自动调整 Pod 资源请求和限制的能力。然而,默认的 VPA 配置可能无法满足所有场景的需求,因此我们需要根据实际情况调整 VPA 的参数。

本文将通过实验,详细介绍如何安装配置以及调整 VPA 的参数,以及通过实验展示带来的效果。

基础配置及测试

部署VPA

先决条件

  • 拥有现有 k8s 集群。
  • 已安装 Kubernetes Metrics Server。有关更多信息,请参阅 使用 KubernetesMetrics Server 查看资源使用情况
  • 安装配置好 kubectl 客户端。
  • 设备已安装 OpenSSL 1.1.1 或更高版本(如本地设备可以通过kubectl控制k8s,即在本地安装即可,如在 master 控制集群则在master安装)。

部署 Vertical Pod Autoscaler

在此部分中,我们将部署 Vertical Pod Autoscaler 到集群。

部署 Vertical Pod Autoscaler

  1. 打开终端窗口,导航到我们要下载 Vertical Pod Autoscaler 源代码的目录。

  2. 克隆 kubernetes/autoscaler GitHub 存储库。

    git clone https://github.com/kubernetes/autoscaler.git
    
  3. 切换到 vertical-pod-autoscaler 目录。

    cd autoscaler/vertical-pod-autoscaler/
    
  4. (可选)如果我们已经部署另一个版本的 Vertical Pod Autoscaler,请使用以下命令将其删除。

    ./hack/vpa-down.sh
    
  5. 使用以下命令将 Vertical Pod Autoscaler 部署到我们的集群。

    ./hack/vpa-up.sh
    
  6. 验证已成功创建 Vertical Pod Autoscaler Pods。

    kubectl get pods -n kube-system
    

    示例输出如下。

    NAME                                        READY   STATUS    RESTARTS   AGE
    [...]
    metrics-server-788b46889b-s6jst             1/1     Running   0               55m
    metrics-server-788b46889b-tz8m9             1/1     Running   0               55m
    vpa-admission-controller-6b6b54cbd6-wkgqw   1/1     Running   0               43m
    vpa-recommender-7cf697b548-xq9td            1/1     Running   0               43m
    vpa-updater-856fc8c478-kx747                1/1     Running   0               45m
    

测试 Vertical Pod Autoscaler 安装

在此部分中,我们部署示例应用程序以验证 Vertical Pod Autoscaler 在正常运行。

测试 Vertical Pod Autoscaler 安装

  1. 使用以下命令部署 hamster.yaml Vertical Pod Autoscaler 示例。

    kubectl apply -f examples/hamster.yaml
    
  2. hamster 示例应用程序获取 Pods。

    kubectl get pods -l app=hamster
    

    示例输出如下。

    hamster-789f8477df-d8bd8   1/1     Running   0          48s
    hamster-789f8477df-7swj6   1/1     Running   0          48s
    
  3. 描述其中一个 Pods 以查看其 cpumemory 预留。请将 c7d89d6db-rglf5 替换为上一步输出中返回的 ID 之一。

    kubectl describe pod hamster-789f8477df-7swj6
    

    示例输出如下。

    [...]
    Containers:
      hamster:
        Container ID:  docker://e76c2413fc720ac395c33b64588c82094fc8e5d590e373d5f818f3978f577e24
        Image:         registry.k8s.io/ubuntu-slim:0.1
        Image ID:      docker-pullable://registry.k8s.io/ubuntu-slim@sha256:b6f8c3885f5880a4f1a7cf717c07242eb4858fdd5a84b5ffe35b1cf680ea17b1
        Port:          <none>
        Host Port:     <none>
        Command:
          /bin/sh
        Args:
          -c
          while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done
        State:          Running
          Started:      Thu, 05 Dec 2024 02:21:42 +0800
        Ready:          True
        Restart Count:  0
        Requests:
          cpu:        100m
          memory:     50Mi
    [...]
    

    我们可以看到原始 Pod 预留了 100 millicpu 和 50 MiB 内存。对于本示例应用程序,100 millicpu 小于 Pod 运行所需的数量,因此 CPU 受限。它预留的内存也远小于所需的数量。Vertical Pod Autoscaler vpa-recommender 部署分析 hamster Pods,以查看 CPU 和内存需求是否合适。如果需要调整,vpa-updater 使用更新后的值重新启动 Pods。

  4. 等待 vpa-updater 启动新 hamster Pod。这大概需要一两分钟。我们可以使用以下命令监控 Pods。

注意

  如果我们不确定已经启动了新 Pod,请将 Pod 名称与我们之前的列表比较。新 Pod 启动时,我们会看到新 Pod 名称。

  ```
  kubectl get --watch Pods -l app=hamster
  ```
  1. 当新 hamster Pod 启动时,描述它并查看更新后的 CPU 和内存预留。

    kubectl describe pod hamster-789f8477df-ldpxc
    

    示例输出如下。

    [...]
    Containers:
      hamster:
        Container ID:  docker://2c3e7b6fb7ce0d8c86444334df654af6fb3fc88aad4c5d710eac3b1e7c58f7db
        Image:         registry.k8s.io/ubuntu-slim:0.1
        Image ID:      docker-pullable://registry.k8s.io/ubuntu-slim@sha256:b6f8c3885f5880a4f1a7cf717c07242eb4858fdd5a84b5ffe35b1cf680ea17b1
        Port:          <none>
        Host Port:     <none>
        Command:
          /bin/sh
        Args:
          -c
          while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done
        State:          Running
          Started:      Thu, 05 Dec 2024 02:21:42 +0800
        Ready:          True
        Restart Count:  0
        Requests:
          cpu:        587m
          memory:     262144k
    [...]
    

    在之前的输出中,我们可以看到 cpu 预留提升到了 587 个 millicpu,这是原始值的五倍多。memory 提高到了 262144 KB,即大约 250 MB,也就是原始值的五倍。此 Pod 资源不足,Vertical Pod Autoscaler 使用更为合适的值纠正了估计值。

  2. 描述 hamster-vpa 资源以查看新的建议。

    kubectl describe vpa/hamster-vpa
    

    示例输出如下。

    Name:         hamster-vpa
    Namespace:    default
    Labels:       <none>
    Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                    {"apiVersion":"autoscaling.k8s.io/v1beta2","kind":"VerticalPodAutoscaler","metadata":{"annotations":{},"name":"hamster-vpa","namespace":"d...
    API Version:  autoscaling.k8s.io/v1beta2
    Kind:         VerticalPodAutoscaler
    Metadata:
      Creation Timestamp:  2024-12-04T02:22:51Z
      Generation:          23
      Resource Version:    14411
      Self Link:           /apis/autoscaling.k8s.io/v1beta2/namespaces/default/verticalpodautoscalers/hamster-vpa
      UID:                 d0d85fb9-e153-11e9-ae53-0205785d75b0
    Spec:
      Target Ref:
        API Version:  apps/v1
        Kind:         Deployment
        Name:         hamster
    Status:
      Conditions:
        Last Transition Time:  2024-12-04T02:23:28Z
        Status:                True
        Type:                  RecommendationProvided
      Recommendation:
        Container Recommendations:
          Container Name:  hamster
          Lower Bound:
            Cpu:     550m
            Memory:  262144k
          Target:
            Cpu:     587m
            Memory:  262144k
          Uncapped Target:
            Cpu:     587m
            Memory:  262144k
          Upper Bound:
            Cpu:     21147m
            Memory:  387863636
    Events:          <none>
    
  3. 在完成对示例应用程序的试验后,使用以下命令可将其删除。

    kubectl delete -f examples/hamster.yaml
    

优化vpa配置

调整 VPA Updater 参数

背景问题分析

由于业务需求,某些 Pod 的副本数必须固定为单副本,这与 VPA 默认策略的假设(需要至少两个副本以避免更新时的服务中断)相冲突。使用 VPA 时,Updater 遇到了以下报错

pods_eviction_restriction.go:226] too few replicas for ReplicaSet cnsre/cnsrevpapod-555464bbc9. Found 1 live pods, needs 2 (global 2)

为解决此问题,需要对 Updater 和 Recommender 进行参数调整,以适应单副本 Pod 的场景,提升配置调整的灵活性和稳定性。

配置文件

 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
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vpa-updater
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vpa-updater
  template:
    metadata:
      labels:
        app: vpa-updater
    spec:
      serviceAccountName: vpa-updater
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534 # nobody 用户
      containers:
      - name: updater
        args:
        - "--min-replicas=1"
        - "--v=4"
        - "--stderrthreshold=info"
        - "--kube-api-qps=20"
        - "--kube-api-burst=40"
        - "--in-recommendation-bounds-eviction-lifetime-threshold=0s" 
        image: registry.k8s.io/autoscaling/vpa-updater:1.2.1
        imagePullPolicy: Always
        resources:
          limits:
            cpu: 200m
            memory: 1000Mi
          requests:
            cpu: 50m
            memory: 500Mi
        ports:
        - name: prometheus
          containerPort: 8943

参数解析

  1. --min-replicas=1:设置最小副本数为 1,确保当部署的副本数大于等于 1 时,VPA Updater 才会执行更新操作,防止在只有一个副本时频繁重启影响服务可用性。

  2. --kube-api-qps=20--kube-api-burst=40:提高与 Kubernetes API 交互的 QPS(每秒请求数)和突发请求数限制,确保在大规模集群或频繁更新情况下,VPA Updater 能够及时获取和更新资源信息。

  3. --in-recommendation-bounds-eviction-lifetime-threshold=0s:设置当 Pod 的资源请求在推荐范围内时,允许立即驱逐 Pod。默认情况下,VPA 会等待一定时间才会驱逐这些 Pod,以减少不必要的重启。将此参数设置为 0s,可以加速资源更新,但需要谨慎使用,避免因频繁重启影响服务稳定性。

  4. -v=4--stderrthreshold=info:设置日志级别为详细模式,方便调试和监控 VPA Updater 的行为。

效果与注意事项

通过上述参数调整,VPA Updater 将更积极地更新 Pod 的资源配置,尤其是在资源请求已经在推荐范围内但需要更新的情况下。需要注意的是,过于频繁的 Pod 重启可能会导致服务不稳定,因此应根据实际需求和应用特点进行权衡。

调整 VPA Recommender 参数

背景问题分析*

在创建 Vertical Pod Autoscaler (VPA) 的配置后,经常会遇到推荐参数更新不及时或不符合预期的问题。这些问题主要表现为以下情况:

​ 1. 推荐参数延迟:VPA Recommender 无法及时计算和更新资源需求,导致 Pod 重建和调优速度滞后。

​ 2. 推荐效果不理想:推荐的 CPU 或内存参数无法满足实际工作负载需求,影响应用性能或资源利用率。

为了解决这些问题,我们需要对 VPA Recommender 的默认参数进行调整,使其更加贴合业务需求,提高资源管理的及时性和准确性。

配置文件

 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
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vpa-recommender
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vpa-recommender
  template:
    metadata:
      labels:
        app: vpa-recommender
    spec:
      serviceAccountName: vpa-recommender
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534 # nobody 用户
      containers:
      - name: recommender
        image: registry.k8s.io/autoscaling/vpa-recommender:1.2.1
        imagePullPolicy: Always
        args:
        - "--recommender-interval=1m"
        - "--history-length=30m"
        - "--oom-bump-up-ratio=1.5"
        - "--oom-min-bump-up-bytes=209715200"
        - "--recommendation-margin-fraction=0.25"
        - "--recommendation-lower-bound-cpu-percentile=0.1"
        - "--recommendation-lower-bound-memory-percentile=0.1"
        - "--recommendation-upper-bound-cpu-percentile=0.95"
        - "--recommendation-upper-bound-memory-percentile=0.95"
        - "--kube-api-qps=20"
        - "--kube-api-burst=40"
        - "-v=4"
        resources:
          limits:
            cpu: 200m
            memory: 1000Mi
          requests:
            cpu: 50m
            memory: 500Mi
        ports:
        - name: prometheus
          containerPort: 8942

参数解析

  1. --recommender-interval=1m:将推荐器的运行间隔设置为 1 分钟,意味着 VPA 每分钟计算一次新的资源推荐值。

  2. --history-length=30m:仅使用过去 30 分钟的历史数据进行推荐,使得推荐结果更加敏感,能及时反映近期的资源使用情况。

  3. --oom-bump-up-ratio=1.5:当发生 OOM(内存不足)时,将内存推荐值提高 1.5 倍,增加内存缓冲,防止再次发生 OOM。

  4. --oom-min-bump-up-bytes=209715200:当发生 OOM 时,最少增加 200MB 的内存,确保有足够的内存缓冲。

  5. --recommendation-margin-fraction=0.25:将资源推荐的安全边际提高到 25%,在推荐值上增加额外的缓冲,减少资源不足的风险。

  6. --recommendation-lower-bound-cpu-percentile=0.1--recommendation-lower-bound-memory-percentile=0.1:将 CPU 和内存的推荐下限百分位设置为 10%,过滤掉短期的低资源使用情况,防止推荐值过低。

  7. --recommendation-upper-bound-cpu-percentile=0.95--recommendation-upper-bound-memory-percentile=0.95:将 CPU 和内存的推荐上限百分位设置为 95%,限制推荐值的最大值,防止过度分配资源。

  8. --kube-api-qps=20--kube-api-burst=40:同样提高与 Kubernetes API 交互的请求限制,确保 Recommender 能够及时获取数据。

  9. -v=4:设置详细的日志级别,方便调试。

效果与注意事项

通过调整 Recommender 的参数,可以使资源推荐更加灵活和贴近实际使用情况。例如,缩短历史数据的参考范围,可以使推荐值更快地响应负载变化。然而,过短的历史数据可能导致推荐值波动过大,需要通过增加安全边际和调整百分位来平衡。

压测过程与结果分析

在调整 VPA 配置后,为验证优化效果,我们进行了详细的压测。以下是完整的测试过程,包括观察 VPA 推荐值的变化、Pod 状态的更新,以及通过负载工具模拟高负载场景。


压测准备

1. 检查 VPA 推荐值

通过以下命令实时观察 VPA 推荐值的更新情况:

1
kubectl get vpa cnsrevpapod-vpa -n cnsre -w

输出结果:

NAME                MODE       CPU     MEM           PROVIDED   AGE
cnsrevpapod-vpa   Recreate   2315m   30751634503   True       45h
cnsrevpapod-vpa   Recreate   2315m   30751634503   True       45h

观察到 VPA 内存推荐值从 30Gi 提升至 50Gi,说明推荐器对负载进行了及时响应。

2. 监控 Deployment 状态

在 VPA 更新生效期间,通过以下命令实时跟踪 Deployment 的状态变化:

1
kubectl get deploy cnsrevpapod -n cnsre -w

输出结果:

NAME            READY   UP-TO-DATE   AVAILABLE   AGE
cnsrevpapod   1/1     1            1           23d

分析:

  • Pod 在 VPA 更新生效时被重建(Recreate 模式),出现短暂的不可用状态。
  • 更新完成后,Pod 恢复为 READY 1/1 状态,资源调整成功。

3. 安装压测工具

进入 Pod 内部并安装 stress 工具,用于生成高负载。

1
kubectl exec -it cnsrevpapod-555464bbc9-6vjst -n cnsre -- /bin/bash

安装步骤:

  1. 下载 RPM 包:

    1
    
    curl -O https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/s/stress-1.0.4-24.el8.x86_64.rpm
    
  2. 安装 RPM 包:

    1
    
    rpm -ivh stress-1.0.4-24.el8.x86_64.rpm
    
  3. 验证安装:

    1
    
    stress --version
    

输出:

stress 1.0.4

压测执行

运行以下命令,在 Pod 内部生成高负载:

1
stress --cpu 10 --vm 5 --vm-bytes 10G --vm-keep

压测输出

kube exec -it cnsrevpapod-555464bbc9-6vjst      -n cnsre /bin/bash
─╯
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
bash-4.4# curl -O https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/s/stress-1.0.4-24.el8.x86_64.rpm
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 39864  100 39864    0     0  1441k      0 --:--:-- --:--:-- --:--:-- 1441k
bash-4.4# rpm -ivh stress-1.0.4-24.el8.x86_64.rpm
warning: stress-1.0.4-24.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 2f86d6a1: NOKEY
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:stress-1.0.4-24.el8              ################################# [100%]
bash-4.4# stress --version
stress 1.0.4
bash-4.4# stress --cpu 10 --vm 5 --vm-bytes 10G --vm-keep 
stress: info: [11485] dispatching hogs: 10 cpu, 0 io, 5 vm, 0 hdd
command terminated with exit code 137

断开是因为pod 进行了重启
参数说明:

  • --cpu 10:使用 10 个 CPU 核心生成计算负载。
  • --vm 5:启动 5 个虚拟内存工作线程。
  • --vm-bytes 10G:每个线程分配 10GB 内存。
  • --vm-keep:持续分配内存,防止释放后被回收。

压测观察与结果

1. Pod 内部状态

在压测过程中,Pod 的 CPU 和内存资源被占满,符合预期。可以通过以下命令验证资源使用情况:
输出示例:

1
2
3
4
5
6
7
8
kube top   pods cnsrevpapod-555464bbc9-6vjst -n cnsre
NAME                             CPU(cores)   MEMORY(bytes)   
cnsrevpapod-555464bbc9-6vjst   6882m        17166Mi         
kube top   pods cnsrevpapod-555464bbc9-6vjst -n cnsre
NAME                             CPU(cores)   MEMORY(bytes)   
cnsrevpapod-555464bbc9-6vjst   6882m        17166Mi         
kube top   pods cnsrevpapod-555464bbc9-6vjst -n cnsre
Error from server (NotFound): pods "cnsrevpapod-555464bbc9-6vjst" not found

pod 不存在是因为pod进行了重启

2. VPA 推荐值更新

压测运行一段时间后,VPA 推荐值会自动调整,提升资源分配以应对负载:

1
kubectl get vpa cnsrevpapod-vpa -n cnsre -w

更新后的推荐值:

NAME                MODE       CPU     MEM           PROVIDED   AGE
cnsrevpapod-vpa   Recreate   2315m   30751634503   True       45h
cnsrevpapod-vpa   Recreate   2315m   30751634503   True       45h
cnsrevpapod-vpa   Recreate   9500m   50Gi          True       45h

3. Deployment 状态变化

VPA 调整完成后,Deployment 更新状态稳定,Pod 正常运行:

1
2
3
4
5
6
kube get  deploy cnsrevpapod  -n cnsre -w
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
cnsrevpapod   1/1     1            1           23d
cnsrevpapod   0/1     0            0           23d
cnsrevpapod   0/1     1            0           23d
cnsrevpapod   1/1     1            1           23d

观察新pod的配置参数

1
kubectl describe pod cnsrevpapod-555464bbc9-tlgx8 -n cnsre

输出示例:

    State:          Running
      Started:      Thu, 05 Dec 2024 12:11:42 +0800
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:     2315m
      memory:  50Gi
    Environment:

压测结论

  1. VPA 能够动态调整单副本 Pod 的资源分配,及时响应高负载需求。
  2. 在压测过程中,VPA 推荐值更新迅速,资源分配上限(50Gi 内存和 9500m CPU)有效保障了服务的稳定性。
  3. Deployment 的短暂重建(Recreate 模式)可能会导致服务瞬时不可用。建议在关键场景中考虑切换至 Auto 模式,结合 PodDisruptionBudget 进行平滑更新。
  4. stress 工具成功验证了优化配置的效果,为业务提供了可靠的负载保障机制。

通过此次测试,我们验证了优化配置在生产环境中的实际效果,为后续性能调优和稳定性保障提供了重要依据。

总结

通过以上调整,我们对 VPA 的 Updater、Recommender 和 VPA 对象本身进行了自定义配置,以满足特定的资源管理需求。具体效果包括:

  • 更快速的资源更新:缩短了 Recommender 的运行间隔,并允许 Updater 立即驱逐符合条件的 Pod。

  • 更灵活的资源推荐:调整了历史数据参考范围和推荐值的百分位,使推荐结果更贴近实际使用情况。

  • 资源分配的安全性:增加了资源推荐的安全边际,设置了资源请求和限制的上下限,防止过度分配或资源不足。

在实际应用中,建议根据应用的特性和负载模式,逐步调整 VPA 的参数,并在测试环境中验证效果,确保在满足性能要求的同时,优化资源的利用率和成本效益。

参考资料

希望本文能帮助您更好地理解和使用 Kubernetes VPA,以实现高效的资源管理和自动伸缩。


作者:SRE运维博客
博客地址:https://www.cnsre.cn/
文章地址:https://www.cnsre.cn/posts/241205123704/
相关话题:https://www.cnsre.cn/tags/k8s/

您的鼓励是我最大的动力
alipay QR Code
wechat QR Code

Avatar
作者
CNSRE
一位只会重启的运维


目录