Pod 调度与亲和性
新创建的 Pod 该放到哪台节点?默认交给 kube-scheduler 自动决定,但很多场景需要人工干预:应用要跑在有 GPU 的机器、副本要分散到不同节点、维护节点时要把 Pod 迁走。调度器提供节点选择、亲和性、污点容忍等机制来满足这些诉求。
kube-scheduler 的调度流程
调度器对每个待调度 Pod 分两步决策:
- 过滤(Filtering):先筛掉不满足硬性条件的节点,如资源不足、端口冲突、不匹配的污点。
- 打分(Scoring):对剩余节点打分,选择总分最高的节点放置 Pod。
Pod 一直 Pending 时,多数是因为过滤阶段没有节点可用,用 describe 看事件即可确认原因:
kubectl describe pod xxx | tail -20
# 输出:Events: FailedScheduling 0/3 nodes are available ...
nodeSelector 与 nodeName
nodeSelector 按节点标签选择节点,先给节点打标签再引用:
kubectl label node node01 disktype=ssd
kubectl get nodes --show-labels | grep ssd
spec:
nodeSelector:
disktype: ssd # 只调度到带此标签的节点
nodeName 直接把 Pod 钉到指定节点(跳过调度器),一般仅用于调试。
节点亲和性 nodeAffinity
比 nodeSelector 更强:required 是硬性要求(无匹配节点则 Pending),preferred 是软偏好(尽量满足,不满足也能调度到别处):
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values: ["ssd"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: zone
operator: In
values: ["zone-a"]
运算符还有 NotIn、Exists、DoesNotExist 等。podAffinity/podAntiAffinity 则按「与其他 Pod 的关系」调度,如让副本分散在不同节点。
污点 Taints 与容忍 Tolerations
污点打在节点上,标记「我不欢迎这类 Pod」;容忍加在 Pod 上,表示「我可以忍受这个污点」。二者配合实现「某些节点只跑特定负载」:
kubectl taint nodes node01 gpu=true:NoSchedule
# 输出:node/node01 tainted
kubectl taint nodes node01 gpu=true:NoSchedule- # 减号移除污点
spec:
tolerations:
- key: gpu
operator: Equal
value: "true"
effect: NoSchedule
effect 类型:NoSchedule 拒绝新调度、PreferNoSchedule 尽量不调度、NoExecute 立即驱逐不匹配的既有 Pod。
节点维护:cordon 与 drain
下线节点前先禁止新 Pod 调度,再优雅清空上面的 Pod:
kubectl cordon node01 # 标记不可调度
kubectl drain node01 --ignore-daemonsets --delete-emptydir-data # 驱逐 Pod
kubectl uncordon node01 # 恢复可调度
drain 会先让 Pod 优雅终止再迁移到其他节点,完成后节点才可安全维护。
小结:调度器先过滤再打分;nodeSelector/节点亲和性决定 Pod 去哪些节点,污点+容忍实现「指定节点只跑指定负载」;维护节点用 cordon 挡新调度、drain 清空 Pod、uncordon 恢复。