图解Kubernetes中pod的资源请求与限制,以及最佳实践

459 阅读8分钟

在 Kubernetes 中使用容器时,资源的需求与分配非常重要。某些应用比其他应用需要更多的 CPU 或内存,关键的应用特别需要重点保护,不应该因为资源不足而影响使用。因此,我们应该正确配置Containers和Pods,以便使用最少的资源保证正常的运行,兼顾性能与成本,做到既要,又要,还要。

Kubernetes资源请求与限制(Requests & Limits)

使用 Kubernetes 时,限制和请求是重要的设置。本文将重点讨论两个最重要的资源:CPU 和内存。

Kubernetes 将限制定义为 容器可使用的最大资源量。这意味着容器消耗的内存量或 CPU 量永远不会超过指定的量。

另一方面,请求是为容器保留的最小资源量

实践示例

让我们看一下这个部署,我们在 CPU 和内存上为两个不同的容器设置限制和请求。

kind: Deployment
apiVersion: extensions/v1beta1

template:
  spec:
    containers:
      - name: redis
        image: redis:5.0.3-alpine
        resources:
          limits:
            memory: 600Mi
            cpu: 1
          requests:
            memory: 300Mi
            cpu: 500m
      - name: busybox
        image: busybox:1.28
        resources:
          limits:
            memory: 200Mi
            cpu: 300m
          requests:
            memory: 100Mi
            cpu: 100m

假设我们正在运行一个具有 4 核和 16GB RAM 节点的集群。我们可以提取出很多信息:

Kubernetes 限制和请求实际示例

  1. Pod 有效请求为 300+100 = 400MiB 内存和 500+100=600毫核 CPU。您需要一个具有足够可用可分配空间的节点来调度 Pod。
  2. Redis 容器的CPU 份额为 512,busybox 容器的 CPU 份额为 102。Kubernetes 总是为每个核心分配 1024 个共享,因此 redis:1024 * 0.5 个核心 ≅ 512 和 busybox:1024 * 0.1 个核心 ≅ 102
  3. 如果 Redis 容器尝试分配超过 600MB 的 RAM,它将被OOM 终止,很可能导致 Pod 失败。
  4. 如果Redis尝试每 100 毫秒使用超过 100 毫秒的 CPU,(由于我们有 4 个核心,因此每 100 毫秒可用时间将为 400 毫秒),Redis 将遭受 CPU 限制,从而导致性能下降**。**
  5. 如果 Busybox 容器尝试分配超过 200MB 的 RAM,则会被OOM 终止,从而导致 pod 失败。
  6. 如果Busybox试图每 100 毫秒使用超过 30 毫秒的 CPU,就会遭受CPU 限制,从而导致性能下降。

Kubernetes 请求

Kubernetes 将请求定义为容器使用的保证的最小资源量。

基本上,它将设置容器消耗的最小资源量。

当 Pod 被调度时,kube-scheduler 将检查 Kubernetes 请求,以便将其分配到至少可以满足 Pod 中所有容器的数量的特定节点。如果请求的数量高于可用资源,Pod 将不会被调度并保持 Pending 状态。

在此示例中,在容器定义中,我们设置了 100m 核 CPU 和 4Mi 内存的请求:

resources:
   requests:
        cpu: 0.1
        memory: 4Mi

请求使用:

  • 当将 Pod 分配给 Node 时,Pod 中的容器所指示的请求将得到满足。
  • 在运行时,将保证指定 Pod 中的容器的请求量为最小值。

如何设置良好的 CPU 请求

Kubernetes 限制

Kubernetes 将限制定义为容器可使用的最大资源量。

这意味着容器消耗的内存量或 CPU 量永远不会超过指定的量。

    resources:
      limits:
        cpu: 0.5
        memory: 100Mi

使用限制:

  • 将 Pod 分配给 Node 时。如果没有设置请求,默认情况下,Kubernetes 将分配请求=限制。
  • 在运行时,Kubernetes 将检查 Pod 中的容器消耗的资源量是否高于限制中指示的数量。

在 Kubernetes 中设置良好的限制

CPU 特性

CPU 是一种可压缩资源,这意味着它可以被拉伸以满足所有需求。如果进程请求过多的 CPU,其中一些进程将受到限制。

CPU代表计算处理时间,以核心为单位测量。

  • 您可以使用毫核 (m) 来表示比核心更小的数量(例如,500m 是半个核心)
  • 最小量为1m
  • 一个节点可能有多个可用核,因此可以请求 CPU > 1

Kubernetes 请求 CPU 镜像

内存特性

内存是一种不可压缩的资源,这意味着它不能像 CPU 那样进行扩展。如果一个进程没有获得足够的内存来工作,该进程就会被终止。

