Pod 和容器的资源管理

当你指定一个Pod时,你可以选择性地指定每个容器所需的资源量。最常见的资源是 CPU 和内存(RAM),还有其他资源。

当你指定 Pod 中容器的资源**请求**时,kube-scheduler 会使用此信息来决定将 Pod 放置在哪个节点上。当你为容器指定资源**限制**时,kubelet 会强制执行这些限制,以确保正在运行的容器不允许使用超过你设置的限制的资源。kubelet 还会专门为该容器保留至少**请求**的系统资源量以供使用。

请求和限制

如果 Pod 正在运行的节点有足够的可用资源,容器可以使用超过其针对该资源指定的`request`(这是允许的)。

例如,如果你为容器设置了 256 MiB 的 `memory` 请求,并且该容器所在的 Pod 被调度到一个具有 8 GiB 内存且没有其他 Pod 的节点上,那么该容器可以尝试使用更多的 RAM。

限制则不同。`cpu` 和 `memory` 限制都由 kubelet(和容器运行时)应用,并最终由内核强制执行。在 Linux 节点上,Linux 内核使用cgroups强制执行限制。`cpu` 和 `memory` 限制的强制执行行为略有不同。

CPU 限制通过 CPU 节流来强制执行。当容器接近其 CPU 限制时,内核将根据容器的限制来限制对 CPU 的访问。因此,CPU 限制是内核强制执行的硬限制。容器不能使用超过其 CPU 限制中指定的 CPU 量。

内存限制由内核通过内存不足(OOM)终止来强制执行。当容器使用超过其内存限制时,内核可能会终止它。但是,终止只发生在内核检测到内存压力时。因此,过度分配内存的容器可能不会立即被终止。这意味着内存限制是反应性强制执行的。容器可以使用超过其内存限制的内存,但如果这样做,它可能会被终止。

资源类型

**CPU** 和 **内存** 都是一种**资源类型**。资源类型有一个基本单位。CPU 代表计算处理能力,以Kubernetes CPU 单位指定。内存以字节为单位指定。对于 Linux 工作负载,你可以指定**大页**(huge page)资源。大页是 Linux 特有的功能,其中节点内核分配的内存块比默认页大小大得多。

例如,在一个默认页大小为 4KiB 的系统上,你可以指定一个限制,`hugepages-2Mi: 80Mi`。如果容器尝试分配超过 40 个 2MiB 大页(总计 80 MiB),则该分配会失败。

CPU 和内存统称为**计算资源**或**资源**。计算资源是可度量的量,可以请求、分配和消耗。它们与API 资源不同。API 资源,例如 Pod 和服务是可以通过 Kubernetes API 服务器读取和修改的对象。

Pod 和容器的资源请求和限制

对于每个容器,您可以指定资源限制和请求,包括以下内容:

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.limits.hugepages-<size>
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory
  • spec.containers[].resources.requests.hugepages-<size>

尽管您只能为单个容器指定请求和限制,但考虑 Pod 的总体资源请求和限制也很有用。对于特定资源,**Pod 资源请求/限制**是 Pod 中每个容器对该类型资源的请求/限制的总和。

Pod 级别资源规范

特性状态: Kubernetes v1.34 [beta] (默认启用:true)

如果你的集群启用了 `PodLevelResources` 功能门控,你可以在 Pod 级别指定资源请求和限制。在 Pod 级别,Kubernetes 1.34 仅支持特定资源类型(CPU、内存和/或 HugePages)的资源请求或限制。通过此功能,Kubernetes 允许你为 Pod 声明一个总体资源预算,这在处理大量容器时特别有用,因为很难准确评估单个容器的资源需求。此外,它还允许 Pod 中的容器相互共享空闲资源,从而提高资源利用率。

对于 Pod,您可以通过包含以下内容来指定 CPU 和内存的资源限制和请求:

  • spec.resources.limits.cpu
  • spec.resources.limits.memory
  • spec.resources.limits.hugepages-<size>
  • spec.resources.requests.cpu
  • spec.resources.requests.memory
  • spec.resources.requests.hugepages-<size>

