(九)Pod 调度
这章我们将学习 节点调度 的相关知识,在标签之上控制 Pod 在节点中部署
亲和性
Node 亲和性
前面我们学习了 nodeSelector ,Deployment 等可以使用 nodeSelector 选择合适的节点部署 Pod,例如 spec.nodeSelector.mem="much"
而节点亲和性类似于 nodeSelector ,可以根据节点上的标签,约束 Pod 可以调度到哪些节点,Pod 亲和性有两种,分别为:
- requiredDuringSchedulingIgnoredDuringExecution 硬需求,将 Pod 调度到一个节点必须满足的规则,节点不满足条件就不能调度
- preferredDuringSchedulingIgnoredDuringExecution 软性偏好,调度器尽量满足,但不保证,就是不一定的意思
节点亲和性语法支持下面的操作符:In,NotIn,Exists,DoesNotExist,Gt,Lt
如果一个 Pod 同时配置了 nodeSelector 和 nodeAffinity,两者必须同时满足
# 给 slave 节点打标签
kubectl label node slave mem=more --overwrite
kubectl get nodes --show-labels
# 硬性匹配 mem=small
cat > affinity-nginx.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: affinity-nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: mem
operator: In
values:
- more
containers:
- name: nginx
image: nginx:latest
EOF
kubectl apply -f affinity-nginx.yaml
kubectl get pod affinity-nginx -o wide
可以看到,当硬性规则完全不满足时,Pod 会保持 Pending

Pod 亲和性与反亲和性
节点亲和性根据 Node 标签选择节点;Pod 亲和性根据其他 Pod 的标签决定相互靠近或分开
Pod 亲和性与反亲和性的合法操作符有 In,NotIn,Exists,DoesNotExist
通过 Affinity 后缀 可以设置亲和性,例如节点亲和性 nodeAffinity,而设置反亲和性使用 AntiAffinity 后缀,例如 nodeAntiAffinity
反亲和性跟亲和性一样,都有 requiredDuringSchedulingIgnoredDuringExecution 硬限制和 preferredDuringSchedulingIgnoredDuringExecution 软限制,只是反亲和性是相反的表示,如果符合条件则不能调度
污点和容忍度
前面提到亲和性和反亲和性,我们可以让 Pod 选择合适的 Node(节点亲和性),或者让 service 、Deployment 选择合适的 Pod(Pod亲和性),这些拥有 Label 的对象都是被选择的
而 污点和容忍度,Node 和 Pod 它们可以排斥 “被选择” 的命运
污点 taint
节点污点:当节点添加一个污点后,除非 Pod 声明能够容忍这个污点,否则 Pod 不会被调度到这个节点上
如果节点一开始没有设置污点,然后部署了 Pod,后面节点设置了污点,节点可能会删除已部署的 Pod,这种行为称为驱逐
节点污点(taint) 可以排斥一类特定的 Pod,而 容忍度(Tolerations)则表示能够容忍这个对象的污点
节点说自己又笨又丑,但是 Pod 说我不介意,要跟你谈一场轰轰烈烈的恋爱
Node 有 taint -> Node 排斥 Pod
Pod 能 tolerations -> Pod 说我是真爱,我能容忍污点 -> Node 接受 Pod
污点有强制和尽量两种,前者完全排斥,后者尽可能排斥,另外某些污点可以将已经在这台节点上部署的 Pod 逐出,这个过程称为 effect
其中 effect 存在三种取值
- NoSchedule 不再把不能容忍该污点的新 Pod 调度到节点;不影响已经运行的 Pod
- PreferNoSchedule 尽量避免把不能容忍该污点的 Pod 调度到节点
- NoExecute 不调度不能容忍的 Pod,并驱逐节点上已经运行且不能容忍的 Pod
系统会 尽量避免将 Pod 调度到存在其不能容忍污点的节点上,但这不是强制的
Kubernetes 处理多个污点和容忍度的过程就像一个过滤器:从一个节点的所有污点开始遍历,过滤掉那些 Pod 中存在与之相匹配的容忍度的污点
污点生成的键值不是标签,污点生成的是 taint 对象,标签生成的是 label 对象,给节点设置的污点,不会在 Labels 中出现,而是在 Traints 中
# 添加 污点
# kubectl taint node <节点名> key=value:<effect>
kubectl taint node slave key1=value1:NoSchedule
kubectl describe node slave
# 更新或覆盖 污点
# kubectl taint node [node] key=value:[effect] --overwrite=true
kubectl taint node slave key1=value1:NoSchedule --overwrite=true
# 删除 污点
kubectl taint node slave key1=value1:NoSchedule-

