4.8.2 资源限制

容器的资源需求仅能达到为其保证可用的最少资源量的目的,它并不会限制容器的可用资源上限,因此对因应用本身存在 Bug 等多种原因而导致的系统资源被长时间占用的情况则无计可施,这就需要通过 limits 属性为容器定义资源的最大可用量。资源分配时,可压缩型资源 CPU 的控制阀门可自由调节,容器进程无法获得超过其 CPU 配额的可用时间。不过,如果进程申请分配超出其 limits 属性定义的硬限制的内存资源时,它将被 OOM Killer 杀死,不过,随后可能会被其控制进程所重启,例如,容器进程的 Pod 对象会被杀死并重启(重启策略为 Always 或 OnFailure 时),或者时容器进程的子进程被其父进程所重启。

下面的配置清单文件(memleak-pod.yaml)中定义了如何使用 saadali/simmemleak 镜像运行一个 Pod 对象,它模拟内存泄露操作不断地申请使用内存资源,直到超出 limits 属性中 memory 字段设定的值而导致 “OMMKilled” 为止:

apiVersion: v1
kind: Pod
metadata:
  name: memleak-pod
  labels:
    app: memleak
spec:
  containers:
  - name: simmemleak
    image: saadali/simmemleak
    resources:
      requests:
        memory: "64Mi"
        cpu: "1"
      limits:
        memory: "64Mi"
        cpu: "1"

下面测试其运行效果,首先将配置清单中定义的资源使用下面的命令创建于集群中:

**[terminal]
**[delimiter $ ]**[command kubectl apply -f memleak-pod.yaml]
pod/memleak-pod created

pod 资源的默认重启策略为 Always,于是在 memleak 因内存资源达到硬限制而被终止后会立即重启,因为用户很难观察到其因 OOM 而被杀死的相关信息。不过,多次重复的因为内存资源消耗尽而重启会出发 Kubernetes 系统的重启延迟机制,即每次重启的时间间隔会不断地拉长。于是,用户看到的 Pod 资源的相关状态通常为 “CrashLoopBackOff”:

**[terminal]
**[delimiter $ ]**[command kubectl apply -f memleak-pod.yaml]
NAME          READY   STATUS             RESTARTS   AGE
memleak-pod   0/1     CrashLoopBackOff   5          4m11s

Pod 资源首次的重启将在 crash 后立即完成,若随后再次 crash,那么其重启操作会延迟10秒进行,随后的延迟时长会逐渐增加,依次为20秒,40秒,80秒,160秒和300秒,随后的延迟将固定在5分钟的时长之上而不再增加,直到其不再 crash 或者 delete 为止。describe 命令可以显示其状态的详细信息,其部分内容如下所示:

**[terminal]
**[delimiter $ ]**[command kubectl describe pods memleak-pod]
Name:               memleak-pod
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               kube-node-1.localdomain/192.168.0.134
Start Time:         Sat, 07 Dec 2019 10:56:17 +0800
Labels:             app=memleak
Annotations:        kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"memleak"},"name":"memleak-pod","namespace":"default"},"spec"...
Status:             Running
IP:                 10.244.2.9
Containers:
  simmemleak:
    Container ID:   docker://465caf91fd04e71f16e413401f5b3ebb43eae6c2942e8a4002adb921501ce1a4
    Image:          saadali/simmemleak
    Image ID:       docker-pullable://saadali/simmemleak@sha256:5cf58299a7698b0c9779acfed15c8e488314fcb80944550eab5992cdf3193054
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Sat, 07 Dec 2019 11:02:01 +0800
      Finished:     Sat, 07 Dec 2019 11:02:02 +0800
    Ready:          False
    Restart Count:  6
    Limits:
      cpu:     1
      memory:  64Mi
    Requests:
      cpu:        1
      memory:     64Mi
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-fwfzr (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  default-token-fwfzr:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-fwfzr
    Optional:    false
QoS Class:       Guaranteed
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age                     From                              Message
  ----     ------     ----                    ----                              -------
  Normal   Scheduled  8m20s                   default-scheduler                 Successfully assigned default/memleak-pod to kube-node-1.localdomain
  Normal   Pulling    7m32s (x4 over 8m19s)   kubelet, kube-node-1.localdomain  Pulling image "saadali/simmemleak"
  Normal   Pulled     7m32s (x4 over 8m17s)   kubelet, kube-node-1.localdomain  Successfully pulled image "saadali/simmemleak"
  Normal   Created    7m31s (x4 over 8m17s)   kubelet, kube-node-1.localdomain  Created container simmemleak
  Normal   Started    7m31s (x4 over 8m17s)   kubelet, kube-node-1.localdomain  Started container simmemleak
  Warning  BackOff    3m12s (x28 over 8m14s)  kubelet, kube-node-1.localdomain  Back-off restarting failed container

如上述命令结果所显示的,OOMKilled 表示容器因内存耗尽而被终止,因此,为 limits 属性中的 memory 设置一个合理值至关重要。与 requests 不同的是,limits 并不影响 Pod 的调度结果,也就是说,一个节点上的所有 Pod 对象的 limits 数量之和可以大于节点所拥有的资源量,即支持资源的过载使用(overcommitted)。不过,这么一来一旦资源耗尽,尤其是内存资源耗尽,则必然会有容器因 OOMKilled 而终止。

另外需要说明的是,Kubernetes 仅会确保 Pod 能够获得它们请求(requests)的 CPU 时间额度,它们能否获得额外(throttled)的 CPU 时间,则取决于其他正在运行的作业对 CPU 资源的占用情况。例如,对于总数为 1000m 的 CPU 资源来说,容器A请求使用 200m,容器B请求使用 500m,在不超出它们各自的最大限额的前提下,余下的300m在双方都需要时会以 2:5(200m:500m) 的方式进行分配。

results matching ""

    No results matching ""