Kubernetes 中的资源单位

CPU 资源单位

CPU 资源的限制和请求以**CPU**单位测量。在 Kubernetes 中,1 CPU 单位相当于**1 个物理 CPU 核心**或**1 个虚拟核心**,具体取决于节点是物理主机还是在物理机内运行的虚拟机。

允许分数请求。当您将容器的 `spec.containers[].resources.requests.cpu` 设置为 `0.5` 时,您请求的 CPU 时间是请求 `1.0` CPU 的一半。对于 CPU 资源单位,数量表达式 `0.1` 等同于表达式 `100m`,可以读作“一百毫核”。有些人说“一百毫核”,这被理解为相同的意思。

CPU 资源始终以资源的绝对量指定,从不以相对量指定。例如,`500m` CPU 代表的计算能力大致相同,无论该容器运行在单核、双核还是 48 核机器上。

内存资源单位

`memory` 的限制和请求以字节为单位测量。您可以使用以下数量后缀之一,将内存表示为纯整数或定点数:E、P、T、G、M、k。您还可以使用二进制等效项:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下值大致相同:

128974848, 129e6, 129M,  128974848000m, 123Mi

请注意后缀的大小写。如果您请求 `400m` 的内存,这表示请求 0.4 字节。输入此值的人可能原本想请求 400 MiB (400Mi) 或 400 MB (400M)。

容器资源示例

以下 Pod 有两个容器。这两个容器都定义了 0.25 CPU 和 64 MiB (226 字节) 内存的请求。每个容器的限制为 0.5 CPU 和 128 MiB 内存。可以说该 Pod 请求 0.5 CPU 和 128 MiB 内存,限制为 1 CPU 和 256 MiB 内存。

---
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Pod 资源示例

特性状态: Kubernetes v1.34 [beta] (默认启用:true)

此功能可通过设置 `PodLevelResources` 功能门控来启用。以下 Pod 具有 1 CPU 和 100 MiB 内存的显式请求,以及 1 CPU 和 200 MiB 内存的显式限制。`pod-resources-demo-ctr-1` 容器设置了显式请求和限制。然而,`pod-resources-demo-ctr-2` 容器将只共享 Pod 资源边界内的可用资源,因为它没有设置显式请求和限制。

apiVersion: v1
kind: Pod
metadata:
  name: pod-resources-demo
  namespace: pod-resources-example
spec:
  resources:
    limits:
      cpu: "1"
      memory: "200Mi"
    requests:
      cpu: "1"
      memory: "100Mi"
  containers:
  - name: pod-resources-demo-ctr-1
    image: nginx
    resources:
      limits:
        cpu: "0.5"
        memory: "100Mi"
      requests:
        cpu: "0.5"
        memory: "50Mi"
  - name: pod-resources-demo-ctr-2
    image: fedora
    command:
    - sleep
    - inf 

带有资源请求的 Pod 如何被调度

当你创建 Pod 时,Kubernetes 调度器会为 Pod 选择一个运行节点。每个节点对每种资源类型都有一个最大容量:它可以为 Pods 提供的 CPU 和内存量。调度器会确保,对于每种资源类型,已调度容器的资源请求总和小于节点的容量。请注意,尽管节点上的实际内存或 CPU 资源使用率非常低,但如果容量检查失败,调度器仍会拒绝将 Pod 放置在该节点上。这可以防止在资源使用量增加时(例如,在每日请求峰值期间)节点上出现资源短缺。

Kubernetes 如何应用资源请求和限制

当 kubelet 启动作为 Pod 一部分的容器时,kubelet 将该容器的内存和 CPU 请求和限制传递给容器运行时。

