Pod 和容器的资源管理
当你指定一个 Pod 时,你可以选择性地指定一个容器需要的每种资源的数量。最常见的资源是 CPU 和内存 (RAM);还有其他资源。
当你为一个 Pod 中的容器指定资源请求时,kube-scheduler 使用此信息来决定将 Pod 放置在哪个节点上。当你为一个容器指定资源限制时,kubelet 强制执行这些限制,以便不允许正在运行的容器使用超过你设置的限制的资源。kubelet 还专门为该容器保留至少请求数量的系统资源以供使用。
请求和限制
如果运行 Pod 的节点有足够的可用资源,则容器可以使用比其资源request
指定更多的资源(这是允许的)。
例如,如果你为一个容器设置了 256 MiB 的 memory
请求,并且该容器位于调度到具有 8 GiB 内存且没有其他 Pod 的节点上的 Pod 中,则该容器可以尝试使用更多的 RAM。
限制是另外一回事。cpu
和 memory
限制都由 kubelet (和容器运行时) 应用,并最终由内核强制执行。在 Linux 节点上,Linux 内核使用cgroups强制执行限制。cpu
和 memory
限制强制执行的行为略有不同。
cpu
限制是通过 CPU 限流强制执行的。当一个容器接近其 cpu
限制时,内核将限制对与容器限制相对应的 CPU 的访问。因此,cpu
限制是内核强制执行的硬限制。容器可能不会使用超过其 cpu
限制中指定的 CPU。
memory
限制由内核通过内存不足 (OOM) 杀死强制执行。当一个容器使用的内存超过其 memory
限制时,内核可能会终止它。但是,只有在内核检测到内存压力时才会发生终止。因此,一个超额分配内存的容器可能不会立即被杀死。这意味着 memory
限制是被动强制执行的。一个容器可能会使用超过其 memory
限制的内存,但如果这样做,它可能会被杀死。
注意
如果你为一个资源指定了限制,但没有指定任何请求,并且没有准入时机制为该资源应用了默认请求,那么 Kubernetes 会复制你指定的限制并将其用作该资源的请求值。资源类型
CPU 和 memory 都是资源类型。资源类型具有基本单位。CPU 表示计算处理,以Kubernetes CPU为单位指定。内存以字节为单位指定。对于 Linux 工作负载,你可以指定大页面资源。大页面是 Linux 特有的功能,其中节点内核分配的内存块远大于默认页面大小。
例如,在默认页面大小为 4KiB 的系统上,你可以指定一个限制,hugepages-2Mi: 80Mi
。如果容器尝试分配超过 40 个 2MiB 大页面(总共 80 MiB),则该分配失败。
注意
你不能过度分配hugepages-*
资源。这与 memory
和 cpu
资源不同。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.32 [alpha]
(默认禁用:false)从 Kubernetes 1.32 开始,你还可以在 Pod 级别指定资源请求和限制。Pod 级别。在 Pod 级别,Kubernetes 1.32 仅支持特定资源类型的资源请求或限制:cpu
和/或 memory
。此功能目前处于 alpha 阶段,并且在启用该功能后,Kubernetes 允许你声明 Pod 的整体资源预算,这在处理大量容器(很难准确衡量单个资源需求)时特别有用。此外,它使 Pod 内的容器可以相互共享空闲资源,从而提高资源利用率。
对于 Pod,你可以通过包含以下内容来指定 CPU 和内存的资源限制和请求
spec.resources.limits.cpu
spec.resources.limits.memory
spec.resources.requests.cpu
spec.resources.requests.memory
Kubernetes 中的资源单位
CPU 资源单位
CPU 资源的限制和请求以 cpu 单位衡量。在 Kubernetes 中,1 个 CPU 单位等效于 **1 个物理 CPU 核心**或 **1 个虚拟核心**,具体取决于节点是物理主机还是在物理机内运行的虚拟机。
允许小数请求。当你定义一个 spec.containers[].resources.requests.cpu
设置为 0.5
的容器时,你请求的 CPU 时间比请求 1.0
CPU 的 CPU 时间少一半。对于 CPU 资源单位,quantity 表达式 0.1
等效于表达式 100m
,它可以理解为“一百毫核”。有些人说“一百毫核”,并且理解为同一件事。
CPU 资源始终以绝对量指定,而不是相对量。例如,500m
CPU 表示大致相同的计算能力,无论该容器运行在单核、双核还是 48 核的机器上。
注意
Kubernetes 不允许您以低于 1m
或 0.001
CPU 的精度指定 CPU 资源。为了避免意外使用无效的 CPU 数量,当使用小于 1 个 CPU 单位时,最好使用 milliCPU 形式而不是十进制形式来指定 CPU 单位。
例如,您有一个 Pod 使用 5m
或 0.005
CPU,并且想要减少其 CPU 资源。使用十进制形式时,很难发现 0.0005
CPU 是一个无效值,而使用 milliCPU 形式时,更容易发现 0.5m
是一个无效值。
内存资源单位
memory
的限制和请求以字节为单位进行测量。您可以使用整数或使用以下数量后缀之一来表示内存:E、P、T、G、M、k。您也可以使用 2 的幂等效项:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下表示大致相同的值
128974848, 129e6, 129M, 128974848000m, 123Mi
请注意后缀的大小写。如果您请求 400m
的内存,则这是请求 0.4 字节。键入该值的人可能想要求 400 mebibytes (400Mi
) 或 400 megabytes (400M
)。
容器资源示例
以下 Pod 有两个容器。这两个容器都定义为请求 0.25 CPU 和 64MiB(226 字节)的内存。每个容器的限制为 0.5 CPU 和 128MiB 的内存。可以说该 Pod 的请求为 0.5 CPU 和 128 MiB 的内存,限制为 1 CPU 和 256MiB 的内存。
---
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.32 [alpha]
(默认禁用:false)以下 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。每个节点都有每个资源类型的最大容量:它可以为 Pod 提供的 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
卷指定 sizeLimit
,则该卷可能会消耗高达该 Pod 的内存限制 (Pod.spec.containers[].resources.limits.memory
)。如果您没有设置内存限制,则 Pod 的内存消耗没有上限,并且可以消耗节点上的所有可用内存。Kubernetes 根据资源请求 (Pod.spec.containers[].resources.requests
) 调度 Pod,并且在决定是否可以将另一个 Pod 放入给定节点时,不会考虑高于请求的内存使用情况。这可能会导致拒绝服务,并导致操作系统执行内存不足 (OOM) 处理。可以创建任意数量的 emptyDir
,这些 emptyDir
可能会消耗节点上的所有可用内存,从而使 OOM 更有可能发生。从内存管理的角度来看,进程将内存用作工作区时与使用内存支持的 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 可以使用本地临时存储为 Pod 提供暂存空间,以将emptyDir
卷挂载到容器中。
kubelet 还使用这种类型的存储来保存节点级容器日志、容器映像和运行容器的可写层。
警告
如果节点发生故障,其临时存储中的数据可能会丢失。您的应用程序不能期望从本地临时存储获得任何性能 SLA(例如,磁盘 IOPS)。注意
要使资源配额在临时存储上工作,需要完成两件事
- 管理员在命名空间中为临时存储设置资源配额。
- 用户需要在 Pod 规范中为临时存储资源指定限制。
如果用户未在 Pod 规范中指定临时存储资源限制,则不会对临时存储强制执行资源配额。
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 不会对临时本地存储应用资源限制。
注意
kubelet 将tmpfs
emptyDir 卷作为容器内存使用情况进行跟踪,而不是作为本地临时存储。注意
kubelet 将仅跟踪根文件系统的临时存储。将单独的磁盘挂载到/var/lib/kubelet
或 /var/lib/containers
的操作系统布局将无法正确报告临时存储。设置本地临时存储的请求和限制
你可以指定 ephemeral-storage
来管理本地临时存储。Pod 的每个容器都可以指定以下一个或两个:
spec.containers[].resources.limits.ephemeral-storage
spec.containers[].resources.requests.ephemeral-storage
ephemeral-storage
的限制和请求以字节为单位进行度量。你可以将存储表示为普通整数或使用以下后缀之一的定点数:E、P、T、G、M、k。你还可以使用 2 的幂等效项:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下数量都表示大致相同的值
128974848
129e6
129M
123Mi
注意后缀的大小写。如果你请求 400m
的临时存储,则请求的是 0.4 字节。输入此值的人可能本意是请求 400 mebibytes (400Mi
) 或 400 megabytes (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。每个节点都有一个可以为 Pod 提供的最大本地临时存储量。有关更多信息,请参阅节点可分配资源。
调度器确保已调度容器的资源请求总和小于节点的容量。
临时存储消耗管理
如果 kubelet 将本地临时存储作为资源进行管理,则 kubelet 会在以下位置测量存储使用情况:
emptyDir
卷,除了 tmpfsemptyDir
卷- 保存节点级日志的目录
- 可写的容器层
如果 Pod 使用的临时存储量超过了你允许的量,则 kubelet 会设置一个驱逐信号,从而触发 Pod 驱逐。
对于容器级隔离,如果容器的可写层和日志使用量超过其存储限制,则 kubelet 会将 Pod 标记为驱逐。
对于 Pod 级隔离,kubelet 通过求和该 Pod 中容器的限制来计算整体 Pod 存储限制。在这种情况下,如果所有容器的本地临时存储使用量之和以及 Pod 的 emptyDir
卷超过了整体 Pod 存储限制,则 kubelet 也会将 Pod 标记为驱逐。
警告
如果 kubelet 没有测量本地临时存储,那么超出其本地存储限制的 Pod 不会因违反本地存储资源限制而被驱逐。
但是,如果可写的容器层、节点级日志或 emptyDir
卷的文件系统空间不足,则该节点会污点化自身,表示本地存储不足,并且此污点会触发任何不专门容忍该污点的 Pod 的驱逐。
请参阅受支持的临时本地存储配置。
kubelet 支持不同的方法来测量 Pod 存储使用情况
kubelet 执行定期的计划检查,扫描每个 emptyDir
卷、容器日志目录和可写的容器层。
扫描测量已使用的空间量。
注意
在此模式下,kubelet 不会跟踪已删除文件的打开的文件描述符。
如果你(或容器)在 emptyDir
卷中创建一个文件,然后某些东西打开该文件,并且你在该文件仍然打开的情况下删除该文件,则已删除文件的 inode 会一直保留到你关闭该文件,但 kubelet 不会将该空间归类为正在使用。
Kubernetes v1.31 [beta]
(默认禁用:false)项目配额是操作系统级别的功能,用于管理文件系统上的存储使用情况。借助 Kubernetes,你可以启用项目配额来监视存储使用情况。确保节点上支持 emptyDir
卷的文件系统提供项目配额支持。例如,XFS 和 ext4fs 提供项目配额。
注意
项目配额允许你监视存储使用情况;它们不强制限制。Kubernetes 使用从 1048576
开始的项目 ID。正在使用的 ID 注册在 /etc/projects
和 /etc/projid
中。如果此范围内的项目 ID 在系统上用于其他目的,则必须在 /etc/projects
和 /etc/projid
中注册这些项目 ID,以便 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
。
如果你不想使用项目配额,你应该
- 使用 kubelet 配置中的
featureGates
字段禁用LocalStorageCapacityIsolationFSQuotaMonitoring
功能门。
扩展资源
扩展资源是 kubernetes.io
域之外的完全限定的资源名称。它们允许集群操作员通告资源,并允许用户使用非 Kubernetes 内置资源。
使用扩展资源需要两个步骤。首先,集群操作员必须通告扩展资源。其次,用户必须在 Pod 中请求扩展资源。
管理扩展资源
节点级扩展资源
节点级扩展资源与节点绑定。
设备插件托管资源
请参阅设备插件,了解如何在每个节点上通告设备插件托管资源。
其他资源
要通告新的节点级扩展资源,集群操作员可以向 API 服务器提交一个 PATCH
HTTP 请求,以指定集群中节点的 status.capacity
中可用的数量。在此操作之后,节点的 status.capacity
将包含新的资源。status.allocatable
字段由 kubelet 自动使用新资源异步更新。
由于调度器在评估 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
}
]
}
]
}
使用扩展资源
用户可以在 Pod 规范中使用扩展资源,就像 CPU 和内存一样。调度器会负责资源记帐,以确保同时分配给 Pod 的资源不超过可用数量。
API 服务器将扩展资源的数量限制为整数。有效数量的示例为 3
、3000m
和 3Ki
。无效数量的示例为 0.5
和 1500m
(因为 1500m
将导致 1.5
)。
注意
扩展资源取代了不透明的整数资源。用户可以使用任何域名作为前缀,但kubernetes.io
保留使用。要在 Pod 中使用扩展资源,请在容器规约中的 spec.containers[].resources.limits
映射中包含资源名称作为键。
注意
扩展资源不能超额分配,因此如果容器规约中同时存在 request 和 limit,则它们必须相等。只有当所有资源请求都得到满足时,包括 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 处于挂起状态,事件消息为 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 处于挂起状态并显示此类消息,可以尝试以下几种方法
- 向集群添加更多节点。
- 终止不需要的 Pod,以便为挂起的 Pod 腾出空间。
- 检查 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
原因表明该容器尝试使用的内存超出了其限制。
你的下一步可能是检查应用程序代码是否存在内存泄漏。如果你发现应用程序的行为符合预期,请考虑为该容器设置更高的内存限制(以及可能的请求)。
下一步
- 获取 将内存资源分配给容器和 Pod 的实践经验。
- 获取 将 CPU 资源分配给容器和 Pod 的实践经验。
- 阅读 API 参考如何定义一个容器及其资源需求
- 阅读有关 XFS 中的 项目配额 的更多信息
- 阅读有关 kube-scheduler 配置参考 (v1) 的更多信息
- 阅读有关 Pod 的服务质量类别 的更多信息