Pod 和容器资源管理
当您指定一个 Pod 时,您可以选择性地指定每个资源的容器需要多少。最常见的要指定的资源是 CPU 和内存(RAM);还有一些其他资源。
当您为 Pod 中的容器指定资源 *请求* 时,kube-scheduler 会使用此信息来决定将 Pod 放置在哪个节点上。当您为容器指定资源 *限制* 时,kubelet 会执行这些限制,以便运行的容器不允许使用超过您设置的限制的资源。kubelet 还为该容器专门保留至少 *请求* 数量的系统资源以供使用。
请求和限制
如果运行 Pod 的节点有足够的可用资源,那么容器可以使用超过其为该资源指定的 请求
的资源(这是可能的,也是允许的)。但是,容器不允许使用超过其资源 限制
的资源。
例如,如果您为容器设置了 256 MiB 的 memory
请求,并且该容器位于已调度到具有 8GiB 内存且没有其他 Pod 的节点的 Pod 中,那么该容器可以尝试使用更多 RAM。
如果您为该容器设置了 4GiB 的 memory
限制,那么 kubelet(和 容器运行时)会执行该限制。运行时会阻止容器使用超过配置的资源限制。例如:当容器中的进程尝试使用超过允许的内存量时,系统内核会终止尝试分配的进程,并出现内存不足 (OOM) 错误。
限制可以通过被动方式(系统在发现违规时介入)或通过强制方式(系统阻止容器超过限制)来实现。不同的运行时可能对实现相同的限制有不同的方法。
注意
如果您为某个资源指定了限制,但没有指定任何请求,并且没有准入时间机制为该资源应用了默认请求,那么 Kubernetes 会复制您指定的限制并将其用作该资源的请求值。资源类型
*CPU* 和 *内存* 都是 *资源类型*。资源类型有一个基本单位。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 中每个容器的该类型资源请求/限制的总和。
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 核机器上运行。
注意
Kubernetes 不允许您使用比 1m
或 0.001
CPU 更精细的精度指定 CPU 资源。为了避免意外使用无效的 CPU 数量,当使用小于 1 个 CPU 单位时,使用毫芯形式而不是小数形式来指定 CPU 单位很有用。
例如,您有一个使用 5m
或 0.005
CPU 的 Pod,并且想要减少其 CPU 资源。通过使用小数形式,很难发现 0.0005
CPU 是一个无效的值,而通过使用毫芯形式,更容易发现 0.5m
是一个无效的值。
内存资源单位
memory
的限制和请求以字节为单位衡量。您可以使用以下其中一个 数量 后缀来表达内存,可以使用纯整数或使用定点数字:E、P、T、G、M、k。您还可以使用二的幂等效项:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下表示大致相同的值
128974848, 129e6, 129M, 128974848000m, 123Mi
请注意后缀的大小写。如果您请求 400m
的内存,这将是一个 0.4 字节的请求。可能输入该内容的人原本想要请求 400 兆字节 (400Mi
) 或 400 兆字节 (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 如何调度
当您创建 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。您也可以使用以下二的幂等效项:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下所有数量都大约表示相同的值
128974848
129e6
129M
123Mi
请注意后缀的大小写。如果您请求400m
的瞬时存储,这相当于请求 0.4 字节。可能有人在输入时是想请求 400 mibytes (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
具有瞬时存储请求的 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 不会将该空间归类为正在使用。
<div class="feature-state-notice feature-beta" title="Feature Gate: LocalStorageCapacityIsolationFSQuotaMonitoring">
<span class="feature-state-name">FEATURE STATE:</span> <code>Kubernetes v1.31 [beta]</code>
</div>
项目配额是操作系统级功能,用于管理文件系统上的存储使用情况。使用 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-node-1
节点上发布五个“example.com/foo”资源,其主节点是k8s-master
。
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
映射中包含资源名称作为键。
注意
扩展资源不能超额分配,因此如果容器规范中同时存在请求和限制,则它们必须相等。只有在满足所有资源请求(包括 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 限制以获取信息。
故障排除
我的 Pod 处于 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 处于 pending 状态,并显示此类消息,您可以尝试以下几种方法
- 向集群添加更多节点。
- 终止不必要的 Pod 以腾出空间供 pending 状态的 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 中,每个节点都有一个.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 分配内存资源的实践经验。
- 获取为容器和 Pod 分配 CPU 资源的实践经验。
- 阅读 API 参考文档,了解 容器 及其 资源需求 的定义。
- 阅读有关 XFS 中 项目配额 的内容。
- 详细了解 kube-scheduler 配置参考 (v1)。
- 详细了解 Pod 的服务质量类。