【Docker-Day 38】Kubernetes 核心调度:深入解析资源请求 (Requests) 与限制 (Limits) 的奥秘
Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来
Python系列文章目录
PyTorch系列文章目录
机器学习系列文章目录
深度学习系列文章目录
Java系列文章目录
JavaScript系列文章目录
Python系列文章目录
Go语言系列文章目录
Docker系列文章目录
01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)
07-【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
08-【Docker-Day 8】高手进阶:构建更小、更快、更安全的 Docker 镜像
09-【Docker-Day 9】实战终极指南:手把手教你将 Node.js 应用容器化
10-【Docker-Day 10】容器的“持久化”记忆:深入解析 Docker 数据卷 (Volume)
11-【Docker-Day 11】Docker 绑定挂载 (Bind Mount) 实战:本地代码如何与容器实时同步?
12-【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射
13-【Docker-Day 13】超越默认Bridge:精通Docker Host、None与自定义网络模式
14-【Docker-Day 14】Docker Compose深度解析
15-【Docker-Day 15】一键部署 WordPress!Docker Compose 实战终极指南
16-【Docker-Day 16】告别单机时代:为什么 Docker Compose 不够用,而你需要 Kubernetes?
17-【Docker-Day 17】K8s 架构全解析:深入理解 Kubernetes 的大脑 (Master) 与四肢 (Node)
18-【Docker-Day 18】告别选择困难症:一文掌握 Minikube、kind、k3d,轻松搭建你的第一个 K8s 集群
19-【Docker-Day 19】万物皆 YAML:掌握 Kubernetes 声明式 API 的艺术
20-【Docker-Day 20】揭秘 Kubernetes 的原子单位:深入理解 Pod
21-【Docker-Day 21】Pod的守护神:ReplicaSet与ReplicationController,轻松实现应用高可用
22-【K8s-Day 22】深入解析 Kubernetes Deployment:现代应用部署的基石与滚动更新的艺术
23-【K8s-Day 23】从 Pod 的“失联”到 Service 的“牵线”:深入理解 ClusterIP 核心原理
24-【Docker-Day 24】K8s网络解密:深入NodePort与LoadBalancer,让你的应用走出集群
25-【Docker-Day 25】深入理解 Kubernetes Namespace:实现多租户与环境隔离的利器
26-【Docker-Day 26】K8s实战演练:从零开始部署一个完整的前后端分离Web应用
27-【K8s-Day 27】应用的“体检医生”:深入解析 Kubernetes 健康检查探针 (Probe)
28-【Docker-Day 28】K8s 核心配置管理:解密 ConfigMap,告别硬编码!
29-【Docker-Day 29】K8s 安全第一课:揭秘敏感信息管理器 Secret
30-【Docker-Day 30】解密 K8s 的“硬盘”:深入理解 PersistentVolume (PV) 与 PersistentVolumeClaim (PVC)
31-【Docker-Day 31】告别手动创建 PV!一文搞懂 Kubernetes StorageClass 工作原理与实战
32-【K8s-Day 32】StatefulSet 深度解析:为你的数据库和有状态应用保驾护航
33-【Docker-Day 33】掌握 K8s 任务调度:DaemonSet、Job、CronJob 实战指南
34-【Docker-Day 34】Kubernetes Ingress 详解:从小白到精通的 K8s 流量路由指南
35-【Docker-Day 35】实战部署 Nginx Ingress Controller:集群流量入口的终极指南
36-【Docker-Day 36】K8s网络解密:CNI接口如何为Pod分配IP地址?
37-【Docker-Day 37】K8s 网络“防火墙”:NetworkPolicy 深度解析与实战
38-【Docker-Day 38】Kubernetes 核心调度:深入解析资源请求 (Requests) 与限制 (Limits) 的奥秘
文章目录
- Langchain系列文章目录
- Python系列文章目录
- PyTorch系列文章目录
- 机器学习系列文章目录
- 深度学习系列文章目录
- Java系列文章目录
- JavaScript系列文章目录
- Python系列文章目录
- Go语言系列文章目录
- Docker系列文章目录
- 摘要
- 一、引言:为什么 Pod 需要“口粮”定额?
- 1.1 无资源管理的“野蛮生长”时代
- 1.2 K8s 的“计划经济”
- 二、核心概念:资源请求 (Requests) 与资源限制 (Limits)
- 2.1 CPU 与 Memory 的单位
- 2.1.1 CPU 单位
- 2.1.2 Memory 单位
- 2.2 资源请求 (requests):Pod 的“最低消费”
- 2.2.1 调度器的决策依据
- 2.2.2 资源预留的保证
- 2.3 资源限制 (limits):Pod 的“消耗上限”
- 2.3.1 运行时的“天花板”
- 2.3.2 超出限制的后果
- 2.4 一图看懂 requests 与 limits 的关系
- 三、实战演练:在 Pod 中配置 Requests 和 Limits
- 3.1 YAML 配置详解
- 3.2 部署与验证
- (1) 部署 Pod
- (2) 验证配置
- (3) 查看节点资源分配情况
- 四、服务质量 (QoS) 等级:K8s 如何区别对待你的 Pod
- 4.1 QoS 的诞生背景
- 4.2 三大 QoS 等级详解
- 4.2.1 Guaranteed (最高优先级)
- 4.2.2 Burstable (中等优先级)
- 4.2.3 BestEffort (最低优先级)
- 4.3 QoS 等级总结与对比
- 4.4 如何查看 Pod 的 QoS 等级
- 五、最佳实践与常见问题
- 5.1 如何设定合理的 Requests 和 Limits?
- 5.2 常见问题 (FAQ)
- (1) 问题一:只设置 `limits` 不设置 `requests` 会怎样?
- (2) 问题二:只设置 `requests` 不设置 `limits` 会怎样?
- (3) 问题三:我的 Pod 为什么一直是 `Pending` 状态?
- (4) 问题四:我的 Pod 为什么被 `OOMKilled`?
- 六、总结
摘要
在 Kubernetes 集群这片繁忙的“土地”上,每个运行的 Pod 都像一个“租户”,需要消耗节点的计算资源。如果没有有效的管理,某些“野蛮生长”的 Pod 可能会耗尽所有资源,导致其他关键应用“饿死”,甚至引发节点崩溃。本文将作为 Kubernetes 调度艺术系列的上篇,深入剖析 K8s 资源管理的两大核心概念——资源请求 (Requests) 与资源限制 (Limits)。我们将从基本概念、单位讲起,通过形象的比喻和 YAML 实战,带你彻底理解它们如何影响 Pod 的调度和运行。最后,我们将揭示由它们决定的服务质量 (QoS) 等级,让你学会如何为 Pod 设置合理的“口粮”定额,构建一个稳定、高效的云原生环境。
一、引言:为什么 Pod 需要“口粮”定额?
在管理一个 Kubernetes 集群时,资源管理是保障集群稳定性和应用性能的基石。想象一个没有规则的共享公寓,如果一个租客无节制地使用水电,其他租客的生活必然会受到严重影响。在 K8s 中,Pod 就是“租客”,CPU 和内存就是“水电”。
1.1 无资源管理的“野蛮生长”时代
如果没有对 Pod 的资源消耗进行任何约束,会发生什么?
- 资源抢占与“邻里噪音”:一个有 Bug 或负载突然飙升的 Pod 可能会疯狂消耗其所在节点的 CPU 和内存,导致同一节点上的其他 Pod 无法获得必要的资源,响应变慢甚至崩溃。这就是典型的“邻里噪音”(Noisy Neighbor)问题。
- 调度盲目性:K8s 调度器 (
kube-scheduler
) 在为新 Pod 寻找合适的家(Node)时,如果不知道这个 Pod 的“饭量”有多大,就无法做出明智的决策。它可能会将一个资源消耗巨大的 Pod 调度到一个本已不堪重负的节点上,从而引发“雪崩效应”。 - 节点崩溃风险:当节点上的内存被耗尽时,Linux 内核的 OOM (Out Of Memory) Killer 机制会被触发,开始随机“杀死”进程以释放内存,这可能导致关键系统进程或重要应用被终止,最终造成节点宕机。
1.2 K8s 的“计划经济”
为了解决上述混乱状态,Kubernetes 引入了一套“计划经济”体系,其核心工具就是资源请求 (Requests) 和资源限制 (Limits)。
- 资源请求 (Requests):为 Pod 设定一个“最低生活保障”。它告诉调度器:“我的应用至少需要这么多资源才能正常启动和运行”。调度器会据此寻找一个能够满足其最低需求的节点。
- 资源限制 (Limits):为 Pod 设定一个“消耗天花板”。它告诉节点上的
kubelet
:“无论如何,我的应用使用的资源都不能超过这个上限”。这可以有效防止单个应用耗尽节点资源,保护了“邻居们”的安宁。
通过这两项配置,我们从“野蛮生长”进入了“精细化运营”的时代,让集群资源分配变得可预测、可控制、更稳定。
二、核心概念:资源请求 (Requests) 与资源限制 (Limits)
在深入配置之前,我们必须先精确理解这两个概念及其相关的资源单位。
2.1 CPU 与 Memory 的单位
Kubernetes 对计算资源的计量有自己的一套标准。
2.1.1 CPU 单位
CPU 是一种可压缩 (Compressible) 资源,意味着即使应用获取的 CPU 时间不足,它的性能会下降,但不会直接崩溃。
- 核心 (Cores):
1
代表 1 个完整的 CPU 核心。 - 毫核 (Millicores):
m
是最常用的单位,表示“千分之一核”。1000m
等于1
个核心。因此,500m
就代表了半个 CPU 核心的计算能力。
示例:requests.cpu: "0.5"
与 requests.cpu: "500m"
是等价的。
2.1.2 Memory 单位
内存是一种不可压缩 (Incompressible) 资源。一旦内存不足,应用无法“压缩”自己的内存需求,很可能直接崩溃。
- Kubernetes 使用标准的计算机存储单位,通常是基于 2 的幂次方:
Ki
(Kibibyte)Mi
(Mebibyte)Gi
(Gibibyte)Ti
(Tetrabyte)
- 你也可以使用对应的十进制单位,但为了精确,推荐使用前者。
换算关系:
- 1Mi=1024Ki1 Mi = 1024 Ki1Mi=1024Ki
- 1Gi=1024Mi1 Gi = 1024 Mi1Gi=1024Mi
示例:limits.memory: "256Mi"
表示限制内存使用为 256 Mebibytes。
2.2 资源请求 (requests):Pod 的“最低消费”
requests
主要服务于 调度阶段。
2.2.1 调度器的决策依据
当一个 Pod 被创建时,kube-scheduler
会扫描所有可用节点,检查每个节点的“可分配资源”是否大于或等于 Pod 中所有容器 requests
的总和。
调度决策流程:
Pod.spec.containers[].resources.requests
≤\le≤ Node.status.allocatable
如果找不到任何一个节点能满足 Pod 的资源请求,Pod 将会一直处于 Pending
状态,直到有足够的资源被释放出来。
2.2.2 资源预留的保证
一旦 Pod 被成功调度到某个节点上,该节点就会为这个 Pod 预留 requests
所指定的资源量。这意味着,即使在节点资源紧张的情况下,该 Pod 也能保证获得至少 requests
数量的资源。
比喻:
requests
就像预订酒店房间。你预订了一个大床房(请求了特定资源),酒店(调度器)就会为你找一个有空余大床房的分店(节点)。入住后,这个房间就确保是你的了,别人不能占用。
2.3 资源限制 (limits):Pod 的“消耗上限”
limits
主要在 运行阶段 发挥作用,由节点上的 kubelet
强制执行。
2.3.1 运行时的“天花板”
limits
为容器的资源使用设定了一个硬性上限。容器在任何时候都不能使用超过这个限制的资源。
2.3.2 超出限制的后果
超出 CPU 和 Memory 限制的后果截然不同:
- CPU (可压缩):如果一个容器的 CPU 使用试图超过其
limit
,它不会被杀死。相反,它的 CPU 使用会受到节流 (Throttling),即内核会强制减少分配给该进程的 CPU 时间片,导致应用性能下降。 - Memory (不可压缩):如果一个容器的内存使用超过其
limit
,它会变得不稳定,并极有可能被内核终止,这个过程被称为 OOMKilled (Out of Memory Killed)。Pod 的状态会显示为OOMKilled
。
比喻:
limits
就像你信用卡的额度。你可以自由消费(使用资源),但一旦消费金额达到额度上限(达到 limit),你的卡就会被冻结(CPU 节流或内存 OOMKilled)。
2.4 一图看懂 requests 与 limits 的关系
我们可以用一个简单的图来可视化 requests
和 limits
的关系。
上图描绘了一个 Pod:
- 内存:请求了
256Mi
(保证获得),限制为512Mi
(使用上限)。它的实际使用量在50Mi
到450Mi
之间波动,这是允许的。 - CPU:请求了
200m
(保证获得),限制为700m
(使用上限)。它的实际使用量在100m
到600m
之间波动,同样是允许的。
三、实战演练:在 Pod 中配置 Requests 和 Limits
理论知识最终要落地到实践。让我们通过一个 YAML 文件来具体配置。
3.1 YAML 配置详解
我们创建一个名为 resource-demo-pod.yaml
的文件,定义一个运行 Nginx 的 Pod,并为其设置资源请求和限制。
apiVersion: v1
kind: Pod
metadata:name: resource-demo-pod
spec:containers:- name: nginx-containerimage: nginx:latestresources:# --- 资源请求:调度和资源保证的依据 ---requests:memory: "128Mi" # 请求 128 Mebibytes 内存cpu: "250m" # 请求 0.25 个 CPU 核心 (250 millicores)# --- 资源限制:运行时资源使用的上限 ---limits:memory: "256Mi" # 限制最多使用 256 Mebibytes 内存cpu: "500m" # 限制最多使用 0.5 个 CPU 核心 (500 millicores)
关键配置解析:
spec.containers[]
:配置应用于 Pod 内的每个容器。resources
:该字段用于定义资源管理策略。resources.requests
:定义了容器的最低资源需求。resources.limits
:定义了容器的资源使用硬上限。
3.2 部署与验证
(1) 部署 Pod
使用 kubectl
应用该配置文件来创建 Pod。
kubectl apply -f resource-demo-pod.yaml
(2) 验证配置
使用 kubectl describe pod
命令可以查看 Pod 的详细信息,其中就包含了资源配置。
kubectl describe pod resource-demo-pod
在输出中,你会找到类似下面的部分,清晰地显示了已应用的 requests
和 limits
:
Containers:nginx-container:...Resources:Limits:cpu: 500mmemory: 256MiRequests:cpu: 250mmemory: 128Mi...
(3) 查看节点资源分配情况
你还可以通过 kubectl describe node <node-name>
查看节点上的资源分配情况。在 Allocated resources
部分,你会看到该节点上所有 Pod 的 requests
总和,这有助于了解节点的资源负载。
Allocated resources:(Total limits may be over 100 percent, i.e., overcommitted.)Resource Requests Limits-------- -------- ------cpu 850m (42%) 1700m (85%)memory 1044Mi (26%) 1952Mi (49%)...
四、服务质量 (QoS) 等级:K8s 如何区别对待你的 Pod
当你为 Pod 设置了不同的 requests
和 limits
组合时,Kubernetes 会自动为你的 Pod 划分一个服务质量 (QoS) 等级。这个等级决定了在节点资源紧张时,哪些 Pod 会被优先驱逐(杀死)。
4.1 QoS 的诞生背景
当一个节点资源耗尽(尤其是内存),K8s 必须做出艰难的选择:牺牲谁来保全大局?QoS 等级就是这个决策的优先级依据。高 QoS 等级的 Pod 会被优先保护,而低 QoS 等级的 Pod 则会成为首要的“牺牲品”。
4.2 三大 QoS 等级详解
Kubernetes 中有三个 QoS 等级,从高到低依次是:Guaranteed
、Burstable
、BestEffort
。
4.2.1 Guaranteed (最高优先级)
这是 K8s 提供的最高级别的服务保障,适用于数据库、消息队列等绝对不能被杀死的关键应用。
- 达成条件:
- Pod 中的每一个容器都必须同时设置了 CPU 和 Memory 的
requests
和limits
。 - 对于每一个容器,其 CPU 和 Memory 的
requests
值必须等于limits
值。
- Pod 中的每一个容器都必须同时设置了 CPU 和 Memory 的
- 待遇:这类 Pod 的驱逐优先级最低。只有当系统资源耗尽,且没有
Burstable
或BestEffort
类型的 Pod 可供驱逐时,才会考虑驱逐Guaranteed
类型的 Pod。
4.2.2 Burstable (中等优先级)
这是最常见的一种 QoS 类型,适用于大多数普通应用,允许在需要时“爆发”使用超过其请求的资源,但又不超过限制。
- 达成条件:
- Pod 不满足
Guaranteed
的条件。 - Pod 中至少有一个容器设置了 CPU 或 Memory 的
requests
。
- Pod 不满足
- 典型场景:
requests
<limits
。 - 待遇:当节点资源紧张时,这类 Pod 会在所有
BestEffort
类型的 Pod 被驱逐后,才会被考虑驱逐。
4.2.3 BestEffort (最低优先级)
这类 Pod 没有任何资源保证,K8s 会尽力而为地为它们提供资源,通常用于不重要的、容错性高的任务,如临时任务、批处理作业等。
- 达成条件:Pod 中没有任何一个容器设置了 CPU 或 Memory 的
requests
或limits
。 - 待遇:它们是节点资源压力下的首要驱逐对象。一旦资源不足,它们会第一个被“干掉”。
4.3 QoS 等级总结与对比
QoS 等级 | 达成条件 | 驱逐优先级 | 适用场景 |
---|---|---|---|
Guaranteed | 所有容器都设置了 requests 和 limits ,且两者相等。 | 最低 (最后被驱逐) | 核心数据库、消息队列等关键有状态服务 |
Burstable | 至少有一个容器设置了 requests ,但不满足 Guaranteed 条件。 | 中等 | 普通无状态 Web 应用、API 服务 |
BestEffort | 任何容器都没有设置 requests 或 limits 。 | 最高 (最先被驱逐) | 测试任务、一次性 Job、非关键后台作业 |
4.4 如何查看 Pod 的 QoS 等级
kubectl describe pod
的输出中,会直接显示 Pod 的 QoS 等级。
kubectl describe pod resource-demo-pod
输出中会包含一行:
QoS Class: Burstable
五、最佳实践与常见问题
5.1 如何设定合理的 Requests 和 Limits?
这是 K8s 运维中最具挑战性的问题之一。设定不当会导致资源浪费或应用不稳定。
- 黄金原则:基于监控数据,而非猜测。
- 实施步骤:
- 初始阶段:为应用设置一个相对宽松的
limits
和一个较小的requests
,让其在测试环境中运行。 - 监控观察:使用 Prometheus、Grafana 等监控工具,收集应用在不同负载(包括峰值)下的实际 CPU 和内存使用数据。
- 迭代优化:根据监控到的数据,逐步调整
requests
和limits
。requests
通常可以设置为应用在平均负载下的资源使用量。limits
应设置为应用在峰值负载下所需的最大资源量,并留出一些缓冲空间。
- 初始阶段:为应用设置一个相对宽松的
- 高级工具:可以考虑使用
Vertical Pod Autoscaler (VPA)
,它可以根据历史使用情况自动为 Pod 推荐甚至设置requests
和limits
。
5.2 常见问题 (FAQ)
(1) 问题一:只设置 limits
不设置 requests
会怎样?
如果只为容器设置了 limits
而没有设置 requests
,Kubernetes 会自动将 requests
的值设置为与 limits
相等。因此,这个 Pod 的 QoS 等级将是 Guaranteed
(前提是 CPU 和 Memory 都这样设置了)。
(2) 问题二:只设置 requests
不设置 limits
会怎样?
这种情况下,Pod 的 QoS 等级为 Burstable
。它的容器可以无限制地使用节点上的空闲资源,直到耗尽为止。这非常危险,因为它可能会影响到节点上的其他所有 Pod,是生产环境中应极力避免的配置。
(3) 问题三:我的 Pod 为什么一直是 Pending
状态?
最常见的原因之一就是集群中没有任何一个节点有足够的空闲资源来满足该 Pod 的 requests
。通过 kubectl describe pod <pod-name>
查看 Events
部分,通常会看到类似 FailedScheduling
的事件,并说明原因,如 0/3 nodes are available: 3 Insufficient cpu
。
(4) 问题四:我的 Pod 为什么被 OOMKilled
?
这意味着你的容器实际使用的内存超过了其 memory.limits
。你需要检查应用是否存在内存泄漏,或者你设置的内存限制对于当前的工作负载来说过低,需要调高 limits.memory
的值。
六、总结
对 Kubernetes 资源请求 (Requests) 与限制 (Limits) 的理解和熟练运用,是从入门走向专业的关键一步。它直接关系到集群的稳定性、资源利用率和应用性能。
本文的核心要点可以总结如下:
- 1. 功能定位:
requests
主要用于调度决策和资源保证,是 Pod 的“最低消费”;limits
则用于运行时控制,是 Pod 消耗资源的“天花板”。 - 2. 核心区别:
requests
影响 Pod 能否被调度到某个节点上;limits
决定 Pod 在运行时最多能使用多少资源。 - 3. 超限后果:CPU 使用超过
limit
会被节流 (Throttled),性能下降但不会被杀死;Memory 使用超过limit
会被终止 (OOMKilled)。 - 4. QoS 等级:
requests
和limits
的不同组合决定了 Pod 的 QoS 等级(Guaranteed
、Burstable
、BestEffort
),这直接影响 Pod 在节点资源紧张时的被驱逐优先级。 - 5. 实践原则:资源值的设定应基于实际监控数据进行科学评估和迭代调整,而非凭空猜测,这是确保集群稳定和高资源利用率的根本。
在下一篇文章《K8s 的“调度艺术” (下) - 高级调度策略》中,我们将继续探索如何通过亲和性、污点与容忍等更高级的手段,实现对 Pod 落点的精细化控制。