在 Linux 上,容器运行时通常配置内核 cgroups 来应用和强制执行你定义的限制。

  • CPU 限制定义了容器可以使用多少 CPU 时间的硬上限。在每个调度间隔(时间片)期间,Linux 内核会检查是否超出了此限制;如果超出,内核会等待,然后再允许该 cgroup 恢复执行。
  • CPU 请求通常定义一个权重。如果几个不同的容器 (cgroups) 想要在一个资源争用的系统上运行,那么具有较大 CPU 请求的工作负载将获得比具有较小请求的工作负载更多的 CPU 时间。
  • 内存请求主要用于(Kubernetes)Pod 调度期间。在支持 cgroups v2 的节点上,容器运行时可能会将内存请求用作设置 `memory.min` 和 `memory.low` 的提示。
  • 内存限制为该 cgroup 定义了一个内存上限。如果容器试图分配超出此限制的内存,Linux 内核的内存不足子系统将激活,并通常通过停止容器中试图分配内存的进程之一进行干预。如果该进程是容器的 PID 1,并且容器被标记为可重启,则 Kubernetes 将重新启动该容器。
  • Pod 或容器的内存限制也可应用于内存支持卷中的页面,例如 `emptyDir`。kubelet 将 `tmpfs` emptyDir 卷视为容器内存使用,而不是本地临时存储。 使用内存支持的 `emptyDir` 时,请务必查看下面的注意事项。

如果容器超出了其内存请求,并且它所运行的节点总体内存不足,那么该容器所属的 Pod 很可能会被驱逐

容器可能会或可能不会被允许长时间超出其 CPU 限制。但是,容器运行时不会因 CPU 使用过度而终止 Pod 或容器。

要确定容器是否无法调度或因资源限制而被终止,请参阅故障排除部分。

监控计算和内存资源使用

kubelet 将 Pod 的资源使用情况作为 Pod `status` 的一部分进行报告。

如果集群中提供了可选的监控工具,则可以通过Metrics API直接或从您的监控工具中检索 Pod 资源使用情况。

内存支持的 `emptyDir` 卷的注意事项

从内存管理的角度来看,进程使用内存作为工作区和使用内存支持的 `emptyDir` 有一些相似之处。但是,当使用内存作为卷(如内存支持的 `emptyDir`)时,您还需要注意以下几点:

  • 存储在内存支持卷上的文件几乎完全由用户应用程序管理。与用作进程工作区不同,您不能依赖诸如语言级垃圾回收之类的东西。
  • 将文件写入卷的目的是保存数据或在应用程序之间传递数据。Kubernetes 和操作系统都不能自动从卷中删除文件,因此当系统或 Pod 内存不足时,这些文件所使用的内存无法回收。
  • 内存支持的 `emptyDir` 因其性能而有用,但内存通常比其他存储介质(如磁盘或 SSD)的尺寸小得多,成本也高得多。将大量内存用于 `emptyDir` 卷可能会影响 Pod 或整个节点的正常运行,因此应谨慎使用。

如果您是集群或命名空间的管理员,您还可以设置ResourceQuota来限制内存使用;您可能还需要定义LimitRange以进行额外强制执行。如果您为每个 Pod 指定了 `spec.containers[].resources.limits.memory`,那么 `emptyDir` 卷的最大大小将是 Pod 的内存限制。

作为替代方案,集群管理员可以使用策略机制(例如ValidationAdmissionPolicy)强制执行新 Pod 中 `emptyDir` 卷的大小限制。

本地临时存储

特性状态: Kubernetes v1.25 [稳定]

节点具有本地临时存储,由本地连接的可写设备或有时由 RAM 提供支持。“临时”意味着对持久性没有长期保证。

Pod 使用临时本地存储作为暂存空间、缓存和日志。kubelet 可以使用本地临时存储通过将`emptyDir`挂载到容器中,为 Pod 提供暂存空间。

kubelet 还使用这种存储来保存节点级容器日志、容器镜像以及运行中容器的可写层。

Kubernetes 允许你跟踪、保留和限制 Pod 可以消耗的本地临时存储量。

本地临时存储的配置

Kubernetes 支持两种配置节点本地临时存储的方式:

在此配置中,所有不同类型的临时本地数据(`emptyDir` 卷、可写层、容器镜像、日志)都放置在一个文件系统中。配置 kubelet 最有效的方法是将此文件系统专用于 Kubernetes (kubelet) 数据。

