LimitRange 是 Kubernetes 中用于限制单个 Namespace 内单个对象资源使用范围的策略对象。
它主要解决三个问题:
requests 和 limitslimit/request 比例它的作用范围是 Namespace 级别,不是集群级别。
Namespace
├── LimitRange:限制单个 Pod、Container、PVC
└── ResourceQuota:限制整个 Namespace 的资源总量二者通常配合使用:
| 对象 | 解决的问题 |
|---|---|
| LimitRange | 一个容器最多、最少能申请多少资源,默认申请多少 |
| ResourceQuota | 一个 Namespace 总共能申请多少资源 |
| Pod Security Admission | Pod 是否允许使用特权、HostNetwork 等安全能力 |
| HPA/VPA | 根据负载自动调整副本数或资源配置 |
这是理解 LimitRange 的基础。
requests 表示容器正常运行时需要的资源量,主要用于调度。
例如:
resources:
含义是:
500m CPU 和 512Mi 内存 可分配空间的节点500m 表示半个 CPU:
1000m = 1 个 CPU 核
500m = 0.5 个 CPU 核
100m = 0.1 个 CPU 核limits 表示容器运行时可以使用的上限。
resources:
大致行为:
CPU 和内存的行为不同:
| 资源 | 超过 limit 后的主要行为 |
|---|---|
| CPU | CFS throttling,进程变慢 |
| Memory | OOMKill,容器可能重启 |
| ephemeral-storage | 可能触发驱逐 |
| GPU | 通常按整数设备分配 |
例如:
可以理解为:
正常调度需求:CPU 200m,内存 256Mi
运行时上限: CPU 1, 内存 512Mi在生产环境中,通常不能只看 limits,还要合理设置 requests。
一个典型的 LimitRange 如下:
各字段含义如下:
| 字段 | 含义 |
|---|---|
type | 限制对象类型 |
default | 未指定时自动注入的 limit |
defaultRequest | 未指定时自动注入的 request |
min | 允许申请的最小值 |
|
type 类型Container最常见的类型,用于限制 Namespace 中每个容器的资源。
注意:这里的限制是每个容器的限制,不是整个 Pod 的总和。
一个 Pod 里有两个容器,每个容器最多 2 CPU,那么整个 Pod 理论上可以申请 4 CPU。
Pod用于限制整个 Pod 的资源总量。
它限制的是 Pod 中所有容器资源的合计。
例如:
容器 A:CPU limit 4,内存 limit 4Gi
容器 B:CPU limit 4,内存 limit 4Gi
Pod 总量:CPU 8,内存 8Gi如果 Pod 总资源超过 Pod 类型的最大值,创建会被拒绝。
实践中常见配置是:
Container:控制单个容器Pod:防止多容器 Pod 总量过大PersistentVolumeClaim可以对 PVC 的存储申请设置最小值和最大值。
这样可以防止:
resources:
requests:
storage: "100Mi"这种过小的 PVC,也可以防止业务一次申请数十 TB 的存储。
假设 Namespace 中存在:
用户创建:
提交后,Pod 会被 Admission 阶段自动补充为近似:
查看实际结果:
kubectl get pod web -n demo -o yaml或者:
kubectl describe pod web -n demoLimitRange 不会自动修改已经存在的 Pod。
例如:
通常需要重新创建 Pod 才能应用新的默认值。
一个 Namespace 中可以存在多个 LimitRange,但不建议这样做。
不同对象的默认值可能产生不明确的组合效果。生产环境通常每个 Namespace 只维护一套清晰的资源策略。
LimitRange 在 Pod 创建或更新时进行校验和默认注入。它不是持续监控器,不会周期性扫描并修正已有 Pod。
min:
cpu: "50m"
memory: "64Mi"表示每个容器至少必须满足:
resources:
如果用户配置:
resources:
创建会被拒绝。
典型错误类似:
Minimum memory usage per Container is 64Mi, but request is 32Mimax:
cpu: "4"
memory: "8Gi"表示单个容器不能申请超过:
CPU:4 个核
内存:8Gi这可以防止普通开发者误提交:
resources:
maxLimitRequestRatiomaxLimitRequestRatio:
cpu: "10"
memory: "2"含义:
cpu limit / cpu request <= 10
memory limit / memory request <= 2例如:
比例是:
1 / 0.1 = 10因此合法。
但是:
比例约为:
1024 / 128 = 8如果最大比例为 2,则会被拒绝。
这个字段可以防止:
request 很小,但 limit 极大造成的调度和资源使用不一致。
LimitRange 会间接影响 Pod 的 QoS Class。
Pod 中每个容器都同时设置了 CPU 和内存的 request、limit,并且 request 等于 limit:
特点:
至少配置了部分资源,或者 request 小于 limit:
这是生产环境最常见的类型。
Pod 中没有任何容器配置资源请求和限制:
resources: {}特点:
LimitRange 的默认值通常可以避免大量 Pod 变成 BestEffort。
kubectl create namespace team-a应用:
kubectl apply -f limitrange.yaml查看:
kubectl get limitrange -n
整体效果:
LimitRange:
每个容器 request 至少 10m,最多 4 CPU
ResourceQuota:
整个 Namespace request.cpu 总量最多 20 CPU一个相对常见的生产模板:
这个配置表达了:
100m/256Mi 的 request1 CPU/1Gi8 CPU/16Gi16 CPU/32Gi但这些数值不能直接照搬,需要结合:
不要所有团队共用一个 Namespace 后使用一套粗粒度规则。
可以按照以下方式划分:
team-a-dev
team-a-staging
team-a-prod
team-b-prod每个 Namespace 使用不同的:
默认值过小:
默认值过大:
建议根据监控数据逐步调整,而不是一次性设置很大的默认值。
内存超过 limit 可能导致 OOMKill,因此应关注:
例如 Java 应用的容器内存 limit 不能简单等于 -Xmx,还要给 Metaspace、线程栈、Direct Buffer 等预留空间。
例如:
requests:
这可能导致:
生产环境可以用 maxLimitRequestRatio 限制这种情况。
一个业务 Pod 可能包含:
LimitRange 的 Container 限制会作用于每个容器,因此要确认 Sidecar 的默认资源不会被设置得不合理。
HPA 基于 CPU 或内存利用率进行扩缩容时,通常需要有对应的 requests。
例如 CPU 利用率常见计算方式接近:
实际 CPU 使用量 / CPU request如果 request 没有设置或被默认设置得过大,HPA 行为可能不符合预期。
建议推广顺序:
LimitRange 只能限制对象是否符合规则,不能替代完整的资源治理流程。
场景:开发者经常提交:
containers:
- name: app
image: example/app:v1结果:
BestEffort配置:
效果:
注意:默认值只是兜底,不代表适合所有业务。核心服务仍应显式配置资源。
场景:某个业务提交:
resources:
它可能导致:
配置:
效果:
单个容器不能超过 4 CPU 和 8Gi 内存如果确实需要更大的资源,可以放到专门的 Namespace,并设置更高的 LimitRange 和 ResourceQuota。
场景:
requests:
它允许容器调度时只占用很小的 request,但运行时可能突然使用大量 CPU。
配置:
maxLimitRequestRatio:
cpu: "10"
memory: "2"结果:
CPU limit 最多是 request 的 10 倍
内存 limit 最多是 request 的 2 倍这更适合资源竞争激烈的多租户集群。
场景:用户误创建:
resources:
requests:
storage: "100Ti"配置:
效果:
开发环境:
生产环境:
这样可以:
错误。
LimitRange 限制的是单个 Container、Pod 或 PVC。
Namespace 总资源上限要用:
kind: ResourceQuota它主要是在创建或更新时进行校验和默认注入。
它不会持续监控所有容器,也不会自动降低正在运行的进程资源使用。
CPU limit 可能造成 throttling。对于低延迟服务,CPU limit 设置过低会导致:
要结合 CPU throttling 指标判断,而不是只看容器是否正常运行。
不是。
真正的硬上限通常是 memory.limit。memory.request 主要影响调度和 QoS。
不会。
需要重建 Pod,或者通过 Deployment 发布新版本,使新的 Pod 重新经过 Admission 处理。
不建议盲目这样做。
最好明确设置:
default:
defaultRequest:否则在不同资源类型和 Kubernetes 版本行为下,可能得到不符合预期的 request/limit 关系。尤其在使用 HPA、ResourceQuota 和多租户资源治理时,显式配置更容易审计。
查看 Namespace 中的 LimitRange:
kubectl get limitrange -n production查看详细配置:
kubectl describe limitrange production-defaults -n production查看 Pod 最终资源配置:
kubectl get pod <pod-name> -n production -o yaml查看 Pod 的 QoS:
kubectl get pod <pod-nam
查看 Pod 资源汇总:
kubectl describe pod <pod-name> -n production查看容器实时使用量:
kubectl top pod <pod-name> -n production --containers查看 Namespace 配额:
kubectl get resourcequota -n production
kubectl describe当 Pod 创建失败时,重点查看:
比较稳妥的生产资源治理组合是:
最重要的原则是:
requests 决定调度和容量规划limits 决定运行时资源上限LimitRange 管单个对象ResourceQuota 管 Namespace 总量假设 Namespace 中有如下配置:
resources: {}最终通常会得到:
resources:
如果没有显式配置 request,Kubernetes 通常会把 limit 复制为 request:
这可能使 Pod 变成 Guaranteed QoS,前提是所有容器的 CPU 和内存都满足相应条件。
因此,开发者只写 limits,并不一定代表 Pod 会按照 Burstable 运行。
resources:
如果 LimitRange 设置了默认 limit,最终会补充默认 limit:
例如只写 CPU:
resources:
requests:
cpu: "100m"内存是否会被补充,取决于 LimitRange 中是否为内存定义了默认值。
如果配置了:
最终会近似为:
用户显式设置的资源值不会被默认值覆盖:
LimitRange 只会对缺失字段进行默认填充,并对最终结果进行校验。
二者经常同时使用,但职责不同。
例如:
如果 Namespace 中配置了 LimitRange:
那么一个完全没有资源配置的 Pod 被创建时:
例如:
20 个 Pod × 200m CPU = 4 CPU request
20 个 Pod × 1 CPU = 20 CPU limit可能出现如下结果:
requests.cpu 配额足够limits.cpu 配额刚好达到上限如果 ResourceQuota 只限制:
hard:
requests.cpu: "10"
requests.memory: "20Gi"而没有 LimitRange,用户创建未设置 request 的 Pod 时,可能收到类似错误:
must specify cpu,memory requests for: app因为 ResourceQuota 要求被统计的资源必须明确存在。
这也是为什么生产环境通常将:
LimitRange + ResourceQuota一起配置。
限制每个容器:
容器 A:最多 4 CPU、8Gi
容器 B:最多 4 CPU、8Gi两个容器总和可能达到:
CPU:8
内存:16Gi限制整个 Pod 的容器资源总和。
容器 A:CPU 4,内存 8Gi
容器 B:CPU 2,内存 4Gi
Pod 总量:CPU 6,内存 12Gi如果 Pod 内所有容器资源合计超过上限,Pod 会被拒绝。
Init Container 的调度资源计算并不是简单地与普通容器全部相加。
Pod 的有效资源通常按以下方式计算:
CPU 有效 request =
max(
所有 init container 中最大的 CPU request,
所有普通容器 CPU request 之和
)内存同理。
例如:
init container:CPU 2,内存 2Gi
业务容器 A:CPU 500m,内存 512Mi
业务容器 B:CPU 500m,内存 512Mi有效 request 近似为:
CPU:max(2, 0.5 + 0.5) = 2
内存:max(2Gi, 512Mi + 512Mi) = 2Gi但 LimitRange 对容器的最小值、最大值校验仍可能分别作用于 Init Container,因此不能通过设置超大的 Init Container 来绕过容器级别限制。
生产环境不建议所有工作负载使用完全相同的资源策略。
特点:
示例:
建议:
示例:
JVM 参数需要与容器限制配合:
-XX:MaxRAMPercentage=70不能简单地认为:
memory limit = -Xmx因为容器内存还包括:
如果 memory limit 为 2Gi,JVM 堆通常不能直接设置为 2Gi。
Go 应用通常需要关注:
示例:
如果内存 limit 设置过低,应用可能在流量峰值期间被 OOMKill。
批处理任务通常资源波动明显:
如果 Namespace 的 maxLimitRequestRatio 设置得很小,可能不适合这类突发型任务。
可以为批处理任务单独使用 Namespace:
online-prod
batch-prod分别设置不同的 LimitRange 和 ResourceQuota。
DaemonSet 会在每个符合条件的节点运行一个 Pod,因此需要特别谨慎:
每个节点 200m CPU
100 个节点 = 20 CPU request如果默认 request 较大,DaemonSet 的总资源占用会随着节点数量线性增加。
建议:
如果 Pod 自动注入 Sidecar,LimitRange 的默认值可能同时作用于:
例如默认每个容器:
requests:
cpu: "200m"
memory: "256Mi"一个带 Sidecar 的 Pod 仅默认 request 就可能达到:
CPU:400m
内存:512Mi如果还有日志容器,实际 request 会继续增加。
生产环境需要明确:
HPA 使用 CPU 或内存指标时,通常需要资源 request 作为利用率计算基准。
例如:
CPU 利用率 = 实际 CPU 使用量 / CPU request如果:
requests:
cpu: "100m"容器实际使用:
200m利用率约为:
200m / 100m = 200%如果 LimitRange 默认把 CPU request 设置为 1,相同的实际使用量:
200m / 1 = 20%HPA 的扩容行为可能完全不同。
因此,默认 request 不是随便填的,它会直接影响自动扩缩容。
VPA 可以根据历史使用情况推荐或调整 requests/limits。
典型流程:
需要注意:
常见做法是:
HPA 管副本数
VPA 管资源规格但需要根据实际场景设计,避免同时让二者基于同一个指标做互相影响的调整。
LimitRange 本身不会直接决定驱逐顺序,但它会影响 Pod 的 QoS 分类,进而影响节点资源紧张时的行为。
一般来说,节点内存压力下:
BestEffort 优先被驱逐
Burstable 次之
Guaranteed 相对更晚但实际驱逐还会考虑:
需要注意,Guaranteed 不是绝对不会被驱逐。节点资源严重不足、系统级资源不足或触发其他保护机制时,Guaranteed Pod 仍可能受到影响。
合法示例:
cpu: "100m"
cpu: "1"
cpu: "2.5"常见错误:
cpu: "1000" # 代表 1000 个 CPU,不是 1 个 CPU正确写法:
cpu: "1000m"常见写法:
二进制单位:
Ki、Mi、Gi、Ti十进制单位:
K、M、G、T生产环境一般建议统一使用:
Mi、Gi例如:
memory: "512Mi"比下面这种写法更容易统一理解:
memory: "500M"如果配置:
maxLimitRequestRatio:
memory: "2"则:
requests:
比例是:
1024Mi / 512Mi = 2合法。
kubectl get limitrange -n demo -o yaml这可以查看服务端准入处理后的对象,适合确认默认资源是否被注入。
执行:
kubectl apply -f too-small.yaml如果低于 LimitRange 的 min,API Server 会拒绝请求。
如果超过 max,会创建失败。
如果配置:
maxLimitRequestRatio:
cpu: "10"那么:
4 / 0.01 = 400超过最大比例,Pod 会被拒绝。
LimitRange 一般放在 Namespace 初始化流程中,而不是临时手工创建。
例如可以使用以下顺序:
1. 创建 Namespace
2. 创建 LimitRange
3. 创建 ResourceQuota
4. 创建 RBAC
5. 创建 NetworkPolicy
6. 允许业务部署这样可以避免先创建大量没有资源配置的工作负载,再补策略。
在 GitOps 场景中,建议:
namespace/
namespace.yaml
limitrange.yaml
resourcequota.yaml
rbac.yaml
networkpolicy.yaml由 Argo CD、Flux 或其他发布系统统一管理。
LimitRange 很有用,但不能解决所有资源治理问题。
它不能直接完成以下事情:
对应的能力通常需要:
ResourceQuota:Namespace 总量
HPA:副本自动扩缩
VPA:资源建议或自动调整
Cluster Autoscaler:节点数量调整
Admission Webhook/Policy Engine:复杂组织策略
Prometheus:监控和分析这里的 CPU 利用率基于:
实际 CPU 使用量 / CPU request因此 requests.cpu: 250m 是 HPA 正确工作的关键输入之一。
重点查看:
至少可以区分:
在线服务
批处理任务
定时任务
消息消费者
默认值用于处理遗漏资源配置的工作负载,但应避免过大。
最小值防止配置过低,最大值防止单个工作负载失控。
以下场景适合配置 maxLimitRequestRatio:
突发型批处理任务则可能需要更高比例,或者单独使用 Namespace。
只设置 LimitRange 而不设置 ResourceQuota,仍然可能出现某个 Namespace 创建大量 Pod 的情况。
重点验证:
资源参数不是一次性配置。上线后应根据实际运行数据调整。
可以用一句话区分几个概念:
LimitRange 管单个对象的资源边界和默认值;
ResourceQuota 管 Namespace 的资源总量;
requests 管调度和容量规划;
limits 管容器运行时上限;
HPA/VPA 根据负载或历史数据进行调整。在生产环境中,推荐把 LimitRange 作为 Namespace 的基础资源治理策略,至少覆盖:
默认 requests/limits
单容器最小值
单容器最大值
limit/request 比例
必要时的 Pod 总资源限制
必要时的 PVC 存储大小限制但关键业务仍应显式声明资源,不能完全依赖默认值。默认值是治理兜底,监控数据和压测结果才是最终确定资源规格的依据。 还有。前面主要覆盖了基础概念和常规用法,下面补充一些更偏生产治理、容易被忽略的内容。
除了 CPU、内存和 PVC,LimitRange 还可以限制容器的临时存储:
这里的临时存储包括:
emptyDir例如应用将大量日志写到容器文件系统中,可能超过:
limits:
ephemeral-storage: "2Gi"然后触发节点磁盘压力或 Pod 驱逐。
业务容器可以显式声明:
生产环境中,临时存储治理经常被忽略,但磁盘打满后可能影响整个节点。
emptyDir 也要纳入资源规划例如:
volumes:
- name: cache
emptyDir: {}如果没有资源限制,应用可能持续写入大量缓存。
可以设置:
同时配置容器的临时存储限制:
需要理解二者的区别:
| 配置 | 作用 |
|---|---|
emptyDir.sizeLimit | 限制某个 emptyDir 卷的大小 |
ephemeral-storage limit | 限制容器相关临时存储总量 |
二者最好同时考虑。
Init Container 也属于 Container 类型资源对象。
例如:
如果 LimitRange 设置了默认值,默认值也可能被应用到 Init Container。
这可能造成两个问题:
尤其是下面这类 Init Container:
它们的资源峰值可能显著高于主业务容器,因此建议显式配置,而不要完全依赖默认值。
GPU 一般属于扩展资源,例如:
resources:
limits:
nvidia.com/gpu: 1LimitRange 可以参与资源边界校验,但 GPU 的完整治理通常需要配合:
例如限制 Namespace 的 GPU 总量:
GPU 场景中通常更关心:
Namespace 总共能使用多少张卡而不是只限制单个容器。
如果应用使用 HugePages:
需要注意:
这类工作负载一般应放入独立 Namespace,并使用专门的 ResourceQuota 和节点池。
虽然 Kubernetes 允许一个 Namespace 中存在多个 LimitRange,但生产环境不建议这样做。
原因包括:
推荐:
一个 Namespace
一个主要 LimitRange
一个主要 ResourceQuota如果开发、测试、生产需要不同策略,应该使用不同 Namespace,而不是在同一个 Namespace 中叠加多个 LimitRange。
这是一个很重要的治理边界。
假设配置:
用户不配置资源时,LimitRange 会自动补充默认值。
但如果你的组织要求开发者必须根据业务实际情况显式填写资源,那么 LimitRange 不是最合适的强制工具。
此时可以配合:
例如使用策略要求每个业务容器必须有资源声明:
resources.requests.cpu 必须存在
resources.requests.memory 必须存在
resources.limits.cpu 必须存在
resources.limits.memory 必须存在LimitRange 负责兜底,策略引擎负责强制规范,二者职责不同。
较新的 Kubernetes 版本支持基于 CEL 的 ValidatingAdmissionPolicy。
例如可以实现一些 LimitRange 不擅长的规则:
生产 Namespace 必须设置资源
CPU limit 不得超过 4
内存 limit 必须大于等于 request
某些镜像必须使用资源配置
DaemonSet 必须显式声明资源LimitRange 适合通用资源边界:
min / max / default / ratioValidatingAdmissionPolicy 适合组织规则:
谁、在什么 Namespace、以什么方式提交什么对象假设节点上剩余资源:
CPU:500m
内存:1GiLimitRange 默认给每个容器注入:
requests:
cpu: "1"
memory: "2Gi"那么即使应用实际只使用:
CPU:50m
内存:100MiPod 也可能无法调度,因为 Scheduler 依据的是 request,而不是实时使用量。
因此默认值过大时,常见现象是:
Pod 一直 Pending
Insufficient cpu
Insufficient memory排查:
kubectl describe pod <pod-name> -n <namespace>重点看:
FailedScheduling
Insufficient cpu
Insufficient memoryCPU limit 不是越小越安全。
例如:
requests:
应用在高峰期需要 1 CPU,但最多只能使用 200m,可能出现:
需要监控 CPU throttling,例如关注:
container_cpu_cfs_throttled_seconds_total
container_cpu_cfs_throttled_periods_total
container_cpu_cfs_periods_total生产策略不能只看:
Pod 有没有 OOM还要看:
CPU 是否被持续 throttling对于延迟敏感服务,有时会采用:
requests:
甚至在特定场景下不设置 CPU limit,但这需要结合:
不能一概而论。
当容器 OOM 时,可以查看:
kubectl describe pod <pod-name> -n <namespace>关注:
Last State: Terminated
Reason: OOMKilled
Exit Code: 137同时查看:
kubectl get pod <pod-name> 并结合:
container_memory_working_set_bytescontainer_memory_usage_bytesLimitRange 只能限制上限,不能告诉你合理上限是多少。合理值仍然需要根据运行数据和压测结果确定。
例如原配置:
default:
memory: "512Mi"后来修改为:
default:
memory: "1Gi"已经运行的 Pod 不会自动变化。
Deployment 的 PodTemplate 也不会因为 LimitRange 变化而自动生成新 Pod。需要:
kubectl rollout restart deployment/api -n production或者修改 Deployment 模板触发滚动更新:
kubectl apply -f deployment.yaml生产变更时应注意:
假设 Deployment:
旧副本数:10
滚动更新 maxSurge:25%更新期间可能短暂存在:
10 个旧 Pod + 3 个新 Pod如果 Namespace 配额只够 10 个 Pod,滚动更新可能卡住:
exceeded quota因此生产环境需要同时考虑:
replicasmaxSurgemaxUnavailable例如配额很紧时,可以降低:
strategy:
但这会降低发布速度,需要在发布可靠性和资源余量之间平衡。
如果使用 RuntimeClass 或 Service Mesh,Pod 可能存在额外的 Pod overhead。
例如:
spec:
runtimeClassName: kataRuntimeClass 可以定义:
overhead:
这部分 overhead 会影响调度和资源计算。
因此对于以下场景:
不能只查看业务容器资源,还要核对 Pod 总资源和运行时额外开销。
当 Pod 因 LimitRange 创建失败时,按这个顺序检查:
重点确认:
minmaxlimit/request 是否超过比例maxSurge 超配额查看服务端默认注入结果:
kubectl create --dry-run=server -o yaml -f pod.yaml这个命令对确认最终对象非常有用。
比较成熟的做法可以分成四层:
解决:
单容器、单 Pod、单 PVC 的边界和默认值解决:
Namespace 总资源量和对象数量解决:
组织级规范、命名规则、资源声明要求、镜像来源解决:
实际使用量、容量预测、资源推荐、异常告警可以抽象为:
LimitRange:单个对象能申请多少
ResourceQuota:一个团队总共能申请多少
Policy:什么样的对象允许提交
Monitoring:实际用了多少
VPA/HPA:如何根据数据调整上线 LimitRange 前,建议确认:
最实用的结论是:
LimitRange 不是“给容器加个 CPU 和内存上限”这么简单。
它是 Namespace 级别的资源准入规则,会影响默认资源、
调度结果、QoS、HPA、ResourceQuota、滚动发布和节点稳定性。生产环境中,建议将它作为 Namespace 初始化模板的一部分,并与 ResourceQuota、Admission Policy、监控和资源分析一起使用。
有。前面已经覆盖了大部分内容,下面补充一些更容易被忽略的边界、设计建议和生产实践。
LimitRange 限制的是 Pod 创建时声明的资源值,不等于实际运行时一定被完全隔离。
例如:
它能保证:
100m CPU 评估1但它不能保证:
100m因此资源治理还需要关注:
CPU、内存、临时存储、PID、网络连接、文件描述符、磁盘 I/O其中有些资源不由 LimitRange 直接管理。
Linux 节点上,如果容器创建了大量进程,可能耗尽节点 PID。
Pod 可以设置:
spec:
securityContext:
pidsLimit: 512具体能力取决于 Kubernetes 版本、容器运行时和节点配置。
这和 LimitRange 是不同层面的能力:
LimitRange:CPU、内存等资源申请边界
pidsLimit:单个 Pod 的进程数量边界对于以下应用尤其需要关注:
例如:
default:
cpu: "1"
memory: "1Gi"这不代表每个应用都应该配置 1 CPU 和 1Gi 内存。
它只是意味着:
当用户未声明资源时,系统使用这个兜底值如果一个 Namespace 中有 100 个未配置资源的 Pod,那么它们可能默认产生:
CPU limit:100
内存 limit:100Gi如果同时配置了:
defaultRequest:
cpu: "200m"
memory: "256Mi"则调度 request 可能是:
CPU request:20
内存 request:25Gi因此默认值会直接影响:
默认值必须基于该 Namespace 的主要业务类型设置。
下面这种设计通常不理想:
所有团队
所有环境
所有业务类型
共用一个 LimitRange原因是:
更合理的划分方式是:
team-a-dev
team-a-prod
team-b-prod
batch-prod
data-prod
gpu-prod每个 Namespace 结合业务类型定义策略。
数据库、消息队列、缓存等工作负载通常需要显式资源:
原因包括:
对于有状态服务,建议:
显式声明资源
使用独立 Namespace
配置专用 ResourceQuota
结合节点标签和 taint
避免完全依赖默认值容器资源只是外部边界,应用内部通常还有自己的资源配置。
例如:
-Xmx
-XX:MaxRAMPercentage
-XX:MaxDirectMemorySizeworker_processes
worker_connectionsheap size
page cache
segment 配置buffer pool
shared buffers
cache size如果应用内部配置明显高于容器 limit,结果通常是 OOM 或频繁抖动。
如果应用内部配置远低于容器 limit,则可能造成资源浪费。
所以应建立关系:
应用内部资源配置 < 容器 limit
容器 request 反映稳定运行所需资源
容器 limit 覆盖合理峰值和运行时开销limit 不一定应该始终设置CPU limit 是否设置,需要结合工作负载判断。
一种常见策略是:
也就是:
但这并不是通用最佳实践。多租户集群需要谨慎评估,避免某个工作负载长期抢占 CPU。
LimitRange 的基本行为比较稳定,但实际资源使用和限制效果还受以下因素影响:
尤其是以下行为要在实际集群验证:
不要只根据 YAML 推断最终运行效果,应结合节点和容器运行时验证。
可以把业务划分为资源等级:
然后通过不同 Namespace 或资源池承载:
app-small
app-medium
app-large这比在一个 Namespace 中让所有团队自由申请更容易进行容量规划。
LimitRange 管资源大小,PriorityClass 管调度优先级。
例如:
然后在 Pod 中使用:
spec:
priorityClassName: production-critical但需要注意:
高优先级不代表可以无限申请资源仍然需要:
PodDisruptionBudget 不限制资源,但会影响滚动发布、节点维护和驱逐。
例如:
资源策略和 PDB 需要一起评估:
LimitRange:单个 Pod 用多少资源
ResourceQuota:Namespace 总共能用多少资源
PDB:同时允许多少 Pod 被主动中断
Deployment:发布时创建多少新 Pod如果配额过紧、PDB 又过于严格,可能出现:
生产环境建议将以下内容放在版本控制中:
修改 LimitRange 时需要记录:
特别是修改 defaultRequest,可能导致新 Pod 的调度需求突然增加。
推荐流程:
重点指标包括:
下面是一套偏严格的示例:
这套配置适合用作参考,但不能直接复制到所有生产环境。尤其需要根据以下因素调整:
可以从以下问题检查:
如果这些问题都能回答清楚,LimitRange 的设计通常就比较成熟了。
最终可以把 Kubernetes 资源治理理解为:
所以,LimitRange 是资源治理的基础设施,但不是完整的资源管理系统。生产环境真正可靠的方案,必须把它和配额、准入策略、调度、扩缩容、监控以及应用自身的资源配置结合起来。 还有一些最后值得补充的高级细节。到这里,LimitRange 的核心内容已经基本完整,下面主要是容易误判的边界和落地检查点。
LimitRange 只支持特定类型:
type: Container
type: Pod
type: PersistentVolumeClaim它不能直接限制:
这些需要使用 ResourceQuota,例如:
LimitRange 的作用对象是 Namespace 中的资源对象,不会根据提交者区分规则。
也就是说,同一个 Namespace 中:
开发人员 A
开发人员 B
CI/CD ServiceAccount
管理员默认都受到同一套 LimitRange 约束。
如果不同团队需要不同资源边界,常见方法是:
不同 Namespace而不是在同一个 Namespace 中使用多套 LimitRange。
如果必须根据用户、标签或镜像来源执行差异化规则,需要使用:
例如一个 Deployment 原来是:
replicas: 3后来扩容到:
replicas: 100LimitRange 仍然只检查单个 Pod 的资源边界,不会阻止副本数变成 100。
这时真正发挥作用的是:
kind: ResourceQuota例如:
如果扩容后超过配额,新 Pod 会无法创建,但已有 Pod 不会被自动删除。
假设:
replicas: 10同时 Namespace 只有足够运行 5 个 Pod 的配额,最终可能出现:
期望副本数:10
实际运行副本数:5Deployment 会持续尝试创建剩余 Pod,但 API Server 会因为 ResourceQuota 拒绝。
需要检查:
典型现象包括:
exceeded quota因此,ResourceQuota 应当按照:
最大副本数
滚动更新 maxSurge
Job 并发数
临时任务一起规划。
例如:
spec:
parallelism: 20
completions: 100如果每个 Job Pod 都有:
requests:
cpu: "500m"
memory: "1Gi"并发运行时可能需要:
CPU:10
内存:20Gi如果 CronJob 频繁创建且历史任务未清理,还可能耗尽:
应配合:
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
concurrencyPolicy并合理设置:
activeDeadlineSeconds
ttlSecondsAfterFinishedLimitRange 只负责 Job Pod 的单对象资源边界,不能替代任务并发治理。
即使所有业务 Pod 都配置了合理的 requests,节点仍需要为系统组件预留资源。
节点资源需要考虑:
相关配置包括:
kubeReserved
systemReserved
evictionHard
evictionSoft如果只通过 LimitRange 管业务 Pod,而没有节点预留,可能出现:
业务 Pod 看起来没有超过配额
节点却发生内存压力或磁盘压力资源治理至少要分为:
Namespace 级别
Pod 级别
Node 级别
Cluster 级别如果:
所有 Pod 的 requests 总和 < 节点容量只能说明调度层面认为资源足够。
实际使用量可能:
所有 Pod 的实际使用量 > 节点容量这就是典型的 overcommit 场景。
例如:
节点 CPU:16
所有 Pod CPU request 总和:12
所有 Pod CPU limit 总和:40这里可能是有意超卖,但要关注:
LimitRange 可以通过 maxLimitRequestRatio 限制超卖比例,但不能决定整个集群应该采用多大超卖率。
CPU 超卖通常表现为:
变慢
排队
throttling
延迟升高内存超卖则可能表现为:
OOMKill
Pod 重启
节点驱逐
系统服务异常因此生产环境通常对内存更加保守:
maxLimitRequestRatio:
cpu: "10"
memory: "2"而不是对 CPU 和内存使用完全相同的比例。
对于关键服务,可以考虑:
requests:
让内存 request 和 limit 相等,减少节点内存压力下的不确定性。
一个 Pod 的资源配置可能包括:
业务容器
Sidecar
Init Container
调试容器
日志容器
安全 Agent查看 Pod 总体配置:
排查资源异常时,不能只看主业务容器。
常见问题是:
业务容器 request:100m
Sidecar request:500m最后 Pod 实际 request 远大于开发者预期。
修改以下字段都可能影响后续发布:
default
defaultRequest
min
max
maxLimitRequestRatio建议先在测试 Namespace 验证:
kubectl apply --dry-run=server -f limitrange.yaml然后对典型工作负载执行:
kubectl create --dry-run=server \
-f deployment.yaml \
检查:
尤其要注意:放宽 max 通常只影响新创建或更新的 Pod,不会自动修改已有 Pod。
如果新策略导致生产发布失败,可以先恢复 LimitRange:
kubectl apply -f limitrange-previous.yaml但需要注意:
因此回滚时还要检查:
可以用下面这张表做最终记忆:
| 需求 | 使用对象 |
|---|---|
| 给未配置资源的容器设置默认值 | LimitRange |
| 限制单个容器最大 CPU/内存 | LimitRange |
| 限制单个 Pod 总资源 | LimitRange |
| 限制 PVC 单次申请大小 | LimitRange |
| 限制临时存储 | LimitRange |
| 限制 Namespace 总 CPU/内存 | ResourceQuota |
| 限制 Pod、Service、PVC 数量 | ResourceQuota |
| 强制资源字段必须显式填写 | Admission Policy |
| 根据运行数据调整资源 | VPA |
| 根据负载调整副本数 | HPA |
| 根据节点容量调整节点数 | Cluster Autoscaler |
| 调度优先级和抢占 | PriorityClass |
| 主动中断保护 | PodDisruptionBudget |
| 运行状态和容量分析 | Metrics/Prometheus |
最简洁的结论是:
LimitRange 是 Namespace 内的单对象资源准入策略。
它负责默认值、最小值、最大值和比例约束,
不负责 Namespace 总量、不负责动态调节,也不负责持续监控。生产环境推荐组合:
至此,LimitRange 从概念、字段、默认规则、调度关系、配额关系、工作负载差异、故障排查到生产治理边界,已经覆盖完整。
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"apiVersion: v1
kind: LimitRange
metadata:
name: resource-policy
namespace: production
spec:
limits:
- type: Container
default:
cpu: "1"
memory: "1Gi"
defaultRequest:
cpu: "100m"
memory: "256Mi"
min:
cpu: "10m"
memory: "16Mi"
max:
cpu: "4"
memory: "8Gi"
maxLimitRequestRatio:
cpu: "10"
memory: "2"| 允许申请的最大值 |
maxLimitRequestRatio | limit/request 允许的最大比例 |
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
min:
cpu: "10m"
memory: "32Mi"
max:
cpu: "2"
memory: "4Gi"apiVersion: v1
kind: LimitRange
metadata:
name: pod-resource-policy
namespace: production
spec:
limits:
- type: Pod
max:
cpu: "8"
memory: "16Gi"
min:
cpu: "10m"
memory: "32Mi"apiVersion: v1
kind: LimitRange
metadata:
name: pvc-storage-policy
namespace: production
spec:
limits:
- type: PersistentVolumeClaim
min:
storage: "1Gi"
max:
storage: "1Ti"apiVersion: v1
kind: LimitRange
metadata:
name: default-resources
namespace: demo
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"apiVersion: v1
kind: Pod
metadata:
name: web
namespace: demo
spec:
containers:
- name: web
image: nginxresources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"resources:
requests:
cpu: "100m"
limits:
cpu: "1"resources:
requests:
memory: "128Mi"
limits:
memory: "1Gi"resources:
requests:
cpu: "1"
memory: "512Mi"
limits:
cpu: "1"
memory: "512Mi"resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"apiVersion: v1
kind: LimitRange
metadata:
name: team-a-container-limits
namespace: team-a
spec:
limits:
- type: Container
default:
cpu: "1"
memory: "1Gi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
min:
cpu: "10m"
memory: "32Mi"
max:
cpu: "4"
memory: "8Gi"
maxLimitRequestRatio:
cpu: "10"
memory: "4"apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "20"
requests.memory: "40Gi"
limits.cpu: "40"
limits.memory: "80Gi"
pods: "50"
requests.storage: "500Gi"apiVersion: v1
kind: LimitRange
metadata:
name: production-defaults
namespace: production
spec:
limits:
- type: Container
default:
cpu: "1"
memory: "1Gi"
defaultRequest:
cpu: "100m"
memory: "256Mi"
min:
cpu: "10m"
memory: "64Mi"
max:
cpu: "8"
memory: "16Gi"
maxLimitRequestRatio:
cpu: "10"
memory: "4"
- type: Pod
max:
cpu: "16"
memory: "32Gi"spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"spec:
limits:
- type: Container
max:
cpu: "4"
memory: "8Gi"spec:
limits:
- type: PersistentVolumeClaim
min:
storage: "10Gi"
max:
storage: "2Ti"default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "50m"
memory: "64Mi"
max:
cpu: "2"
memory: "2Gi"default:
cpu: "1"
memory: "1Gi"
defaultRequest:
cpu: "200m"
memory: "256Mi"
max:
cpu: "8"
memory: "16Gi"kubectl describe pod <pod-name> -n production
kubectl get events -n production --sort-by=.lastTimestampLimitRange
├── 设置默认 requests/limits
├── 限制单容器最小值
├── 限制单容器最大值
└── 限制 limit/request 比例
ResourceQuota
├── 限制 Namespace 总 CPU/内存
├── 限制 Pod 数量
├── 限制 PVC 数量和存储容量
└── 限制 requests/limits 总量
HPA/VPA
├── 通过运行数据调整资源或副本数
└── 避免长期依赖拍脑袋配置
监控与治理
├── CPU throttling
├── OOMKill
├── 内存工作集
├── 调度失败
├── Namespace 配额使用率
└── Pod 驱逐apiVersion: v1
kind: LimitRange
metadata:
name: default-resources
namespace: demo
spec:
limits:
- type: Container
default:
cpu: "1"
memory: "512Mi"
defaultRequest:
cpu: "200m"
memory: "256Mi"resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"resources:
requests:
cpu: "1"
memory: "512Mi"
limits:
cpu: "1"
memory: "512Mi"resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"default:
cpu: "1"
memory: "512Mi"
defaultRequest:
cpu: "200m"
memory: "256Mi"resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"apiVersion: v1
kind: ResourceQuota
metadata:
name: quota
namespace: demo
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
pods: "20"defaultRequest:
cpu: "200m"
memory: "256Mi"
default:
cpu: "1"
memory: "512Mi"- type: Container
max:
cpu: "4"
memory: "8Gi"- type: Pod
max:
cpu: "6"
memory: "12Gi"resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "1"
memory: "512Mi"resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "4"
memory: "8Gi"memory: "128Mi"
memory: "1Gi"
memory: "512M"
memory: "2G"kubectl create -f pod.yaml \
--namespace demo \
--dry-run=server \
-o yamlapiVersion: v1
kind: Pod
metadata:
name: too-small
spec:
containers:
- name: app
image: nginx
resources:
requests:
cpu: "1m"
memory: "1Mi"resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "32"
memory: "64Gi"resources:
requests:
cpu: "10m"
limits:
cpu: "4"apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- type: Container
defaultRequest:
cpu: "200m"
memory: "256Mi"
default:
cpu: "1"
memory: "1Gi"
min:
cpu: "10m"
memory: "64Mi"
max:
cpu: "8"
memory: "16Gi"
maxLimitRequestRatio:
cpu: "10"
memory: "4"
- type: Pod
max:
cpu: "16"
memory: "32Gi"
- type: PersistentVolumeClaim
min:
storage: "1Gi"
max:
storage: "2Ti"apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "100"
requests.memory: "200Gi"
limits.cpu: "200"
limits.memory: "400Gi"
pods: "200"
persistentvolumeclaims: "100"
requests.storage: "20Ti"apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: example/api:v1.2.0
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70apiVersion: v1
kind: LimitRange
metadata:
name: ephemeral-storage-policy
namespace: production
spec:
limits:
- type: Container
default:
ephemeral-storage: "2Gi"
defaultRequest:
ephemeral-storage: "512Mi"
min:
ephemeral-storage: "100Mi"
max:
ephemeral-storage: "20Gi"resources:
requests:
ephemeral-storage: "512Mi"
limits:
ephemeral-storage: "2Gi"resources:
requests:
ephemeral-storage: "512Mi"
limits:
ephemeral-storage: "2Gi"spec:
initContainers:
- name: init
image: busybox
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
containers:
- name: app
image: nginxapiVersion: v1
kind: ResourceQuota
metadata:
name: gpu-quota
namespace: ai
spec:
hard:
requests.nvidia.com/gpu: "8"
limits.nvidia.com/gpu: "8"resources:
requests:
hugepages-2Mi: 512Mi
limits:
hugepages-2Mi: 512Midefault:
cpu: "1"
memory: "1Gi"
defaultRequest:
cpu: "200m"
memory: "256Mi"kubectl get limitrange -n <namespace> -o yaml
kubectl get resourcequota -n <namespace> -o yaml
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp[ ] 是否明确 Namespace 的业务边界
[ ] 是否定义 defaultRequest
[ ] 是否定义 default
[ ] 是否定义 min
[ ] 是否定义 max
[ ] 是否需要 maxLimitRequestRatio
[ ] 是否需要限制 Pod 总资源
[ ] 是否需要限制 PVC 大小
[ ] 是否需要限制 ephemeral-storage
[ ] 是否已经配置 ResourceQuota
[ ] 是否考虑 Sidecar 资源
[ ] 是否考虑 Init Container 资源
[ ] 是否评估 HPA 对 request 的依赖
[ ] 是否验证滚动更新时的配额余量
[ ] 是否在测试环境验证拒绝行为
[ ] 是否有 OOM、throttling、驱逐监控
[ ] 是否准备了回滚策略resources:
requests:
cpu: "100m"
limits:
cpu: "1"resources:
requests:
cpu: "2"
memory: "8Gi"
limits:
cpu: "4"
memory: "8Gi"resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
memory: "1Gi"defaultRequest:
cpu: "50m"
memory: "64Mi"
default:
cpu: "250m"
memory: "256Mi"
max:
cpu: "1"
memory: "1Gi"defaultRequest:
cpu: "200m"
memory: "256Mi"
default:
cpu: "1"
memory: "1Gi"
max:
cpu: "4"
memory: "8Gi"defaultRequest:
cpu: "1"
memory: "2Gi"
default:
cpu: "4"
memory: "8Gi"
max:
cpu: "16"
memory: "32Gi"apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: production-critical
value: 100000
globalDefault: false
description: "Critical production workloads"apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
namespace: production
spec:
minAvailable: 2
selector:
matchLabels:
app: apiNamespace
LimitRange
ResourceQuota
PriorityClass
NetworkPolicy
RBAC
HPA/VPA
PDB1. 在开发 Namespace 修改
2. 使用 dry-run 验证默认注入
3. 部署典型工作负载
4. 检查 HPA、QoS 和调度
5. 在预生产环境观察
6. 选择一个生产 Namespace 灰度
7. 检查拒绝率、Pending、OOM、throttling
8. 分批推广Pod 创建失败数
FailedScheduling 数量
OOMKilled 数量
CPU throttling
节点内存压力
Pod 驱逐
ResourceQuota 使用率
HPA 扩缩容次数
Deployment 发布失败apiVersion: v1
kind: LimitRange
metadata:
name: production-resource-policy
namespace: production
spec:
limits:
- type: Container
defaultRequest:
cpu: "250m"
memory: "256Mi"
ephemeral-storage: "256Mi"
default:
cpu: "1"
memory: "1Gi"
ephemeral-storage: "2Gi"
min:
cpu: "10m"
memory: "64Mi"
ephemeral-storage: "32Mi"
max:
cpu: "8"
memory: "16Gi"
ephemeral-storage: "20Gi"
maxLimitRequestRatio:
cpu: "8"
memory: "4"
ephemeral-storage: "8"
- type: Pod
max:
cpu: "16"
memory: "32Gi"
ephemeral-storage: "40Gi"
- type: PersistentVolumeClaim
min:
storage: "1Gi"
max:
storage: "2Ti"一个未配置资源的 Pod,默认值是否合理?
一个小容器,是否能申请过大的资源?
一个大容器,是否会被错误的默认值限制?
一个多容器 Pod,总量是否受到控制?
一个 Namespace,是否有总量配额?
一个 HPA,是否基于合理的 request?
一个 Sidecar,是否被算入总资源?
一个 Deployment,是否有滚动更新余量?
一个节点,是否能承受实际峰值?
一个业务 OOM 或 throttling 后,是否有诊断数据?apiVersion: v1
kind: ResourceQuota
metadata:
name: object-quota
namespace: production
spec:
hard:
pods: "200"
services: "50"
configmaps: "200"
secrets: "200"
persistentvolumeclaims: "100"
jobs.batch: "100"spec:
hard:
pods: "50"
requests.cpu: "20"
requests.memory: "40Gi"kubectl get deployment -n production
kubectl describe deployment api -n production
kubectl get rs -n production
kubectl get events -n productionkubectl get pod <pod-name> -n <namespace> -o jsonpath='
{range .spec.initContainers[*]}
init: {.name}{" request="}{.resources.requests}{" limit="}{.resources.limits}{"\n"}
{end}
{range .spec.containers[*]}
container: {.name}{" request="}{.resources.requests}{" limit="}{.resources.limits}{"\n"}
{end}'kubectl rollout status deployment/<name> -n <namespace>
kubectl get pods -n <namespace>
kubectl get events -n <namespace>Namespace
+ LimitRange
+ ResourceQuota
+ Admission Policy
+ HPA/VPA
+ PriorityClass
+ PDB
+ 监控告警
+ 版本化和灰度变更