K8S 1.27 动态调整容器CPU和内存资源限制,无需重启应用程序

2023-08-09 14:09:54 浏览数 (1)

如果您在部署Pod时指定了 CPU 和内存资源,更改资源大小需要重新启动 Pod。到目前为止,重启对于正在运行工的作负载是一种破坏性操作。

Kubernetes 1.27 中的 alpha 功能发布。其中一项能够自动调整 Pod 的 CPU 和内存限制的大小,只需修补正在运行的 Pod 定义即可更改它们,而无需重新启动它。

这也意味着 resources 规范中的字段不能再作为 Pod 实际资源的指示符。监控工具和其他此类应用程序现在必须查看 Pod 状态中的新字段,这对我们的现有监控告警也是一项比较大的挑战。Kubernetes 通过对运行时(例如负责运行容器的 containerd)的 CRI(容器运行时接口)API 调用来查询实际的 CPU 和内存请求以及对正在运行的容器强制执行的限制。容器运行时的资源占用反映在 Pod 的状态中,这块后面会举例说明。

Kubernetes v1.27 有哪些新功能?

除了在 pod 规范中添加用于调整大小的重启策略之外,pod 的状态中还添加了三个新字段。

  • allocatedResources容器状态中的字段反映了分配给 pod 容器的节点资源。
  • resources容器状态中的字段反映了容器运行时报告的正在运行的容器上配置的实际资源(请求和限制)。
  • resizePod 的值Proposed是对请求的调整大小的确认,并指示请求已验证并记录。
  • resizePod 的值InProgress表示节点已接受调整大小请求,并且正在将调整大小请求应用到 Pod 的容器。
  • resizePod 的值Deferred表示此时无法授予请求的调整大小,节点将继续重试。当其他 Pod 离开并释放节点资源时,可以授予调整大小的权限。
  • resizePod 的值表示Infeasible节点无法适应所请求的调整大小。如果请求的调整大小超过节点可以为 Pod 分配的最大资源,就会发生这种情况。

何时使用此功能

  • Pod 正在节点上运行,但资源过多或过少。
  • 由于集群中缺乏足够的 CPU 或内存,而过度配置的正在运行的 Pod 未充分利用,因此无法调度此 Pod。
  • 当该节点上存在其他优先级较低的 Pod(可以调整大小或移动以为有状态 Pod 腾出空间)时,驱逐需要更多资源将其调度到更大节点上的某些有状态 Pod 是一项昂贵或具有破坏性的操作。

如何使用此功能

为了在 v1.27 中使用此功能,InPlacePodVerticalScaling 必须启用功能门。

代码语言:javascript复制
FEATURE_GATES=InPlacePodVerticalScaling=true ./hack/local-up-cluster.sh

一旦本地集群启动并运行,Kubernetes 用户就可以通过 kubectl 调度 pod 的资源并调整 pod 的大小。后文会演示使用此功能的示例。

已知问题

该功能进入 Kubernetes v1.27 的 alpha 阶段。以下是用户可能遇到的一些已知问题:

  • v1.6.9 以下的 containerd 版本不具备此功能的完整端到端操作所需的 CRI 支持。尝试调整 pod 大小似乎会陷入状态InProgress,并且resourcespod 状态中的字段永远不会更新,即使可能已在正在运行的容器上启用新资源。
  • Pod 调整大小可能会遇到与其他 Pod 更新的竞争条件,导致 Pod 调整大小延迟实施。
  • 调整大小后的容器资源反映在 pod 的状态中可能需要很长时间。
  • 此功能不支持 static CPU 管理策略。

示例

我使用 Kubernetes 的公共云版本,但由于这些托管版本中尚未提供 1.27 版(截至 2023 年 4 月),我们将使用 minikube 在本地启动一个版本。有很多方法可以做到这一点;这只是一个简单的例子。

这是在功能标志下发布的InPlacePodVerticalScaling。使用该标志启动一个 minikube 集群,并添加一个节点:

代码语言:javascript复制
minikube start --kubernetes-version=v1.27.0 --feature-gates=InPlacePodVerticalScaling=true --cni calico
minikube node add

准备就绪后,启动测试容器。举例来说,对于我们的应用程序,无需重新启动即可安全地更改 CPU 数量,但更改内存数量则需要重新启动。例如,运行数据库的 pod 在运行时 CPU 计数变化不会出现问题,但减少内存量会导致意外行为。restartPolicy我们通过设置为“内存”为RestartContainer,即重启容器才会生效,否则,默认行为将尝试就地更新所有资源。

代码语言:javascript复制
apiVersion: v1
kind: Pod
metadata:
  name: inplacedemo
spec:
  containers:
  - name: inplacedemo
    image: alpine
    command: ["tail", "-f", "/dev/null"]
    resizePolicy:
    - resourceName: "memory"
      restartPolicy: "RestartContainer"
    resources:
      limits:
        cpu: 2
        memory: "1Gi"
      requests:
        cpu: 1
        memory: "500Mi"

应用 yaml并确保它正在运行,然后在准备就绪时通过获取 pod 信息来查看新字段:

代码语言:javascript复制
$ kubectl apply -f yaml_above.yaml
pod/inplacedemo created
$ kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
inplacedemo   1/1     Running   0          53s
$ kubectl get pod inplacedemo -o yaml

在 pod 定义中要注意的是resizePolicy:

代码语言:javascript复制
spec:
  containers:
    ...
    resizePolicy:
    - resourceName: memory
      restartPolicy: RestartContainer
    - resourceName: cpu
      restartPolicy: NotRequired

allocatedResources是分配给 pod 容器的资源,并且还有一个附加resources字段。这反映了实际的当前资源,而不是所需/待更新的资源。

代码语言:javascript复制
 containerStatuses:
  - allocatedResources:
      cpu: "1"
      memory: 500Mi
    ...
    resources:
      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: "1"
        memory: 500Mi

让我们首先修改 pod CPU 限制,将其从 2 增加到 3。

代码语言:javascript复制
kubectl patch pod inplacedemo --patch '{"spec":{"containers":[{"name":"inplacedemo", "resources":{"limits":{"cpu":"3"}}}]}}'

再次查看 pod 规格

代码语言:javascript复制
spec:
  ...
    resources:
      limits:
        cpu: "3"
        memory: 1Gi
      requests:
        cpu: "1"
        memory: 500Mi

status:
  ...
  containerStatuses:
    ...
    resources:
      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: "1"
        memory: 500Mi
    restartCount: 0
  ...
  resize: InProgress

Pod 从 resize: InProgress完成到完成(标志消失)所需的时间而有所不同。如果您看到其他标志,例如resize: Infeasible,请检查您的节点资源以确保它们足够。

继续将限制从 1G 增加到 2G:

代码语言:javascript复制
kubectl patch pod inplacedemo --patch '{ "spec" :{ "containers" :[{ "name" : "inplacedemo" , "resources" :{ "limits" :{ "memory" : "2Gi" }}}]} }'

通过检查,调整大小标签和 Pod 状态的过程与之前相同。

Kubernetes 就地更新底层 c-group 分配,从而使 pod 资源定义可变。这在垂直扩展 pod 的情况下特别有用,例如使用 Kubernetes 内置的Vertical Pod Autoscaler (VPA),它允许应用程序在同一 pod 内向上/向下扩展资源(而不是通过更多pod 进/出进行扩展)与传统的水平 Pod 缩放一样)。

在许多用例中,垂直扩展很有帮助,例如某些 Java 应用程序在初始化期间可能需要比正常进程操作期间所需的 CPU 多得多的 CPU。如果此类应用程序指定适合正常操作的 CPU 请求和限制,则它们可能会遭受很长的启动时间。此类 Pod 可以在创建 Pod 时请求更高的 CPU 值,并且可以在应用程序完成初始化后调整大小以满足正常运行需求。

0 人点赞