kubelet 还会写入节点级容器日志,并将其与临时本地存储类似处理。

kubelet 将日志写入其配置的日志目录(默认为 `/var/log`)内的文件;并有一个用于其他本地存储数据的基础目录(默认为 `/var/lib/kubelet`)。

通常,`/var/lib/kubelet` 和 `/var/log` 都位于系统根文件系统上,kubelet 的设计考虑了这种布局。

您的节点可以拥有任意数量的其他不用于 Kubernetes 的文件系统。

节点上有一个文件系统,您将其用于来自运行中 Pod 的临时数据:日志和 `emptyDir` 卷。您可以将此文件系统用于其他数据(例如:与 Kubernetes 无关的系统日志);它甚至可以是根文件系统。

kubelet 还会将节点级容器日志写入第一个文件系统,并将其与临时本地存储类似处理。

您还使用由不同逻辑存储设备支持的单独文件系统。在此配置中,您告知 kubelet 放置容器镜像层和可写层的目录位于第二个文件系统上。

第一个文件系统不包含任何镜像层或可写层。

您的节点可以拥有任意数量的其他不用于 Kubernetes 的文件系统。

kubelet 可以测量它使用了多少本地存储。它这样做,前提是您使用本地临时存储的一种支持配置设置了节点。

如果您有不同的配置,则 kubelet 不会对临时本地存储应用资源限制。

设置本地临时存储的请求和限制

您可以指定 `ephemeral-storage` 来管理本地临时存储。Pod 的每个容器可以指定以下一个或两个:

  • spec.containers[].resources.limits.ephemeral-storage
  • spec.containers[].resources.requests.ephemeral-storage

`ephemeral-storage` 的限制和请求以字节数量表示。您可以将存储表示为纯整数或使用以下后缀之一的定点数:E、P、T、G、M、k。您还可以使用二进制等效项:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下数量都大致表示相同的值:

  • 128974848
  • 129e6
  • 129M
  • 123Mi

请注意后缀的大小写。如果您请求 `400m` 的临时存储,这表示请求 0.4 字节。输入此值的人可能原本想请求 400 MiB (400Mi) 或 400 MB (400M)。

在以下示例中,Pod 有两个容器。每个容器都请求 2GiB 的本地临时存储。每个容器的限制为 4GiB 的本地临时存储。因此,该 Pod 请求 4GiB 的本地临时存储,限制为 8GiB 的本地临时存储。其中 500Mi 的限制可由 `emptyDir` 卷消耗。

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  volumes:
    - name: ephemeral
      emptyDir:
        sizeLimit: 500Mi

带有 ephemeral-storage 请求的 Pod 如何被调度

当您创建一个 Pod 时,Kubernetes 调度器会为该 Pod 选择一个运行节点。每个节点都可以为 Pods 提供最大量的本地临时存储。有关更多信息,请参阅节点可分配资源

调度器确保已调度容器的资源请求总和小于节点的容量。

临时存储消耗管理

如果 kubelet 将本地临时存储作为资源进行管理,则 kubelet 会测量存储使用情况:

  • `emptyDir` 卷,除了 *tmpfs* `emptyDir` 卷
  • 保存节点级别日志的目录
  • 可写容器层

如果 Pod 使用的临时存储超过您允许的量,kubelet 会设置一个驱逐信号,触发 Pod 驱逐。

对于容器级隔离,如果容器的可写层和日志使用量超出其存储限制,kubelet 会将 Pod 标记为驱逐。

对于 Pod 级隔离,kubelet 通过汇总该 Pod 中所有容器的存储限制来计算 Pod 的总体存储限制。在这种情况下,如果所有容器的本地临时存储使用量以及 Pod 的 `emptyDir` 卷的总和超出了 Pod 的总体存储限制,则 kubelet 也会将该 Pod 标记为驱逐。

kubelet 支持不同的方式来测量 Pod 存储使用情况:

kubelet 执行定期、计划的检查,扫描每个 `emptyDir` 卷、容器日志目录和可写容器层。

