在 Kubernetes 集群中,“服务高可用” 从来不是单一维度的问题。即使应用配置了完美的健康检查、自动扩缩容和容错策略,一旦节点因资源分配不当 “宕机”,所有部署在该节点上的服务都可能受到波及。
想象这样一个场景:某公司的 Kubernetes 集群同时承载了开发、测试和生产环境的业务。开发团队为了快速验证功能,创建了 10 个未限制资源的 Pod;测试团队为了模拟高并发,启动了大量占用 CPU 的压测容器;而生产环境的核心数据库因节点内存被占满,突然被 “OOM 杀死”—— 这就是典型的 “资源失控” 灾难。
Kubernetes 资源管理的核心目标,就是通过 **“预防” 和 “调控”** 避免这类灾难:
本章将深入解析 Kubernetes 资源管理的三大核心工具 ——ResourceQuota、LimitRange 和 QoS,带你从理论到实战,构建稳定、可控的集群资源体系。
在单管理员维护的集群中,资源分配通常是可控的 —— 管理员清楚集群总资源(如 100 核 CPU、512GB 内存),并能合理分配给各个应用。但在多团队共享的集群中,问题会变得复杂:
ResourceQuota(资源配额) 正是为解决这些问题而生:它为每个命名空间设定资源使用的 “总量上限”,包括 CPU、内存、Pod 数量、Service 数量等,确保单个命名空间的资源使用不超出集群承载能力。
举例来说,可为 “生产环境” 命名空间配置:
通过这种方式,既能保障生产环境有足够资源,又能避免资源浪费。
ResourceQuota 与其他 Kubernetes 资源一样,通过 YAML 文件定义。以下是一个典型的 ResourceQuota 配置及参数说明:
yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: resource-test # 资源配额名称
namespace: prod # 作用的命名空间(若不指定,默认作用于当前命名空间)
labels:
app: resourcequota
spec:
hard: # 硬限制(无法突破的上限)
pods: "50" # 最多创建50个Pod
requests.cpu: "16" # 所有Pod的CPU请求总量不超过16核
requests.memory: "64Gi" # 所有Pod的内存请求总量不超过64GB
limits.cpu: "32" # 所有Pod的CPU上限总量不超过32核
limits.memory: "128Gi" # 所有Pod的内存上限总量不超过128GB
configmaps: "20" # 最多创建20个ConfigMap
secrets: "20" # 最多创建20个Secret
services: "30" # 最多创建30个Service
services.loadbalancers: "5" # 最多创建5个LoadBalancer类型的Service
persistentvolumeclaims: "10" # 最多创建10个PVC
requests.storage: "100Gi" # 所有PVC的存储请求总量不超过100GB
核心参数说明:
pods
:限制命名空间内 Pod 的总数量(无论状态,包括 Running、Pending 等);requests.xxx
:所有 Pod 的 “初始资源请求”(requests)总和上限(xxx 可为 cpu、memory、storage);limits.xxx
:所有 Pod 的 “资源使用上限”(limits)总和上限;注意:ResourceQuota 仅作用于指定的命名空间,且仅对配置后创建的资源生效(已存在的资源不受影响)。
下面通过实战演示 ResourceQuota 的使用流程,以 “限制 PVC 数量不超过 1 个” 为例。
首先创建一个独立的命名空间(避免影响其他资源):
bash
[root@k8s-master ~]# kubectl create ns quota-example
namespace/quota-example created
创建quota-objects.yaml
,限制 PVC 数量上限为 1:
yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-quota-demo # 资源配额名称
namespace: quota-example # 作用的命名空间
spec:
hard:
persistentvolumeclaims: "1" # PVC数量上限为1
执行以下命令将配置应用到集群:
bash
[root@k8s-master ~]# kubectl create -f quota-objects.yaml
resourcequota/object-quota-demo created
通过kubectl get quota
查看配额信息:
bash
[root@k8s-master ~]# kubectl get quota object-quota-demo -n quota-example -o yaml
apiVersion: v1
kind: ResourceQuota
metadata:
creationTimestamp: "2023-08-19T08:10:19Z"
name: object-quota-demo
namespace: quota-example
spec:
hard:
persistentvolumeclaims: "1"
status:
hard:
persistentvolumeclaims: "1"
used:
persistentvolumeclaims: "0" # 当前使用量为0
创建第一个 PVC(pvc.yaml
):
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-quota-demo
spec:
storageClassName: manual # 存储类(需提前创建)
accessModes:
- ReadWriteOnce # 读写权限(单节点挂载)
resources:
requests:
storage: 3Gi # 请求3GB存储
创建 PVC 并查看配额状态:
bash
[root@k8s-master ~]# kubectl create -f pvc.yaml -n quota-example
persistentvolumeclaim/pvc-quota-demo created
# 再次查看配额:used变为1(已达到上限)
[root@k8s-master ~]# kubectl get quota object-quota-demo -n quota-example -o yaml
status:
hard:
persistentvolumeclaims: "1"
used:
persistentvolumeclaims: "1"
尝试创建第二个 PVC(pvc2.yaml
):
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-quota-demo2
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
创建时会提示 “超出配额”,无法创建:
bash
[root@k8s-master ~]# kubectl create -f pvc2.yaml -n quota-example
Error from server (Forbidden): error when creating "pvc2.yaml": persistentvolumeclaims "pvc-quota-demo2" is forbidden: exceeded quota: object-quota-demo, requested: persistentvolumeclaims=1, used: persistentvolumeclaims=1, limited: persistentvolumeclaims=1
测试完成后,删除资源避免占用集群空间:
bash
# 删除PVC
[root@k8s-master ~]# kubectl delete -f pvc.yaml -n quota-example
persistentvolumeclaim "pvc-quota-demo" deleted
# 删除命名空间(会自动删除命名空间内的所有资源)
[root@k8s-master ~]# kubectl delete ns quota-example
namespace "quota-example" deleted
kubectl edit quota
修改配额(需谨慎,避免突破集群总容量);ResourceQuota 解决了 “总量控制” 问题,但存在两个明显漏洞:
LimitRange(资源限制范围) 正是为填补这些漏洞而生:
简单来说:ResourceQuota 是 “总量天花板”,LimitRange 是 “单个资源的边界”。
若 Pod 未配置 requests 和 limits,LimitRange 会自动添加默认值。以下是配置示例:
创建limitrange01.yaml
,设置容器的默认资源参数:
yaml
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-mem-limit-range # 限制范围名称
spec:
limits:
- type: Container # 作用对象为容器
default: # 未指定limits时的默认上限
cpu: "1" # 默认CPU上限1核
memory: "512Mi" # 默认内存上限512MiB
defaultRequest: # 未指定requests时的默认请求
cpu: "500m" # 默认CPU请求0.5核(1核=1000m)
memory: "256Mi" # 默认内存请求256MiB
bash
[root@k8s-master ~]# kubectl create -f limitrange01.yaml
limitrange/cpu-mem-limit-range created
创建pod-demo.yaml
(不设置 requests 和 limits):
yaml
apiVersion: v1
kind: Pod
metadata:
name: default-cpu-demo
spec:
containers:
- name: default-cpu-demo-ctr
image: nginx # 未配置resources字段
创建 Pod 后,查看其资源配置:
bash
[root@k8s-master ~]# kubectl create -f pod-demo.yaml
pod/default-cpu-demo created
# 查看Pod详情(重点看resources字段)
[root@k8s-master ~]# kubectl get pod default-cpu-demo -o yaml
spec:
containers:
- name: default-cpu-demo-ctr
resources:
limits:
cpu: "1"
memory: "512Mi"
requests:
cpu: "500m"
memory: "256Mi" # 自动添加了默认值
可见,未配置资源的 Pod 已被自动添加 LimitRange 中定义的默认值。
除了默认值,LimitRange 还能限制单个资源的最大 / 最小值,避免资源独占。
创建limitrange02.yaml
,限制 CPU 和内存的范围:
yaml
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-min-max-demo-lr
spec:
limits:
- type: Container
max: # 最大限制
cpu: "800m" # CPU上限800m
memory: "1Gi" # 内存上限1Gi
min: # 最小限制
cpu: "200m" # CPU请求最小200m
memory: "500Mi" # 内存请求最小500Mi
创建一个内存请求为 500Mi 的 Pod(符合 min 要求):
yaml
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo-2
spec:
containers:
- name: constraints-mem-demo-2-ctr
image: nginx
resources:
limits:
memory: "500Mi"
requests:
memory: "500Mi"
创建成功;若将内存请求改为 400Mi(低于 min),则创建失败:
bash
Error from server (Forbidden): error when creating "pod-demo.yaml": pods "constraints-mem-demo-2" is forbidden: memory request 400Mi is below minimum 500Mi
LimitRange 不仅能限制容器,还能限制 PVC 的存储申请大小。
创建limitrange03.yaml
,限制 PVC 的存储范围:
yaml
apiVersion: v1
kind: LimitRange
metadata:
name: storage-limits
spec:
limits:
- type: PersistentVolumeClaim # 作用对象为PVC
max:
storage: "2Gi" # 最大存储申请2Gi
min:
storage: "1Gi" # 最小存储申请1Gi
创建一个申请 3Gi 存储的 PVC(超过 max):
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc-hostpath
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "3Gi"
创建失败,提示超出限制:
bash
Error from server (Forbidden): error when creating "pvc-hostpath.yaml": persistentvolumeclaims "mypvc-hostpath" is forbidden: maximum storage usage per PersistentVolumeClaim is 2Gi, but request is 3Gi
LimitRange 和 ResourceQuota 并非孤立存在,需协同使用才能实现完整的资源控制:
即使配置了 ResourceQuota 和 LimitRange,仍可能面临 “资源紧张”:节点内存使用率达 90%、CPU 持续 100%。此时 Kubernetes 会通过 “杀死 Pod” 释放资源,但 “杀谁” 直接影响业务稳定性 —— 若杀死核心数据库 Pod,后果将远大于杀死非核心的日志收集 Pod。
QoS(Quality of Service,服务质量) 解决的就是 “资源紧张时优先保谁” 的问题:通过为 Pod 设置 QoS 级别,Kubernetes 在资源不足时会按优先级决定 “杀死顺序”。
Kubernetes 定义了 3 种 QoS 级别,优先级从高到低为:Guaranteed > Burstable > BestEffort。
QoS 级别 | 定义 | 资源配置要求 | 资源紧张时的命运 |
---|---|---|---|
Guaranteed(保证级) | 最高优先级,优先存活 | 所有容器的 requests 与 limits 相等(如 requests.cpu=1 核,limits.cpu=1 核) | 最后被杀死(仅当其他级别 Pod 被杀死后仍资源不足时) |
Burstable(弹性级) | 中优先级 | 至少一个容器设置了 requests,且 requests < limits(如 requests.cpu=0.5 核,limits.cpu=1 核) | 先于 Guaranteed 被杀死,后于 BestEffort |
BestEffort(尽力而为级) | 最低优先级 | 所有容器均未设置 requests 和 limits | 最先被杀死 |
以下通过实战演示 3 种 QoS 级别的配置方法。
bash
[root@k8s-master ~]# kubectl create namespace qos-example
namespace/qos-example created
需满足 “所有容器的 requests 与 limits 相等”:
创建qos-pod.yaml
:
yaml
apiVersion: v1
kind: Pod
metadata:
name: qos-demo
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr
image: nginx:1.7.9
resources:
limits:
cpu: "700m" # limits与requests相等
memory: "200Mi"
requests:
cpu: "700m"
memory: "200Mi"
创建后查看 QoS 级别:
bash
[root@k8s-master ~]# kubectl create -f qos-pod.yaml
pod/qos-demo created
# 查看QoS字段(qosClass: Guaranteed)
[root@k8s-master ~]# kubectl get pod qos-demo -n qos-example -o yaml | grep qosClass
qosClass: Guaranteed
需满足 “至少一个容器有 requests,且 requests < limits”:
创建qos-pod-2.yaml
:
yaml
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-2
namespace: qos-example
spec:
containers:
- name: qos-demo-2-ctr
image: nginx:1.7.9
resources:
limits:
memory: "200Mi" # limits > requests
requests:
memory: "100Mi"
创建后查看 QoS 级别:
bash
[root@k8s-master ~]# kubectl create -f qos-pod-2.yaml
pod/qos-demo-2 created
# 查看QoS字段(qosClass: Burstable)
[root@k8s-master ~]# kubectl get pod qos-demo-2 -n qos-example -o yaml | grep qosClass
qosClass: Burstable
需满足 “所有容器均未设置 requests 和 limits”:
创建qos-pod-3.yaml
:
yaml
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-3
namespace: qos-example
spec:
containers:
- name: qos-demo-3-ctr
image: nginx:1.7.9
# 不配置resources字段
创建后查看 QoS 级别:
bash
[root@k8s-master ~]# kubectl create -f qos-pod-3.yaml
pod/qos-demo-3 created
# 查看QoS字段(qosClass: BestEffort)
[root@k8s-master ~]# kubectl get pod qos-demo-3 -n qos-example -o yaml | grep qosClass
qosClass: BestEffort
问题 | 原因 | 解决方案 |
---|---|---|
Pod 创建失败,提示 “超出 ResourceQuota” | 命名空间资源使用已达上限 | 1. 清理废弃资源(如无用 Pod、PVC);2. 临时提高配额(需评估集群容量) |
Pod 未配置资源,导致节点资源被占满 | 未配置 LimitRange,未限制未设置资源的 Pod | 为所有命名空间配置 LimitRange,设置默认 requests/limits |
核心 Pod 在资源紧张时被杀死 | 核心 Pod 未配置为 Guaranteed | 将核心 Pod 的 requests 与 limits 设为相等,确保 QoS 为 Guaranteed |
PVC 申请存储失败,提示 “超出 LimitRange” | 申请大小超出 PVC 的 max 限制 | 调整申请大小或修改 LimitRange 的 max 值(需确保不突破 ResourceQuota) |
Kubernetes 资源管理不是孤立的,需与其他功能协同:
只有将资源管理与这些功能结合,才能构建真正稳定、高效的 Kubernetes 集群。