kubectl taint node slave key1=value1:NoSchedule
cat > taint-nginx.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: taint-nginx
spec:
nodeSelector:
kubernetes.io/hostname: slave
containers:
- name: nginx
image: nginx:latest
EOF
kubectl get pod taint-denied -o wide
kubectl describe pod taint-nginx ( | grep Warning )
nodeSelector 要求它必须去 slave,但 Pod 没有容忍 key1=value1:NoSchedule,所以应保持 Pending 在 Events 中可以看到调度器无法选择节点

kubectl edit node slave -o yaml

容忍度 Tolerations
kubectl delete pod taint-nginx
cat > taint-tolerated.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: taint-tolerated
spec:
nodeSelector:
kubernetes.io/hostname: slave
tolerations:
- key: key1
operator: Equal
value: value1
effect: NoSchedule
containers:
- name: nginx
image: nginx:latest
EOF
kubectl apply -f taint-tolerated.yaml
kubectl get pod taint-tolerated -o wide
# 使用 apt install jq 安装 json 筛选工具
kubectl get nodes slave -o json | jq '.spec.taints'
这次 Pod 进入 Running,节点为 slave,容忍度与污点具有相同的 key、value 和 effect,所以能够通过该污点的过滤

当节点设置污点后,无论其效果是哪一种,只要 Pod 没有设置相关的容忍度,Pod 就不会调度到此节点上
例如节点声明了 smallcpu 污点,只要 Pod 没有声明容忍此 污点,那么 Pod 就不应该被调用到此节点上除了 smallcpu 污点名称外,还有值也属于规则约束,这点我们后面再解释
系统默认污点
尽管一个节点上的污点完全排斥 Pod,但是某些系统创建的 Pod 可以容忍所有 NoExecute 和 NoSchedule 污点,因此不会被逐出
例如 master 节点是不会被 Deployment 等分配 Pod 的,因为 master 有个污点,表面它只应该运行 kube-system 命名空间中的很多系统 Pod,用户 Pod 会被排斥部署到 master 节点上
kubectl describe nodes | grep -E 'Name:|Taints'
可以看到,master 节点上有一个 node-role.kubernetes.io/control-plane:NoSchedule 的污点,Kubernetes 部署用户的 Pod 时会检查节点是否存在此污点,如果有,则不会在此节点上部署 Pod

# 删除污点
kubectl taint node master node-role.kubernetes.io/control-plane:NoSchedule-
kubectl create deployment nginx-taint --image=nginx:latest --replicas=5
kubectl get pods -o wide
# 恢复污点
kubectl taint node master node-role.kubernetes.io/control-plane:NoSchedule
kubectl describe node master | grep -E 'Name:|Taints'
可以看到,master 节点也挂载上来 Pod

总结
这一部分,说实话,有些地方,我没怎么写明白...比如亲和性,等以后有机会了再继续深入理解理解吧
在我的理解里,这个 亲和性 的作用就是一个 Pod 的调度机制,通过打标签的方式去让 Pod 挂载到我需要的节点上...以及污点,也是个 Pod 的调度机制
这俩具体能干多大的事,不清楚,以后有机会再看吧...
愿诸君顺遂