扫描测量使用了多少空间。

特性状态: Kubernetes v1.31 [beta] (默认禁用)

项目配额是用于管理文件系统存储使用的操作系统级别功能。通过 Kubernetes,您可以启用项目配额来监控存储使用情况。确保节点上支持 `emptyDir` 卷的文件系统提供项目配额支持。例如,XFS 和 ext4fs 提供项目配额。

Kubernetes 使用从 `1048576` 开始的项目 ID。正在使用的 ID 注册在 `/etc/projects` 和 `/etc/projid` 中。如果此范围内的项目 ID 用于系统上的其他目的,则这些项目 ID 必须注册在 `/etc/projects` 和 `/etc/projid` 中,以便 Kubernetes 不会使用它们。

配额比目录扫描更快、更准确。当一个目录被分配到一个项目时,该目录下创建的所有文件都在该项目中创建,内核只需跟踪该项目中文件使用了多少块。如果一个文件被创建和删除,但有一个打开的文件描述符,它会继续占用空间。配额跟踪准确地记录了该空间,而目录扫描则会忽略被删除文件占用的存储空间。

要使用配额来跟踪 Pod 的资源使用情况,Pod 必须位于用户命名空间中。在用户命名空间中,内核限制对文件系统上 projectID 的更改,确保配额计算的存储指标的可靠性。

如果要使用项目配额,您应该:

  • 使用 kubelet 配置中的 `featureGates` 字段启用 `LocalStorageCapacityIsolationFSQuotaMonitoring=true` 功能门控

  • 确保 `UserNamespacesSupport` 功能门控已启用,并且内核、CRI 实现和 OCI 运行时支持用户命名空间。

  • 确保根文件系统(或可选的运行时文件系统)已启用项目配额。所有 XFS 文件系统都支持项目配额。对于 ext4 文件系统,您需要在文件系统未挂载时启用项目配额跟踪功能。

    # For ext4, with /dev/block-device not mounted
    sudo tune2fs -O project -Q prjquota /dev/block-device
    
  • 确保根文件系统(或可选的运行时文件系统)已挂载并启用了项目配额。对于 XFS 和 ext4fs,挂载选项都命名为 `prjquota`。

如果您不想使用项目配额,您应该:

扩展资源

扩展资源是 `kubernetes.io` 域之外的完全限定资源名称。它们允许集群操作员通告非 Kubernetes 内置资源,并允许用户使用这些资源。

使用扩展资源需要两个步骤。首先,集群操作员必须通告扩展资源。其次,用户必须在 Pod 中请求扩展资源。

管理扩展资源

节点级扩展资源

节点级扩展资源与节点绑定。

设备插件管理资源

有关如何在每个节点上通告设备插件管理资源的信息,请参见设备插件

其他资源

要通告新的节点级扩展资源,集群操作员可以向 API 服务器提交 `PATCH` HTTP 请求,以指定集群中节点 `status.capacity` 中的可用数量。此操作后,节点的 `status.capacity` 将包含新的资源。kubelet 会异步自动使用新资源更新 `status.allocatable` 字段。

由于调度器在评估 Pod 适应性时使用节点的 `status.allocatable` 值,因此调度器仅在该异步更新后才考虑新值。在用新资源修补节点容量与第一个请求该资源的 Pod 可以调度到该节点之间可能会有短暂的延迟。

示例

以下示例展示了如何使用 `curl` 形成 HTTP 请求,以在主节点为 `k8s-master` 的节点 `k8s-node-1` 上通告五个“example.com/foo”资源。

curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1foo", "value": "5"}]' \
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status

集群级扩展资源

集群级扩展资源不与节点绑定。它们通常由调度器扩展器管理,调度器扩展器处理资源消耗和资源配额。

您可以在调度器配置中指定由调度器扩展器处理的扩展资源。

示例

