K8s-kubernetes(二)资源限制-详细介绍
K8s如何合理规定对象资源使用
基本概念
- Kubernetes中,占用资源的最小单元为
单个Pod
- Kubernetes中,资源占用主要针对服务器的
CPU
、内存
为什么要做资源限制
- 对于Kubernetes集群而言,所有Pod都会占用K8s集群所在服务器的资源,如果不做资源控制,则很有可能出现某些Pod无限制占用资源(CPU、内存),导致系统崩溃
资源限制设置方式
Pod、Container级别控制
关键参数:request、limits
-
request参数
- controller做调度时,创建Pod的最低资源占用标准
-
limits参数
- 单个Pod在运行时的资源占用上限 –
真正限制资源可用到多少
- 当容器试图使用超过limits指定的CPU时会被 CFS 限流;试图使用超过limits指定的内存时会被 OOM Killer 杀掉并重启。
- 单个Pod在运行时的资源占用上限 –
使用示例
apiVersion: v1kind: Podmetadata:name: demo-podspec:containers:- name: appimage: nginx:latestresources: # k8s中定义资源规格的关键字,主要针对CPU和内存requests: # Pod最低的资源占用。调度器在将Pod指派给某个节点时,会检查该节点“可分配资源”是否满足request要求cpu: "100m" # 0.1 核memory: "128Mi" # 128 MBlimits: # Pod运行时的最大资源使用上限,cpu: "500m" # 0.5 核(上限)memory: "256Mi" # 256 MB(上限)
命名空间级别控制
关键策略对象:LimitRange
- 在命名空间级别,可以使用LimitRange给整个命名空间设置默认值/最大值
- LimitRange不仅仅是默认值的概念,也是一道硬性检查
- 默认值:如果 Pod 或容器未显式声明 requests 或 limits,LimitRange 会自动注入默认值
- 硬性检查:如果Pod或容器显式声明了request或者limits,但是不在 LimitRange的允许范围内,不允许创建Pod
使用示例
apiVersion: v1
kind: LimitRange #LimitRange类型对象
metadata:name: cpu-mem-limit #LimitRange对象名称namespace: dev #该策略适用的命名空间
spec: #定义策略具体规则limits: #limits为一个列表,可以包含多个限制策略- type: Container #表示该限制针对的是容器级别,而不是Pod或其他级别min: #指定容器资源的最小值,如果容器请求的资源低于这个值,K8s 会拒绝创建cpu: 100m #最少请求 0.1 个 CPU 核心memory: 128Mi #最少请求128M内存max: #超过这个值的容器会被拒绝创建cpu: 1 #最大请求1个CPU核心memory: 1Gi #最大请求1G内存default: #默认配置,当容器和Pod没有显式声明resources.limits,自动使用这里配置的默认值cpu: 500m #当容器和Pod没有显式声明resources.limits,默认resources.limits.cpu=500mmemory: 512Mi #当容器和Pod没有显式声明resources.limits,默认resources.limits.memory=512Mi defaultRequest: #默认配置,当容器和Pod没有显式声明resources.request,默认的requests数量,request: Pod最低的资源占用。调度器在将Pod指派给某个节点时,会检查该节点“可分配资源”是否满足request要求cpu: 200mmemory: 256MimaxLimitRequestRatio: #限制比例:限制与请求的最大比例,控制 limit/request 的最大比例。作用:防止用户设置过高的 limit 而请求很低的资源,防止节点资源被过度使用或者其他Pod的资源无法保证cpu: 2 # CPU的限制值不能超过请求值的2倍。如果请求是250M内存,则限制不能超过500M。如果超过这个比例,Pod 会被拒绝创建
命名空间/集群级别总量限制
关键对象:ResourceQuota
- ResourceQuota是一种命名空间级别的硬限制机制,作用是给每个命名空间设定资源总量红线
- 一旦配额用满,任何导致超配的对象创建都会被拒绝,包括通过Deployment、StatefulSet等控制器间接创建的Pod
ResourceQuota作用范围
- ResourceQuota控制的是集群节点级别的总量,还是命名空间的总量?
- ResourceQuota控制的是单个命名空间资源的总量
- 如果希望控制集群节点级别,需要多命名空间+ResourceQuota 或 集群级策略(如 ClusterPolicy、PodNodeSelector、多集群联邦)来实现
ResourceQuota和LimitRange有什么区别
- ResourceQuota限制的是整个命名空间资源的总量
- LimitRange限制的是这个命名空间内,单个资源的限制量和默认值
- 两者需要结合使用才能达到最佳效果
使用示例
- 确保准入控制器已启用
- 大多数发行版默认已包含 --enable-admission-plugins=ResourceQuota;若手动搭建,需在 kube-apiserver 启动参数里加入
- 编写YML并应用
apiVersion: v1
kind: ResourceQuota #类型为ResourceQuota
metadata:name: team-a-quota #名称namespace: team-a #作用的命名空间
spec:hard: #hard 是一个 map,key 是被限制的资源类型,value 是字符串形式的硬性上限requests.cpu: "20" #该命名空间内所有 非终止状态 Pod 的 spec.containers[*].resources.requests.cpu 之和 ≤ 20 CPU(= 20 核)requests.memory: 40Gi #所有 Pod 的 requests.memory 总和 ≤ 40 GiBlimits.cpu: "40" #所有 Pod 的 limits.cpu 总和 ≤ 40 核limits.memory: 80Gi #所有 Pod 的 limits.memory 总和 ≤ 80 GiBpods: "50" #命名空间里当前存在的 Pod 对象数量 ≤ 50 个(Running / Pending / Succeeded 都算,Failed 或 Completed 且 TTL 已过的不算)persistentvolumeclaims: "10" #PVC 对象总数 ≤ 10 个count/deployments.apps: "15" #apps/v1 组下的 Deployment 对象 ≤ 15 个
- 查看配额使用/剩余
kubectl describe quota <ResourceQuota名称> -n <命名空间>
引申问题1:LimitRange限制了容器最大使用资源,如果使用中超过这个限制,会发生什么
- 结论
- 最终表现是容器会被OOMKilled
- 原因
- LimitRange属于准入控制,即在Pod创建/更新时作限制校验,如果超出或低于限制要求,则不允许创建
- 当Pod创建完后,LimitRange任务结束,不再发挥作用
- 实际的运行时限制,是由cgroup 和 kubelet 负责,限制的方式也不是拒绝分配,而是直接杀掉
引申问题2:如果容器资源一旦超限就OOMKilled,如何保证应用稳定性?
- 预估
- 在配置上线前,充分压测评估出最大峰值
- 给足安全余量,一般要在压测峰值上再加20%-50%作为安全余量
- 观察
- 上线后持续观察,并设置预警措施
- 调优
- 发现不足就及时调大,并滚动升级
- 垂直扩容(加大limit限制值)
- 水平扩容(拆业务、分片、增加副本数,降低单实例负载)
- 应用层优化(减少缓存大小、调整GC参数、使用内存池、对象复用)**
- 兜底
- 保证即使有实例被OOMKilled,其余实例还可以承载流量
引申问题3:LimitRange 和 ResourceQuota 对已有 Pod 有什么影响
这是一个非常重要的问题,涉及 Kubernetes 中资源限制策略的生效范围和时效性。
✅ 1. LimitRange 对已有 Pod 的影响
- 不会影响已存在的 Pod。
LimitRange
只在 新创建的 Pod 或容器 时生效。- 它的作用是在 Pod 创建时:
- 自动补全
resources.requests
和resources.limits
。 - 验证资源是否在允许范围内。
- 自动补全
🔍 如果已有 Pod 的资源配置超过了 LimitRange
的 max 限制:
- 不会强制修改或终止这些 Pod。
- 它们会继续运行,直到被手动删除或更新。
- 只有在重新创建或更新 Pod 时,才会触发
LimitRange
的验证。
✅ 2. ResourceQuota 对已有 Pod 的影响
- 不会强制终止或修改已存在的 Pod。
ResourceQuota
是针对命名空间资源总量的限制。- 它在创建新资源时检查是否超过配额。
🔍 如果已有资源已经超过了配额限制:
- 不会影响这些资源的运行。
- 但无法再创建新的资源,直到资源使用量低于配额。
🧠 举个例子
假设你在 dev
命名空间中设置了如下配额:
limits.cpu: "4"
而已有 Pod 总共使用了 5
个 CPU:
- ✅ 已有 Pod 不会被删除或停止。
- ❌ 新 Pod 无法创建,除非已有 Pod 被删除或资源使用量降低。
📌 总结
特性 | LimitRange | ResourceQuota |
---|---|---|
是否影响已有 Pod | ❌ 不影响 | ❌ 不影响 |
是否影响新建 Pod | ✅ 生效 | ✅ 生效 |
是否强制修改已有资源 | ❌ 不会 | ❌ 不会 |
是否阻止新资源创建 | ✅(不符合规则) | ✅(超出配额) |
✅ 建议做法
- 在设置
LimitRange
和ResourceQuota
前,先评估当前命名空间资源使用情况。 - 使用
kubectl describe quota
和kubectl top pod
查看资源使用。 - 如果想让“老 Pod”也受新限制,只能人工或自动化地做:手动滚动重启 Deployment/StatefulSet → 新 Pod 走新规则。
- 配合策略引擎(如 Kyverno)实现更强的资源治理。
注意事项
- LimitRange 和 ResourceQuota设置前,已有存在的pod,这部分Pod不会不受影响
- 一个命名空间建议只创建一个
- 多租户集群,防止某个用户的 Pod 占用过多资源
- CICD环境,限制测试 Pod 的最大资源,防止资源争抢
- 为未声明资源的容器自动分配合理默认值,避免调度失败