Kubernetes 中的内存以字节为单位

  • 您可以使用 E、P、T、G、M、k 来表示 Exabyte、Petabyte、Terabyte、Gigabyte、Megabyte 和 kilobyte,但通常只使用最后四种。(如500M、4G)
  • 警告:不要使用小写 m 表示内存(这代表毫字节,低得离谱)
  • 您可以使用 Mi 定义 Mebibytes,也可以使用 Ei、Pi、Ti 定义其余的单位(例如 500Mi)

Mebibyte(及其类似物 Kibibyte、Gibibyte...)是 2 的 20 字节次方。它的创建是为了避免与公制的 Kilo、Mega 定义混淆。您应该使用此表示法,因为它是字节的规范定义,而 Kilo 和 Mega 是 1000 的倍数

Kubernetes 内存镜像的限制

最佳实践

在极少数情况下,您应该使用限制来控制 Kubernetes 中的资源使用情况。这是因为如果您想避免饥饿(确保每个重要进程都获得其份额),您应该首先使用请求。

通过设置限制,您只是防止进程在异常情况下检索额外的资源,在内存情况下导致 OOM 终止,在 CPU 情况下进行限制(进程需要等待 CPU 可以再次使用) 。

如果您将请求值设置为等于 Pod 的所有容器中的限制,则该 Pod 将获得保证的服务质量。

另请注意,资源使用率高于请求的 Pod 更有可能被驱逐,因此设置非常低的请求会弊大于利。

命名空间资源配额

借助命名空间,我们可以将 Kubernetes 资源隔离到不同的组(也称为租户)中。

使用ResourceQuotas,您可以为整个命名空间设置内存或 CPU 限制,确保其中的实体不会消耗更多的内存或 CPU 限制。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-demo
spec:
  hard:
    requests.cpu: 2
    requests.memory: 1Gi
    limits.cpu: 3
    limits.memory: 2Gi


  • requests.cpu:此命名空间中所有请求总和的最大 CPU 量
  • requests.memory:该命名空间中所有请求总和的最大内存量
  • limit.cpu:此命名空间中所有限制总和的最大 CPU 量
  • limit.memory:此命名空间中所有限制总和的最大内存量

然后,将其应用到您的命名空间:

kubectl apply -f resourcequota.yaml --namespace=mynamespace

您可以使用以下命令列出命名空间的当前 ResourceQuota:

kubectl get resourcequota -n mynamespace

请注意,如果您为命名空间中的给定资源设置 ResourceQuota,则需要为该命名空间中的每个 Pod 相应地指定限制或请求。如果没有,Kubernetes 将返回“配额失败”错误:

Error from server (Forbidden): error when creating "mypod.yaml": pods "mypod" is forbidden: failed quota: mem-cpu-demo: must specify limits.cpu,limits.memory,requests.cpu,requests.memory

如果您尝试添加容器限制或请求超出当前 ResourceQuota 的新 Pod,Kubernetes 将返回“超出配额”错误:

Error from server (Forbidden): error when creating "mypod.yaml": pods "mypod" is forbidden: exceeded quota: mem-cpu-demo, requested: limits.memory=2Gi,requests.memory=2Gi, used: limits.memory=1Gi,requests.memory=1Gi, limited: limits.memory=2Gi,requests.memory=1Gi

命名空间限制范围

如果我们想要限制可分配给命名空间的资源总量,则 ResourceQuota 非常有用。但是如果我们想给里面的元素赋予默认值会发生什么?

LimitRanges是一项 Kubernetes 策略,用于限制命名空间中每个实体的资源设置

apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-resource-constraint
spec:
  limits:
  - default:
      cpu: 500m
    defaultRequest:
      cpu: 500m
    min:
      cpu: 100m
    max:
      cpu: "1"
    type: Container

  • default:如果未指定,创建的容器将具有此值。
  • min:创建的容器不能有小于此的限制或请求。
  • max:创建的容器不能有大于此的限制或请求。

稍后,如果您创建一个没有设置请求或限制的新 Pod,LimitRange 会自动将这些值设置为其所有容器:

    Limits:
      cpu:  500m
    Requests:
      cpu:  100m

现在,假设您添加一个新的 Pod,限制为 1200M。您将收到以下错误:

Error from server (Forbidden): error when creating "pods/mypod.yaml": pods "mypod" is forbidden: maximum cpu usage per Container is 1, but limit is 1200m

请注意,默认情况下,Pod 中的所有容器实际上都会请求 100m CPU,即使没有设置 LimitRanges。

结论

为 Kubernetes 集群选择最佳限制是充分利用能源的关键。

为 Pod 提供的规模过大或投入过多的资源可能会导致成本飙升。

规模过小或专用很少的 CPU 或内存将导致应用程序无法正常运行,甚至 Pod 被驱逐。

如前所述,除非在非常特殊的情况下,否则不应使用 Kubernetes 限制,因为它们可能弊大于利。容器有可能在内存不足的情况下被杀死,或者在 CPU 不足的情况下被限制。

对于请求,当您需要确保进程获得有保证的资源份额时,请使用它们。

image.png