以下调度器策略配置表明集群级扩展资源“example.com/foo”由调度器扩展器处理。

  • 只有当 Pod 请求 "example.com/foo" 时,调度器才将 Pod 发送到调度器扩展器。
  • `ignoredByScheduler` 字段指定调度器在其 `PodFitsResources` 谓词中不检查 "example.com/foo" 资源。
{
  "kind": "Policy",
  "apiVersion": "v1",
  "extenders": [
    {
      "urlPrefix":"<extender-endpoint>",
      "bindVerb": "bind",
      "managedResources": [
        {
          "name": "example.com/foo",
          "ignoredByScheduler": true
        }
      ]
    }
  ]
}

通过 DRA 进行扩展资源分配

通过 DRA 进行扩展资源分配允许集群管理员在 DeviceClass 中指定 `extendedResourceName`,然后可以从 Pod 的扩展资源请求中请求与 DeviceClass 匹配的设备。阅读有关通过 DRA 进行扩展资源分配的更多信息。

使用扩展资源

用户可以在 Pod 规格中像 CPU 和内存一样使用扩展资源。调度器负责资源记账,以便同时分配给 Pod 的资源量不超过可用量。

API 服务器将扩展资源的数量限制为整数。**有效**数量的示例包括 `3`、`3000m` 和 `3Ki`。**无效**数量的示例包括 `0.5` 和 `1500m`(因为 `1500m` 将导致 `1.5`)。

要在 Pod 中使用扩展资源,请将资源名称作为容器规范中 `spec.containers[].resources.limits` 映射中的键包含进去。

只有当所有资源请求(包括 CPU、内存和任何扩展资源)都得到满足时,Pod 才会调度。只要资源请求无法满足,Pod 就会保持 `PENDING` 状态。

示例

下面的 Pod 请求 2 个 CPU 和 1 个“example.com/foo”(一个扩展资源)。

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: myimage
    resources:
      requests:
        cpu: 2
        example.com/foo: 1
      limits:
        example.com/foo: 1

PID 限制

进程 ID (PID) 限制允许配置 kubelet 来限制给定 Pod 可以消耗的 PID 数量。有关信息,请参阅PID 限制

故障排除

我的 Pods 处于 Pending 状态,并显示事件消息 `FailedScheduling`

如果调度器找不到任何 Pod 可以适应的节点,Pod 将保持未调度状态,直到找到一个位置。每次调度器未能为 Pod 找到位置时,都会生成一个事件。您可以使用 `kubectl` 查看 Pod 的事件;例如:

kubectl describe pod frontend | grep -A 9999999999 Events
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  23s   default-scheduler  0/42 nodes available: insufficient cpu

在前面的示例中,名为“frontend”的 Pod 由于任何节点上的 CPU 资源不足而无法调度。类似的错误消息也可能表明由于内存不足(PodExceedsFreeMemory)导致的失败。通常,如果 Pod 处于挂起状态并带有此类型的消息,可以尝试以下几件事:

  • 向集群添加更多节点。
  • 终止不需要的 Pods,为待处理的 Pods 腾出空间。
  • 检查 Pod 是否没有比所有节点都大。例如,如果所有节点的容量都是 `cpu: 1`,那么请求 `cpu: 1.1` 的 Pod 将永远不会被调度。
  • 检查节点污点。如果大多数节点都被污染,并且新 Pod 不容忍该污点,则调度器只会考虑将其放置在没有该污点的其余节点上。

您可以使用 `kubectl describe nodes` 命令检查节点容量和分配量。例如:

kubectl describe nodes e2e-test-node-pool-4lw4
Name:            e2e-test-node-pool-4lw4
[ ... lines removed for clarity ...]
Capacity:
 cpu:                               2
 memory:                            7679792Ki
 pods:                              110
Allocatable:
 cpu:                               1800m
 memory:                            7474992Ki
 pods:                              110
