Kubernets-资源管理
k8s集群中为了能够使系统正常稳定运行,通常会限制Pod的资源使用情况,在k8s集群中如果有一个程序出现异常,并占用大量的系统资源。如果未对该Pod进行资源限制的话,可能会影响其他的Pod。
k8s常见的资源管理方式:
计算资源管理(Compute Resources): 为Pod中的容器指定使用的计算资源(CPU和内存)。
资源的配置范围管理(LimitRange):可以对集群内Request和Limits的配置做一个全局的统一的限制,相当于批量设置了某一个范围内(某个命名空间)的Pod的资源使用限制。
资源的配额管理(Resource Quotas):可以为每一个命名空间(namespace)提供一个总体的资源使用限制,通过它可以限制命名空间中某个类型的对象的总数目上限,也可以设置命名空间中Pod可以使用到的计算资源的总上限。资源的配额管理有效解决了多用户或多个团队公用一个k8s集群时资源有效分配的问题。
ResourceQuota 资源配额
ResourceQuota 是 Kubernetes 中用于限制命名空间资源使用量的核心机制,它如同集群资源的"守门人",确保多租户环境下资源的公平分配与合理使用。本文将深入剖析 ResourceQuota 的工作原理、配置方法、高级特性以及最佳实践,帮助您全面掌握这一关键工具。
资源配额,通过 ResourceQuota 对象来定义,对每个命名空间的资源消耗总量提供限制。 它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命令空间中的 Pod 可以使用的计算资源的总上限。
- 不同的团队可以在不同的命名空间下工作,目前这是非约束性的,在未来的版本中可能会通过 ACL(Access Control List 访问控制列表) 来实现强制性约束。
- 集群管理员可以为每个命名空间创建一个或多个资源配额对象。
- 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会 跟踪集群的资源使用情况,以确保使用的资源用量不超过资源配额中定义的硬性资源限额。
- 如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN), 并在消息中给出有可能违反的约束。
- 如果命名空间下的计算资源 (如 cpu 和 memory)的配额被启用,则用户必须为 这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。 提示: 可使用LimitRanger 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。
ResourceQuota 核心概念与工作原理
什么是 ResourceQuota?
ResourceQuota 是 Kubernetes 提供的命名空间级资源配额管理机制,它通过定义硬性限制来:
- 限制命名空间中可使用的计算资源(CPU/内存)和存储资源总量
- 控制命名空间中特定类型对象(如 Pod、Service 等)的数量上限
典型应用场景包括:
- 多租户隔离:防止某个团队占用过多集群资源而影响其他团队
- 成本控制:在公有云环境中限制资源使用量以控制成本
- 稳定性保障:避免资源耗尽导致的集群不稳定
核心工作原理
ResourceQuota 通过以下机制实现资源管控:
- 命名空间隔离:不同团队工作在不同的命名空间中,通过 RBAC 实现访问控制
- 配额创建:管理员为每个命名空间创建 ResourceQuota 对象定义限制规则
- 准入控制:当用户创建资源时,API 服务器会检查是否违反配额限制
- 强制拒绝:如果请求超出配额,API 服务器返回 HTTP 403 Forbidden 错误
特殊要求:
- 对于 CPU 和内存资源,Pod 必须明确指定 requests 或 limits,否则创建会被拒绝
- 可使用 LimitRange 准入控制器为未设置资源需求的 Pod 提供默认值
ResourceQuota 的三种主要类型
计算资源配额
计算资源配额限制命名空间内可请求的计算资源总量,支持以下资源类型:
| 资源名称 | 描述 |
|---|---|
limits.cpu | 所有非终止状态 Pod 的 CPU 限制总和 |
limits.memory | 所有非终止状态 Pod 的内存限制总和 |
requests.cpu | 所有非终止状态 Pod 的 CPU 请求总和 |
requests.memory | 所有非终止状态 Pod 的内存请求总和 |
hugepages-<size> | 指定大小的巨页请求总数 |
配置示例:
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
requests.cpu: "1" # CPU请求总量不超过1核
requests.memory: 1Gi # 内存请求总量不超过1GB
limits.cpu: "2" # CPU限制总量不超过2核
limits.memory: 2Gi # 内存限制总量不超过2GB
hugepages-2Mi: "4Gi" # 2MB巨页请求不超过4GB存储资源配额
存储资源配额限制命名空间内的存储资源使用,包括持久化存储和临时存储:
| 资源名称 | 描述 |
|---|---|
requests.storage | 所有 PVC 的存储请求总和 |
persistentvolumeclaims | 允许的 PVC 总数 |
<storage-class>.storageclass.storage.k8s.io/requests.storage | 特定存储类的存储请求总和 |
requests.ephemeral-storage | 所有 Pod 的临时存储请求总和 |
多存储类配额示例:
apiVersion: v1
kind: ResourceQuota
metadata:
name: storage-resources
spec:
hard:
requests.storage: 100Gi # 所有存储类总量限制
gold.storageclass.storage.k8s.io/requests.storage: 50Gi # 黄金存储类限制
bronze.storageclass.storage.k8s.io/requests.storage: 10Gi # 青铜存储类限制
persistentvolumeclaims: "20" # PVC总数限制对象数量配额
对象数量配额限制命名空间中特定类型 Kubernetes 对象的数量,语法格式为:
- 核心组资源:
count/<resource>(如count/pods) - 非核心组资源:
count/<resource>.<group>(如count/deployments.apps)
常见可限制对象:
count/pods- 非终止状态的 Pod 数量count/services- Service 数量count/secrets- Secret 数量count/configmaps- ConfigMap 数量count/deployments.apps- Deployment 数量
配置示例:
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
count/pods: "50" # 最多50个Pod
count/services: "10" # 最多10个Service
count/secrets: "20" # 最多20个Secret
count/deployments.apps: "5" # 最多5个DeploymentResourceQuota 特性
配额作用域(Scopes)
ResourceQuota 可以设置作用域,只有匹配作用域的资源才会被计入配额。支持的作用域包括:
| 作用域 | 描述 | 跟踪的资源 |
|---|---|---|
Terminating | 匹配设置了 activeDeadlineSeconds 的 Pod | pods |
NotTerminating | 匹配未设置 activeDeadlineSeconds 的 Pod | pods, cpu, memory 等 |
BestEffort | 匹配 QoS 为 BestEffort 的 Pod | pods |
NotBestEffort | 匹配 QoS 不为 BestEffort 的 Pod | pods, cpu, memory 等 |
PriorityClass | 匹配特定优先级的 Pod | pods, cpu, memory 等 |
作用域使用规则:
- 不能在同一配额中同时设置
Terminating和NotTerminating - 不能在同一配额中同时设置
BestEffort和NotBestEffort
作用域选择器示例:
apiVersion: v1
kind: ResourceQuota
metadata:
name: scope-selector
spec:
hard:
pods: "10"
cpu: "1"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["high"] # 仅对优先级为high的Pod生效基于优先级的资源配额
从 Kubernetes 1.17 开始稳定支持基于 Pod 优先级的配额控制,允许为不同优先级的 Pod 分配不同的资源量:
apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["high"] # 仅限制高优先级Pod这种机制特别适合确保关键业务应用能获得所需资源,同时限制低优先级应用的资源使用。
配额与 LimitRange 的协同工作
ResourceQuota 通常与 LimitRange 配合使用,形成完整的资源管控体系:
- ResourceQuota:控制命名空间资源总量
- LimitRange:为单个容器/Pod 设置:
- 默认资源请求和限制
- 最小/最大资源限制
- 存储请求大小限制
典型工作流程:
- 管理员创建命名空间
- 设置 ResourceQuota 定义命名空间资源上限
- 设置 LimitRange 定义单个资源的默认值和限制范围
- 用户创建资源时:
- 未设置资源需求时使用 LimitRange 默认值
- 所有资源需求总和不能超过 ResourceQuota 限制
ResourceQuota 案例
基础配置步骤
步骤1:创建测试命名空间
kubectl create ns quota-demo步骤2:创建计算资源配额
# compute-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: quota-demo
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
pods: "5"kubectl apply -f compute-quota.yaml步骤3:验证配额状态
kubectl get quota -n quota-demo
kubectl describe quota compute-quota -n quota-demo输出示例:
Name: compute-quota
Namespace: quota-demo
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 5
requests.cpu 0 1
requests.memory 0 1Gi配额限制验证案例
案例1:创建合规 Pod
# pod-valid.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-valid
namespace: quota-demo
spec:
containers:
- name: nginx
image: nginx:1.19
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"kubectl apply -f pod-valid.yaml # 成功创建案例2:创建超出配额的 Pod
# pod-invalid.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-invalid
namespace: quota-demo
spec:
containers:
- name: nginx
image: nginx:1.19
resources:
requests:
cpu: "1.5" # 超过requests.cpu配额(1)
memory: "512Mi"
limits:
cpu: "2"
memory: "1Gi"kubectl apply -f pod-invalid.yaml预期错误:
Error from server (Forbidden): error when creating "pod-invalid.yaml": pods "pod-invalid" is forbidden: exceeded quota: compute-quota, requested: requests.cpu=1.5, used: requests.cpu=0.5, limited: requests.cpu=1对象数量配额验证
创建对象数量配额:
# object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
namespace: quota-demo
spec:
hard:
count/pods: "3"
count/services: "2"
count/secrets: "5"kubectl apply -f object-counts.yaml测试创建多个 Pod:
kubectl create deployment nginx --image=nginx:1.19 -n quota-demo --replicas=5由于 Pod 数量限制为3,只有3个 Pod 能成功运行:
kubectl get pods -n quota-demo输出:
NAME READY STATUS RESTARTS AGE
nginx-6799fc88d8-4bn6x 1/1 Running 0 15s
nginx-6799fc88d8-8wq5k 1/1 Running 0 15s
nginx-6799fc88d8-kx9g7 1/1 Running 0 15sesourceQuota 常用命令
# 查看指定命名空间的所有 ResourceQuota
kubectl get resourcequotas -n <namespace>
# 查看所有命名空间的 ResourceQuota
kubectl get resourcequotas --all-namespaces
# 使用缩写形式
kubectl get quota -n <namespace>
# 查看特定 ResourceQuota 的详细配置
kubectl describe resourcequota <quota-name> -n <namespace>
# 示例:查看 dev 命名空间中 compute-quota 的详情
kubectl describe resourcequota compute-quota -n dev
# 删除指定的 ResourceQuota
kubectl delete resourcequota <quota-name> -n <namespace>
# 通过 YAML 文件删除
kubectl delete -f quota.yaml -n <namespace>LimitRange
LimitRange 是 Kubernetes 中用于精细控制命名空间内资源分配的核心机制,它如同资源分配的"精密调节器",能够为容器和 Pod 设置默认资源值、定义资源使用范围,并确保资源配置的合理性。本文将系统性地介绍 LimitRange 的核心概念、工作原理、配置方法、使用场景以及最佳实践,帮助您全面掌握这一关键资源管理工具。
LimitRange 核心概念与价值
LimitRange 是什么?
LimitRange 是 Kubernetes 中的一种策略对象,用于约束命名空间内各种资源对象(如 Pod 和 PersistentVolumeClaim)的资源分配量。它主要提供以下关键功能:
- 设置默认值:为未指定资源需求的 Pod 或容器自动注入合理的资源请求(request)和限制(limit)值
- 定义资源范围:约束 Pod 或容器能够使用的资源最小值和最大值,防止配置不合理
- 控制比例关系:限制资源请求值与限制值之间的比例,避免资源分配失衡
- 存储限制:对 PersistentVolumeClaim 设置最小和最大存储空间限制
为什么需要 LimitRange?
在 Kubernetes 集群中,容器默认可以无限制地使用计算资源(CPU、内存等),这会导致一系列问题:
- 资源浪费:开发者可能忘记设置资源限制,导致容器占用过多资源
- 资源争用:单个 Pod 或容器可能独占节点资源,影响其他应用性能
- 调度不稳定:未设置资源请求的 Pod 可能导致节点资源超卖,引发随机驱逐
- 配置不一致:不同团队设置的资源值差异过大,难以统一管理
LimitRange 通过命名空间级别的资源约束,有效解决了这些问题,确保集群资源得到合理分配和使用。
LimitRange 与 ResourceQuota 的关系
LimitRange 和 ResourceQuota 都是 Kubernetes 的资源管理机制,但侧重点不同:
| 特性 | LimitRange | ResourceQuota |
|---|---|---|
| 作用对象 | 命名空间内的单个 Pod/容器/PVC | 整个命名空间的资源总量 |
| 控制粒度 | 精细控制(单个对象) | 宏观控制(命名空间总量) |
| 主要功能 | 设置默认值、定义范围、控制比例 | 限制命名空间资源使用上限 |
| 使用场景 | 确保单个资源配置合理 | 防止命名空间耗尽集群资源 |
| 互补性 | 通常与 ResourceQuota 配合使用 | 依赖 LimitRange 提供默认值 |
最佳实践是将两者结合使用:LimitRange 确保单个 Pod/容器的资源配置合理,ResourceQuota 确保命名空间不会耗尽集群资源。
LimitRange 工作原理
LimitRange 通过 Kubernetes 的准入控制机制实现资源约束,具体流程如下:
- 管理员创建 LimitRange:在命名空间中定义资源限制规则
- 用户创建资源对象:尝试创建 Pod/PVC 等资源
- 准入控制器介入:
- 如果对象未设置资源需求,注入默认值(default/defaultRequest)
- 验证显式设置的资源值是否符合 min/max 范围
- 检查 limit/request 比率是否超过 maxLimitRequestRatio
- 创建结果:
- 验证通过:创建资源对象
- 验证失败:返回 HTTP 403 错误,拒绝创建
LimitRange 核心配置详解
LimitRange 对象结构
一个完整的 LimitRange 配置包含以下主要部分:
apiVersion: v1
kind: LimitRange
metadata:
name: [LimitRange名称]
namespace: [命名空间名称]
spec:
limits:
- type: [限制类型] # Pod/Container/PersistentVolumeClaim
# 容器/Pod级别配置
min: # 资源最小值
cpu: "100m"
memory: "128Mi"
max: # 资源最大值
cpu: "1"
memory: "1Gi"
default: # 默认限制值
cpu: "500m"
memory: "512Mi"
defaultRequest: # 默认请求值
cpu: "250m"
memory: "256Mi"
maxLimitRequestRatio: # 限制与请求的最大比率
cpu: "2"
memory: "1.5"支持的限制类型
LimitRange 支持对三种类型的对象进行资源限制:
Container:针对 Pod 中的每个容器设置资源限制
- 控制单个容器的 CPU/内存 requests 和 limits
- 可设置默认值、最小/最大值、比例限制
Pod:针对整个 Pod 的资源总和设置限制
- 控制 Pod 中所有容器的 requests/limits 总和
- 仅支持设置 max 值(最大值限制)
PersistentVolumeClaim:针对存储声明设置限制
- 控制 PVC 的存储请求大小
- 可设置最小/最大存储容量
关键参数解析
min 和 max
min:指定资源请求(request)或限制(limit)的最小值
- 对于 CPU:通常以毫核为单位(如 "100m" 表示 0.1 核)
- 对于内存:通常以 MiB/GiB 为单位(如 "128Mi" 表示 128MB)
max:指定资源请求或限制的最大值
- 确保单个容器/Pod 不会占用过多资源
- 超过 max 的资源创建请求将被拒绝
示例:
min:
cpu: "100m"
memory: "128Mi"
max:
cpu: "1"
memory: "1Gi"default 和 defaultRequest
- default:当未指定资源限制(limits)时使用的默认限制值
- defaultRequest:当未指定资源请求(requests)时使用的默认请求值
这两个参数确保即使开发者忘记设置资源需求,容器也能获得合理的默认配置。
示例:
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "250m"
memory: "256Mi"maxLimitRequestRatio
- 定义资源限制与请求之间的最大允许比率
- 防止资源配置严重失衡(如 limit 远大于 request)
- 计算公式:
limit/request ≤ maxLimitRequestRatio
示例:
maxLimitRequestRatio:
cpu: "2" # CPU limit 最多是 request 的2倍
memory: "1.5" # 内存 limit 最多是 request 的1.5倍LimitRange 案例
未设置资源需求的 Pod
创建不指定任何资源需求的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: demo-limitrange-pod
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Never结果:
- LimitRange 会注入默认的 requests 和 limits
- 查看 Pod 配置可见自动添加的资源设置:yaml
resources: limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi
设置部分资源需求的 Pod
创建只设置 requests 的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: dmeo-limitrage
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Never
resources:
requests:
cpu: "180m"
memory: "180Mi"结果:
- requests 使用用户指定的值
- limits 使用 LimitRange 的默认值:yaml
resources: limits: # pod 资源未定义limits会使用LimitRange的default的值 cpu: 500m memory: 512Mi requests: cpu: 180m memory: 180Mi
设置 limits 但未设置 requests 的 Pod
创建只设置 limits 的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: limit-only-spec
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Never
resources:
limits:
cpu: "300m"
memory: "300Mi"结果:
- Kubernetes 会将 requests 设置为与 limits 相同的值:yaml
resources: limits: cpu: "300m" memory: "300Mi" requests: cpu: "300m" memory: "300Mi"
违反 min/max 限制的 Pod
尝试创建 requests 小于 min 的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: invalid-resource-spec
spec:
containers:
- name: nginx
image: nginx:1.19
resources:
limits:
cpu: "300m"
memory: "300Mi"
requests:
cpu: "80m" # 小于 min.cpu (100m)
memory: "80Mi" # 小于 min.memory (100Mi)结果:
- API 服务器返回 403 错误:
Error from server (Forbidden): error when creating "pod.yaml": pods "invalid-resource-spec" is forbidden: [minimum cpu usage per Container is 100m, but request is 80m, minimum memory usage per Container is 100Mi, but request is 80Mi]
多租户环境资源隔离
在多团队共享的 Kubernetes 集群中,LimitRange 可确保:
- 每个团队的命名空间有统一的资源标准
- 防止某个团队的应用配置异常影响其他团队
- 通过默认值降低配置门槛,减少人为错误
配置示例:
apiVersion: v1
kind: LimitRange
metadata:
name: team-a-limits
namespace: team-a
spec:
limits:
- type: Container
min:
cpu: "100m"
memory: "256Mi"
max:
cpu: "2"
memory: "4Gi"
default:
cpu: "500m"
memory: "1Gi"
defaultRequest:
cpu: "250m"
memory: "512Mi"关键应用资源保障
对于关键业务应用,可通过 LimitRange 确保:
- 设置较高的 min 值,防止资源不足
- 限制非关键应用的 max 值,避免资源争用
- 通过 maxLimitRequestRatio 防止过度超卖
生产环境示例:
apiVersion: v1
kind: LimitRange
metadata:
name: critical-app-limits
namespace: production
spec:
limits:
- type: Container
min: # 关键应用最小需求
cpu: "500m"
memory: "1Gi"
max:
cpu: "4"
memory: "8Gi"
defaultRequest:
cpu: "1"
memory: "2Gi"
maxLimitRequestRatio:
cpu: "1.5" # 严格限制超卖比例
memory: "1.2"存储资源限制
LimitRange 可对 PersistentVolumeClaim 进行约束:
- 防止申请过大存储造成浪费
- 确保存储请求满足最低要求
存储限制示例:
apiVersion: v1
kind: LimitRange
metadata:
name: storage-limits
spec:
limits:
- type: PersistentVolumeClaim
min:
storage: "1Gi" # 最小1GB
max:
storage: "50Gi" # 最大50GB与 ResourceQuota 的协同配置
典型的多层次资源管控方案:
LimitRange:确保单个 Pod/容器的资源配置合理
yaml# limitrange.yaml apiVersion: v1 kind: LimitRange metadata: name: default-limits spec: limits: - type: Container default: cpu: "500m" memory: "512Mi" defaultRequest: cpu: "250m" memory: "256Mi"ResourceQuota:限制命名空间资源总量
yaml# quota.yaml apiVersion: v1 kind: ResourceQuota metadata: name: team-quota spec: hard: requests.cpu: "10" requests.memory: "20Gi" limits.cpu: "20" limits.memory: "40Gi"工作流程:
- 开发者创建 Pod,未设置资源需求 → 使用 LimitRange 默认值
- 所有 Pod 的资源总和不能超过 ResourceQuota 限制
- 确保既有个体合理性,又有总量控制
LimitRange 管理命令
查看 LimitRange 列表:
bashkubectl get limitrange -n [命名空间]查看 LimitRange 详情:
bashkubectl describe limitrange [名称] -n [命名空间]创建 LimitRange:
bashkubectl apply -f limitrange.yaml删除 LimitRange:
bashkubectl delete limitrange [名称] -n [命名空间]
节点亲和性-NodeSelector
NodeSelector 核心概念
定义 NodeSelector 是 Kubernetes 中一种基于节点标签(Labels)的简单调度机制,允许用户通过键值对匹配将 Pod 强制调度到特定节点上。它通过 spec.nodeSelector 字段实现,仅支持完全匹配(精确的键值对)。
核心用途
- 资源隔离:将不同服务(如生产/测试环境)调度到不同节点组。
- 硬件约束:指定 Pod 运行在具备特定硬件(如 GPU、SSD)的节点上。
- 地理位置调度:在多区域集群中,选择低延迟的节点。
NodeSelector 工作原理
节点标签标记 管理员需先为节点打上标签,例如:
bashkubectl label nodes <node-name> disktype=ssdPod 配置匹配 Pod 的 YAML 中通过
nodeSelector指定标签,调度器会筛选出匹配的节点:yamlspec: nodeSelector: disktype: ssd # 仅调度到带有 disktype=ssd 标签的节点强制调度 若无匹配节点,Pod 将处于
Pending状态,直到符合条件的节点可用。
NodeSelector 案例
测试pod
资源清单
apiVersion: v1
kind: Pod
metadata:
name: nginx-ssd
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Never
nodeSelector:
disktype: ssd # 必须与节点标签完全匹配给节点添加标签
# node创建标签
kubectl label nodes k8s-node01 disktype=ssd
# 查看node标签
kubectl get node --show-labels多标签匹配
nodeSelector:
disktype: ssd
gpu: "true" # 同时满足多个标签的节点结合 Namespace 使用
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
namespace: production # 指定命名空间
spec:
nodeSelector:
env: prodNodeSelector 与相关调度策略对比
NodeSelector vs. NodeAffinity
| 特性 | NodeSelector | NodeAffinity |
|---|---|---|
| 匹配条件 | 仅完全匹配 | 支持 In、NotIn、Exists 等运算符 |
| 规则类型 | 硬性要求 | 支持硬性(required)和软性(preferred) |
| 多条件组合 | 仅 AND 逻辑 | 支持 AND/OR 逻辑 |
| 适用场景 | 简单调度需求 | 复杂调度策略(如多可用区、权重优先级) |
NodeSelector vs. NodeName
- NodeName:直接指定节点名称(跳过调度器),灵活性极低。
- NodeSelector:通过标签动态选择节点,更适合自动化管理。
节点亲和性-NodeAffinity
节点亲和性核心概念
节点亲和性(Node Affinity)是 Kubernetes 中比 NodeSelector 更高级的调度机制,它允许您通过复杂的逻辑表达式指定 Pod 应该(或不应该)调度到哪些节点上。
与 NodeSelector 的关键区别
| 特性 | NodeSelector | Node Affinity |
|---|---|---|
| 匹配逻辑 | 完全相等匹配 | 支持多种操作符(In, NotIn, Exists等) |
| 约束强度 | 硬性约束 | 支持软性(preferred)和硬性(required)约束 |
| 表达式复杂度 | 简单键值对 | 支持复杂逻辑表达式 |
| 多条件组合 | AND 逻辑 | 支持复杂组合逻辑 |
节点亲和性类型
requiredDuringSchedulingIgnoredDuringExecution (硬性要求)
- 调度时必须满足的条件
- 不满足则 Pod 保持 Pending 状态
- "IgnoredDuringExecution"表示 Pod 运行后节点标签变化不影响已调度 Pod
preferredDuringSchedulingIgnoredDuringExecution (软性偏好)
- 调度时优先考虑的条件
- 不满足仍可调度,但会影响调度评分
- 可设置权重(weight)表示偏好强度
节点亲和性实战案例解析
案例1:多区域部署(硬性要求)
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity: # 亲和性配置,包含节点亲和性和Pod亲和性/反亲和性
nodeAffinity: # 节点亲和性配置,定义Pod与节点的调度关系
requiredDuringSchedulingIgnoredDuringExecution: # 硬性调度要求(必须满足的条件)
# 注意:即使有多个nodeSelectorTerms,也只需满足其中一个即可(OR逻辑)
nodeSelectorTerms: # 节点选择条件列表(每个term内部是AND逻辑)
- matchExpressions: # 节点标签匹配表达式列表
- key: disktype # 要匹配的节点标签键
operator: In # 匹配操作符(In表示标签值在指定列表中)
values: # 允许的标签值列表(OR逻辑)
- ssd # 必须调度到disktype为ssd...
- antarctica-west1 # ...或antarctica-west1的节点上
# 注意:若找不到匹配节点,Pod将保持Pending状态
containers:
- name: with-node-affinity
image: nginx
imagePullPolicy: Never
# 注意:实际生产环境应设置resources.requests/limits确保调度稳定性配置解析:
- 必须调度到带有
topology.kubernetes.io/zone标签且值为antarctica-east1或antarctica-west1的节点 - 若无匹配节点,Pod 将保持 Pending 状态
- 使用场景:跨可用区部署保证高可用性
案例2:偏好特定节点标签(软性偏好)
apiVersion: v1
kind: Pod
metadata:
name: test-node-affinity
spec:
containers:
- name: test-node-affinity
image: nginx
# 注意:生产环境建议设置resources.requests/limits
affinity: # 亲和性配置
nodeAffinity: # 节点亲和性配置
preferredDuringSchedulingIgnoredDuringExecution: # 软性调度偏好(非强制要求)
# 注意:多个preference之间按weight权重竞争,不影响最终调度结果
- weight: 80 # 权重值(1-100),数值越大优先级越高
preference: # 偏好条件
matchExpressions: # 标签匹配规则
- key: app # 节点标签键
operator: In # 操作符(包含在values列表中)
values: # 期望的标签值
- web # 优先调度到app=web的节点(权重80)
- weight: 20 # 次要权重
preference:
matchExpressions:
- key: tier # 次级优先标签键
operator: In
values:
- frontend # 其次考虑tier=frontend的节点(权重20)
# 关键字段说明:
# 1. preferredDuringSchedulingIgnoredDuringExecution 表示:
# - preferredDuringScheduling: 调度时优先考虑(非强制)
# - IgnoredDuringExecution: Pod运行后节点标签变化不影响已调度Pod
#
# 2. weight 权重特点:
# - 相对值(80 vs 20表示4倍优先级差异)
# - 仅影响调度器评分,不保证绝对调度
# - 所有weight累加不需要等于100
#
# 3. 与requiredDuringScheduling的区别:
# - 若无满足preferred条件的节点,仍会调度到其他节点
# - 调度器会选择综合评分最高的节点
#
# 典型应用场景:
# - 优先但不强制使用SSD节点
# - 多区域部署时优先选择低延迟区域
# - 优先使用有GPU的节点(但非必须)
# 使用建议:
# 1. 先标记节点标签:
# kubectl label nodes <node1> app=web
# kubectl label nodes <node2> tier=frontend
#
# 2. 验证调度结果:
# kubectl get pod test-node-affinity -o wide
#
# 3. 查看调度详情:
# kubectl describe pod test-node-affinity | grep -A 10 Events
#
# 4. 生产环境建议配合使用:
# - requiredDuringScheduling(硬性要求)
# - podAntiAffinity(避免同类Pod集中)
# - resource requests/limits(资源保障)配置解析:
- 优先调度到有
app=web标签的节点(权重80) - 其次考虑有
tier=frontend标签的节点(权重20) - 若无匹配节点仍可调度到其他节点
- 使用场景:优化性能但不强制要求
案例3:组合硬性和软性条件
apiVersion: v1
kind: Pod
metadata:
name: combined-affinity
spec:
affinity: # 亲和性配置,包含节点亲和性和Pod亲和性/反亲和性
nodeAffinity: # 节点亲和性配置
# 硬性要求部分(必须满足的条件)
requiredDuringSchedulingIgnoredDuringExecution: # 调度时必须满足的条件
nodeSelectorTerms: # 节点选择条件列表
- matchExpressions: # 标签匹配表达式列表
- key: kubernetes.io/arch # 系统预定义的节点架构标签
operator: In # 操作符:包含在values列表中
values: # 允许的标签值
- amd64 # 必须运行在amd64架构的节点上
# 注意:若不满足此条件,Pod将保持Pending状态
# 软性偏好部分(优先考虑的条件)
preferredDuringSchedulingIgnoredDuringExecution: # 调度偏好(非强制)
- weight: 1 # 权重值(1-100),影响调度评分
preference: # 偏好条件
matchExpressions: # 标签匹配规则
- key: disktype # 自定义磁盘类型标签
operator: In # 操作符:包含在values列表中
values: # 期望的标签值
- ssd # 优先选择disktype=ssd的节点(但不强制)
# 注意:若无SSD节点,仍可调度到其他满足硬性条件的节点
containers:
- name: nginx
image: nginx
# 生产环境建议添加resources配置:
# resources:
# requests:
# cpu: "100m"
# memory: "128Mi"
# limits:
# cpu: "200m"
# memory: "256Mi"
# 关键字段说明:
# 1. requiredDuringSchedulingIgnoredDuringExecution:
# - 这是硬性约束,节点必须满足条件才能被调度
# - kubernetes.io/arch是Kubernetes自动添加的系统标签
# - 多个matchExpressions之间是AND关系
# 2. preferredDuringSchedulingIgnoredDuringExecution:
# - 这是软性偏好,调度器会优先考虑但不强制
# - weight值用于多个偏好之间的优先级比较
# - 即使没有满足偏好的节点,Pod仍会被调度
# 3. 组合使用策略:
# - 先用required保证基本运行条件(如架构、区域)
# - 再用preferred优化运行时性能(如SSD、GPU)
# 使用场景:
# - 必须运行在特定架构(如amd64)但优先使用高性能存储
# - 必须运行在特定区域但优先使用新型实例类型
# - 必须满足安全合规要求但优先使用资源充足的节点
# 操作建议:
# 1. 标记节点:
# kubectl label nodes <node-name> disktype=ssd
# kubectl get nodes --show-labels # 查看标签
# 2. 验证调度:
# kubectl apply -f pod.yaml
# kubectl get pod -o wide # 查看调度结果
# kubectl describe pod combined-affinity # 查看详细事件
# 3. 生产建议:
# - 配合ResourceQuota使用防止资源耗尽
# - 结合PodDisruptionBudget保证高可用
# - 通过NodeSelector简化简单场景的配置配置解析:
- 必须运行在 amd64 架构的节点上(硬性要求)
- 优先选择有 SSD 磁盘的节点(软性偏好)
- 使用场景:保证兼容性同时优化性能
节点亲和性操作符
节点亲和性支持多种匹配操作符:
| 操作符 | 描述 | 示例 |
|---|---|---|
In | 标签值在指定列表中 | values: ["web", "api"] |
NotIn | 标签值不在指定列表中 | values: ["test"] |
Exists | 标签必须存在(不检查值) | 不设置 values 字段 |
DoesNotExist | 标签必须不存在 | 不设置 values 字段 |
Gt | 标签值大于指定值(数字比较) | values: ["3"] (标签值 > 3) |
Lt | 标签值小于指定值(数字比较) | values: ["5"] (标签值 < 5) |
数字比较示例:
- key: gpu-count
operator: Gt
values: ["2"] # 选择 GPU 数量大于2的节点节点标记与管理命令
节点标签管理
# 查看节点标签
kubectl get nodes --show-labels
# 添加/更新标签
kubectl label nodes <node-name> <label-key>=<label-value>
# 示例:标记节点为 web 类型
kubectl label node k8s-worker01 app=web
# 删除标签
kubectl label nodes <node-name> <label-key>-验证调度结果
# 查看 Pod 调度到的节点
kubectl get pod <pod-name> -o wide
# 查看调度失败原因
kubectl describe pod <pod-name>
# 查看节点详情(包括标签)
kubectl describe node <node-name>Pod亲和
pod的亲和性主要用来解决pod可以和哪些pod部署在同一个集群里面,即拓扑域(由node组成的集群)里面;而pod的反亲和性是为了解决pod不能和哪些pod部署在一起的问题,二者都是为了解决pod之间部署问题。需要注意的是,Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度,不建议在具有几百个节点的集群中使用,而且Pod 反亲和需要对节点进行一致的标记,即集群中的每个节点必须具有适当的标签能够匹配 topologyKey。如果某些或所有节点缺少指定的topologyKey 标签,可能会导致意外行为。
Pod亲和性核心概念
基本定义与作用
Pod亲和性是一种调度策略,允许用户定义新Pod与现有Pod之间的部署关系,包括:
- 亲和性(Pod Affinity):使Pod倾向于与特定标签的Pod部署在同一拓扑域
- 反亲和性(Pod Anti-Affinity):使Pod避免与特定标签的Pod部署在同一拓扑域
与节点亲和性不同,Pod亲和性关注的是Pod-to-Pod的关系而非Pod-to-Node的关系这种机制主要用于:
- 实现服务间的紧密协同部署(如前端与缓存)
- 保证服务的高可用性(分散部署相同服务的多个副本)
- 优化网络通信性能(减少跨节点通信)
- 满足数据局部性需求(如计算与存储的协同定位)
拓扑域(Topology Key)概念
拓扑域是理解Pod亲和性的关键概念,它定义了调度决策的范围边界,通过节点标签来划分:
kubernetes.io/hostname:节点级拓扑域(最细粒度)failure-domain.beta.kubernetes.io/zone:可用区级拓扑域failure-domain.beta.kubernetes.io/region:区域级拓扑域- 自定义标签:如
rack、switch等物理拓扑标签
当使用topologyKey: "kubernetes.io/hostname"时,亲和性规则仅在单个节点范围内生效;而使用区域级标签时,规则会跨多个节点生效
Pod亲和性实现
硬性规则(Required)
测试pod
apiVersion: v1
kind: Pod
metadata:
name: demo-app-backend
labels:
app: backend
spec:
containers:
- name: demo-pod
image: nginx
imagePullPolicy: Never添加标签
# 查看demo-app-backend创建的节点位置
kubectl get pod
# 添加节点标签(拓扑)
kubectl label node k8s-node02 Region=bj节点亲和性
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app-redis
labels:
app: redis
spec:
replicas: 2
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
affinity:
# Pod亲和性规则
podAffinity:
# 强制性的调度规则
requiredDuringSchedulingIgnoredDuringExecution:
# pod 标签选择器
- labelSelector:
matchLabels:
app: backend
# 节点拓扑标签
topologyKey: Region
containers:
- name: redis
image: redis:alpine3.22
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
ports:
- containerPort: 6379
name: redis检测
# 查看Deployment是否创建在和demo-app-backend相同的节点
kubectl get pod -owide软性规则(Preferred)
# 偏好性的调度规则, 但不会影响已在节点上运行的Pod
preferredDuringSchedulingIgnoredDuringExecution:
# 权重范围: 1~100, 权重值越大, 优先级越高
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: "app"
operator: "In"
values: ["db"]
topologyKey: "kubernetes.io/hostname"优先但不强制满足条件,通过weight(1-100)表示优先级
Pod反亲和性实现
测试pod
apiVersion: v1
kind: Pod
metadata:
name: demo-app-backend
labels:
app: backend
spec:
containers:
- name: demo-pod
image: nginx
imagePullPolicy: Never添加标签
# 查看demo-app-backend创建的节点位置
kubectl get pod
# 添加节点标签(拓扑)
kubectl label node k8s-node02 Region=bj节点亲和性
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app-redis
labels:
app: redis
spec:
replicas: 2
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
affinity:
# Pod反亲和性规则
podAntiAffinity:
# 强制性的调度规则
requiredDuringSchedulingIgnoredDuringExecution:
# pod 标签选择器
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- backend
# 节点拓扑标签
topologyKey: Region
containers:
- name: redis
image: redis:alpine3.22
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
ports:
- containerPort: 6379
name: redis检测
# 查看Deployment是否创建在和demo-app-backend在不同的节点
kubectl get pod -owide污点与容忍
污点(Taints)与容忍(Tolerations)是Kubernetes调度系统中的核心机制,用于实现节点与Pod之间的"选择性匹配",为生产环境提供了精细化的调度控制能力。
如果node节点有多个污点的话,在pod中需要全部设置。
污点(Taints)
污点是节点(Node)上的属性,用于排斥不符合条件的Pod被调度到该节点。
污点组成
每个污点包含三个部分:
key: 污点的标识符value: 污点的值effect: 污点的效果,决定如何排斥Pod
污点命名规范
标准化前缀
使用
node-role.kubernetes.io/master作为键名,这是Kubernetes社区广泛认可的命名规范语义化值
reserved:表示节点为系统保留资源dedicated:表示专用节点(二选一)
效果选择
NoSchedule(生产首选)比NoExecute更温和,允许已有Pod继续运行
污点策略
| 策略 | 说明 |
|---|---|
NoSchedule | 不容忍该污点的Pod不会被调度到该节点 |
PreferNoSchedule | 尽量避免调度不容忍的Pod,但不是强制的 |
NoExecute | 不容忍的Pod不会被调度到该节点,且已运行的Pod会被驱逐 |
污点操作命令
添加污点
kubectl taint nodes <node-name> <key>=<value>:<effect>
# 示例:给master01添加dedicated专用污点
kubectl taint nodes k8s-master01 dedicated=master:NoSchedule查看污点
kubectl describe nodes <node-name> | grep Taints删除污点
kubectl taint nodes <node-name> <key>[:<effect>]-
# 示例:删除master01的dedicated污点
kubectl taint nodes k8s-master01 dedicated:NoSchedule-容忍(Tolerations)
容忍是Pod上的配置,允许(但不强制)Pod被调度到带有特定污点的节点上。
容忍字段说明
| 字段 | 说明 | 可选值 |
|---|---|---|
key | 要匹配的污点键 | 字符串 |
operator | 匹配操作符 | Exists(存在即可)或Equal(值相等) |
value | 要匹配的污点值 | 字符串 |
effect | 要匹配的污点效果 | NoSchedule, PreferNoSchedule, NoExecute |
tolerationSeconds | 仅对NoExecute有效,指定被驱逐前的等待时间 | 秒数 |
容忍配置
NoSchedule
apiVersion: v1
kind: Pod
metadata:
name: demo-app
spec:
containers:
- name: demo-pod
image: nginx
imagePullPolicy: IfNotPresent
# pod 容忍
tolerations:
- key: "dedicated"
operator: "Equal"
value: "master"
# 污点策略
effect: "NoSchedule"Exists
apiVersion: v1
kind: Pod
metadata:
name: demo-app
spec:
containers:
- name: demo-pod
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "dedicated"
operator: "Equal"
value: "master"
effect: "Exists"带延迟的NoExecute容忍
apiVersion: v1
kind: Pod
metadata:
name: demo-app
spec:
containers:
- name: demo-pod
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "dedicated"
operator: "Equal"
value: "master"
effect: "NoExecute"
tolerationSeconds: 3600 # 1小时后才被驱逐