污点 及 容忍度
污点介绍
taint,中文译作"污点"。taint是k8s中用于标记Node局限性的,它可让Pod与Node产生排斥性。
查看调度情况
文件 pod-alpine.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-alpine
namespace: default
labels:
app: myapp
spec:
restartPolicy: Always
containers:
- name: container-alpine
image: alpine:3.7
command: ["/bin/sh", "-c", "while true;do sleep 3600;done;"]操作
# 创建pod
kubectl apply -f pod-alpine.yaml
# 查看pod
kubectl get pod pod-alpine -o wide
# 查看node的taint
kubectl describe node <nodename> | grep Taints这意味着什么
master 节点带
NoSchedule污点:这是 Kubernetes 的标准做法,防止业务 Pod 跑到控制平面节点上。普通 Pod(没有对应 Toleration)不会调度到 master。node1 / node2 没有污点:任何 Pod 都可以调度到这两个节点上。
创建和删除Taint
创建节点Taint的格式为:
kubectl taint node <nodename> key=[value]:effect删除节点Taint的格式为:
kubectl taint node <nodename> key=[value]:effect-命令格式详解
添加污点
kubectl taint node <nodename> key=[value]:effecteffect 三种取值:
示例:
# 带 value 的
kubectl taint node node1 gpu=true:NoSchedule
# 不带 value 的(key 后面直接跟 :effect)
kubectl taint node node1 dedicated:NoSchedule删除污点
kubectl taint node <nodename> key=[value]:effect-关键就是末尾的 -,表示删除。删除时必须完整写对 key、value、effect,才能精确匹配删掉。
示例:
# 删除你 master 上的那个污点
kubectl taint node master node-role.kubernetes.io/master:NoSchedule-
# 删除带 value 的
kubectl taint node node1 gpu=true:NoSchedule-⚠️ 注意:
-要紧贴在effect后面,中间不能有空格。
实验要求
1.为node1定义污点: taint=:PreferNoSchedule
2.创建pod并查看实际调度的节点
3.为node2定义污点: taint=:NoSchedule
4.重复第2步骤
5.修改node1污点: taint=:NoExecute
6.清除2个节点的所有污点实验操作
1-
kubectl taint node node1 taint=:PreferNoSchedule
2-
kubectl apply -f pod-alpine.yaml
watch -n 1 kubectl get po pod-alpine -o wide
3-
kubectl taint node node2 taint=:NoSchedule
kubectl delete -f pod-alpine.yaml
4-
kubectl apply -f pod-alpine.yaml
5-
kubectl taint node node1 taint=:PreferNoSchedule-
kubectl taint node node1 taint=:NoExecute
6-
kubectl taint node node1 taint=:NoExecute- && kubectl taint node node2 taint=:NoSchedule-Taint与pod调度(定向调度)
通过诸如"nodeName"、"nodeSelector"、"affinity"等手段可以实现Pod的定向调度。定向调度代表Pod对节点的偏好,而taint代表着节点对Pod的偏好。当这两个设置出现冲突的时候,又是怎样的结果?
完整的对照表:
测试文件 pod-alpine.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-alpine
namespace: default
labels:
app: myapp
spec:
nodeName: node1 # 定向调度
restartPolicy: Always
containers:
- name: container-alpine
image: alpine:3.7
command: ["/bin/sh", "-c", "while true;do sleep 3600;done;"]操作(可以观察 pod 启动后分配 工作节点 及 状态 )
# 设置node1的taint
kubectl taint node node1 taint=:PreferNoSchedule
# 启动pod做测试(查看在那个工作节点启动)
kubectl apply -f pod-alpine.yaml
watch -n 1 kubectl get po pod-alpine -o wide
kubectl delete -f pod-alpine.yaml
# 换一个taint (NoSchedule)
kubectl taint node node1 taint=:PreferNoSchedule-
kubectl taint node node1 taint=:NoSchedule
kubectl apply -f pod-alpine.yaml
kubectl taint node node1 taint=:NoSchedule-
# 换最后一个taint (NoExecute)
kubectl delete -f pod-alpine.yaml
kubectl taint node node1 taint=:NoExecute
kubectl apply -f pod-alpine.yaml
kubectl taint node node1 taint=:NoExecute-容忍度
什么是Toleration toleration,中文译作"容忍”。与taint刚好相反,某些时候我们需要在有污点的节点上运行Pod,这种无视污点的调度方式称呼为容忍(即使节点存在污点,也能容忍下来,依旧让其运行Pod)。
容忍度匹配策略
精确匹配:
spec:
# 定义容忍策略
tolerations:
# Equal精确匹配,表示 key、value、effect必须写全
- operator: Equal
# 污点的键。如果设置成 key: "" 代表任意的键值对
key: taint
# 污点的值。
value: ""
# 污点的效果,如果设置成 effect: "" 代表所有策略
effect: NoSchedule模糊匹配:
spec:
# 定义容忍策略
tolerations:
# Exists模糊匹配,表示 key、value、effect满足其中之一即可
- operator: Exists
# 污点的键。如果设置成 key: "" 代表任意的键值对
key: taint
# 污点的效果,如果设置成 effect: "" 代表所有效果
effect: NoSchedule容忍度测试pod (pod-alpine.yaml)
apiVersion: v1
kind: Pod
metadata:
name: pod-alpine
namespace: default
labels:
app: myapp
spec:
# 定义容忍策略
tolerations:
# Equal精确匹配
- operator: Equal
key: taint
value: ""
effect: NoSchedule
restartPolicy: Always
containers:
- name: container-alpine
image: alpine:3.7
command: ["/bin/sh", "-c","while true;do sleep 3600;done;"]实验步骤
- 1. 为node1定义污点: taint=:PreferNoSchedule
- 2. 为node2定义污点: taint=:NoSchedule
- 3. 创建pod并查看实际调度的节点
- 4. 修改pod 的容忍为: operator: Exists effect: NoSchedule
修改node2污点: taint=:NoExecute
- 5. 再次创建pod并查看实际调度的节点
- 6. 清除2个节点的所有污点实验操作
1-
kubectl taint node node1 taint=:PreferNoSchedule
2-
kubectl taint node node2 taint=:NoSchedule
3-
kubectl apply -f pod-alpine.yaml
watch -n 1 kubectl get po pod-alpine -o wide
4-
vim pod-alpine.yaml 编辑配置文件修改内容
kubectl taint node node2 taint=:NoSchedule-
kubectl taint node node2 taint=:NoExecute
5-
kubectl apply -f pod-alpine.yaml
6-
kubectl taint node node1 taint=:PreferNoSchedule-
kubectl taint node node2 taint=:NoExecute-亲和及反亲和
亲和介绍
Affinity,中文译作“亲和”。亲和性调度用于表达 Pod 对 Node 的偏好(节点亲和),或 Pod 对其他 Pod 的偏好(Pod 亲和)。与污点“节点排斥 Pod”的方向相反,亲和是“Pod 主动靠近节点或其他 Pod”。
亲和分为两类:
硬亲和与软亲和:与污点的 effect 类似,亲和也有强弱之分:
IgnoredDuringExecution 的含义与容忍度一致:调度时生效,运行后若标签变化不再匹配,不会驱逐已有 Pod。
节点亲和(nodeAffinity)
节点亲和根据 Node 的标签 约束 Pod 可以调度到哪些节点,是 nodeSelector 的增强版,语法更丰富,且支持软策略。
节点亲和匹配策略
硬亲和(required):
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd软亲和(preferred):
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssdweight 范围 1-100,权重越高,调度器越倾向于选择满足条件的节点。
操作符说明
Pod 亲和及反亲和
Pod 亲和/反亲和基于 节点上已有 Pod 的标签 来约束新 Pod 的调度位置,而非节点自身的标签。
核心概念:
拓扑域(topologyKey):用节点标签的 key 来划分范围。例如
kubernetes.io/hostname表示以单个节点为范围,topology.kubernetes.io/zone表示以可用区为范围。LabelSelector:筛选参照的 Pod 标签。
语义:
Pod 亲和:如果节点上已有满足条件的 Pod,则新 Pod 应该 调度到该节点(或同一拓扑域)。
Pod 反亲和:如果节点上已有满足条件的 Pod,则新 Pod 不应该 调度到该节点(或同一拓扑域)。
Pod 亲和匹配策略
硬亲和(required):
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- backend
topologyKey: kubernetes.io/hostname软亲和(preferred):
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- backend
topologyKey: kubernetes.io/hostnamePod 反亲和匹配策略
硬反亲和(required):
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: kubernetes.io/hostname软反亲和(preferred):
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: kubernetes.io/hostname拓扑域理解
⚠️ 注意:使用 Pod 反亲和时,集群中每个节点都必须具有
topologyKey指定的标签,否则可能导致意外调度行为。Pod 亲和/反亲和计算开销较大,不建议在数百节点的集群中使用。
实验要求
1. 为node1打标签:disk=ssd
2. 创建pod,配置节点硬亲和:必须调度到 disk=ssd 的节点
3. 查看pod调度到的节点
4. 为node2打标签:disk=hdd
5. 修改pod为节点软亲和:偏好 disk=ssd
6. 再次创建pod,观察调度结果
7. 清除node1和node2的标签实验操作
1-
kubectl label node node1 disk=ssd
2-
cat > pod-nodeaffinity.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity
namespace: default
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk
operator: In
values:
- ssd
restartPolicy: Always
containers:
- name: container-alpine
image: alpine:3.7
command: ["/bin/sh", "-c", "while true;do sleep 3600;done;"]
EOF
kubectl apply -f pod-nodeaffinity.yaml
watch -n 1 kubectl get po pod-nodeaffinity -o wide
3-
# 观察pod是否运行在 node1 上
4-
kubectl label node node2 disk=hdd
5-
cat > pod-nodeaffinity.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity
namespace: default
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: disk
operator: In
values:
- ssd
restartPolicy: Always
containers:
- name: container-alpine
image: alpine:3.7
command: ["/bin/sh", "-c", "while true;do sleep 3600;done;"]
EOF
6-
kubectl delete -f pod-nodeaffinity.yaml
kubectl apply -f pod-nodeaffinity.yaml
watch -n 1 kubectl get po pod-nodeaffinity -o wide
# 预期:优先调度到 node1(disk=ssd),若无资源则可能调度到 node2
7-
kubectl label node node1 disk-
kubectl label node node2 disk-
kubectl delete -f pod-nodeaffinity.yaml污点 及 容忍度 定向 亲和与反亲和
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法