[ ... lines removed for clarity ...]
Non-terminated Pods:        (5 in total)
  Namespace    Name                                  CPU Requests  CPU Limits  Memory Requests  Memory Limits
  ---------    ----                                  ------------  ----------  ---------------  -------------
  kube-system  fluentd-gcp-v1.38-28bv1               100m (5%)     0 (0%)      200Mi (2%)       200Mi (2%)
  kube-system  kube-dns-3297075139-61lj3             260m (13%)    0 (0%)      100Mi (1%)       170Mi (2%)
  kube-system  kube-proxy-e2e-test-...               100m (5%)     0 (0%)      0 (0%)           0 (0%)
  kube-system  monitoring-influxdb-grafana-v4-z1m12  200m (10%)    200m (10%)  600Mi (8%)       600Mi (8%)
  kube-system  node-problem-detector-v0.1-fj7m3      20m (1%)      200m (10%)  20Mi (0%)        100Mi (1%)
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  CPU Requests    CPU Limits    Memory Requests    Memory Limits
  ------------    ----------    ---------------    -------------
  680m (34%)      400m (20%)    920Mi (11%)        1070Mi (13%)

在上述输出中,您可以看到,如果 Pod 请求超过 1.120 个 CPU 或超过 6.23Gi 的内存,该 Pod 将无法适应此节点。

通过查看“Pods”部分,您可以查看哪些 Pod 正在占用节点上的空间。

可用 Pod 的资源量小于节点容量,因为系统守护进程占用了一部分可用资源。在 Kubernetes API 中,每个 Node 都有一个 `status.allocatable` 字段(有关详细信息,请参见NodeStatus)。

`status.allocatable` 字段描述了该节点上可供 Pod 使用的资源量(例如:15 个虚拟 CPU 和 7538 MiB 内存)。有关 Kubernetes 中节点可分配资源的更多信息,请参见为系统守护进程保留计算资源

您可以配置资源配额来限制命名空间可以消耗的资源总量。当命名空间中有 ResourceQuota 时,Kubernetes 会强制执行特定命名空间中对象的配额。例如,如果您将特定命名空间分配给不同的团队,您可以将 ResourceQuotas 添加到这些命名空间中。设置资源配额有助于防止一个团队使用过多的资源,从而影响其他团队。

您还应该考虑授予该命名空间的访问权限:对命名空间的**完全**写访问权限允许拥有该访问权限的人删除任何资源,包括已配置的 ResourceQuota。

我的容器被终止了

您的容器可能会因资源不足而被终止。要检查容器是否因达到资源限制而被终止,请对相关 Pod 调用 `kubectl describe pod`:

kubectl describe pod simmemleak-hra99

输出类似于:

Name:                           simmemleak-hra99
Namespace:                      default
Image(s):                       saadali/simmemleak
Node:                           kubernetes-node-tf0f/10.240.216.66
Labels:                         name=simmemleak
Status:                         Running
Reason:
Message:
IP:                             10.244.2.75
Containers:
  simmemleak:
    Image:  saadali/simmemleak:latest
    Limits:
      cpu:          100m
      memory:       50Mi
    State:          Running
      Started:      Tue, 07 Jul 2019 12:54:41 -0700
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Fri, 07 Jul 2019 12:54:30 -0700
      Finished:     Fri, 07 Jul 2019 12:54:33 -0700
    Ready:          False
    Restart Count:  5
Conditions:
  Type      Status
  Ready     False
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  42s   default-scheduler  Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
  Normal  Pulled     41s   kubelet            Container image "saadali/simmemleak:latest" already present on machine
  Normal  Created    41s   kubelet            Created container simmemleak
  Normal  Started    40s   kubelet            Started container simmemleak
  Normal  Killing    32s   kubelet            Killing container with id ead3fb35-5cf5-44ed-9ae1-488115be66c6: Need to kill Pod

在前面的示例中,`Restart Count: 5` 表示 Pod 中的 `simmemleak` 容器已被终止并重新启动了五次(到目前为止)。`OOMKilled` 原因表明容器尝试使用的内存超出了其限制。

您的下一步可能是检查应用程序代码是否存在内存泄漏。如果您发现应用程序的行为符合预期,请考虑为该容器设置更高的内存限制(也可能是请求)。

下一步

上次修改时间:2025 年 8 月 6 日下午 3:40 PST:移除了 DeviceClass 周围的反引号 (3a894e1291)