16.6.2 节点筛选与亲和性/反亲和性

节点筛选与亲和性/反亲和性#

节点筛选用于控制 Pod 被调度到哪些节点,常见机制包括节点标签/选择器、节点亲和性与反亲和性、以及 Pod 亲和性/反亲和性。合理使用这些能力可实现隔离、高可用、性能优化与成本控制。

原理草图(调度匹配关系)#

文章图片

节点标签与节点选择器#

安装/准备(环境验证)

# 查看节点列表与标签
kubectl get nodes --show-labels

# 给节点打标签(示例:磁盘类型与可用区)
kubectl label node node1 disktype=ssd zone=cn-bj1
kubectl label node node2 disktype=hdd zone=cn-bj1

# 查看单节点标签
kubectl get node node1 --show-labels

配置示例:NodeSelector(精确匹配)

# 文件:/tmp/pod-nodeselector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-ns
  labels:
    app: demo
spec:
  containers:
  - name: nginx
    image: nginx:1.25
  nodeSelector:
    disktype: ssd

应用与验证

kubectl apply -f /tmp/pod-nodeselector.yaml
kubectl get pod app-ns -o wide
# 预期效果:Pod 调度到带 disktype=ssd 的节点

命令解释
- kubectl label node:给节点打标签,供调度筛选使用
- nodeSelector:只匹配标签完全一致的节点

节点亲和性/反亲和性(Node Affinity)#

配置示例:硬约束 + 软约束

# 文件:/tmp/pod-nodeaffinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-na
  labels:
    app: demo
spec:
  containers:
  - name: nginx
    image: nginx:1.25
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: zone
            operator: In
            values: ["cn-bj1"]
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 50
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values: ["ssd"]

应用与验证

kubectl apply -f /tmp/pod-nodeaffinity.yaml
kubectl get pod app-na -o wide
# 预期效果:优先调度到 zone=cn-bj1 且 disktype=ssd 的节点

命令解释
- requiredDuringSchedulingIgnoredDuringExecution:硬约束,不满足则 Pending
- preferredDuringSchedulingIgnoredDuringExecution:软约束,资源紧张可被忽略
- matchExpressions:支持 In/NotIn/Exists/Gt/Lt 等操作符

Pod 亲和性/反亲和性(Pod Affinity/Anti-Affinity)#

准备测试标签与应用

# 文件:/tmp/app-mysql.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mysql-1
  labels:
    app: mysql
spec:
  containers:
  - name: mysql
    image: mysql:8.0
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "pass"
---
apiVersion: v1
kind: Pod
metadata:
  name: api-1
  labels:
    app: api
spec:
  containers:
  - name: nginx
    image: nginx:1.25
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: mysql
        topologyKey: kubernetes.io/hostname

应用与验证

kubectl apply -f /tmp/app-mysql.yaml
kubectl get pod -o wide
# 预期效果:api-1 不与 mysql-1 同节点

命令解释
- podAntiAffinity:避免与指定标签的 Pod 同拓扑域
- topologyKey:定义“同域”的范围,如节点级或可用区级

关键参数与调度行为#

  • 亲和/反亲和只影响调度阶段,已运行 Pod 不会被强制迁移
  • 硬约束过多会导致 Pod Pending
  • 软约束提高调度成功率
  • 与污点/容忍度结合可实现更强的隔离与保障

排错与诊断(含命令与解释)#

1)Pod Pending

kubectl describe pod app-na
# 关注 Events 中的 FailedScheduling 原因

2)检查节点标签是否满足

kubectl get nodes --show-labels | grep -E "node1|node2"

3)检查调度器日志(控制平面节点)

# 若使用 systemd
journalctl -u kube-scheduler -n 200 --no-pager

常见原因
- 标签缺失或拼写错误
- 硬约束过多,候选节点为空
- topologyKey 不存在或节点未标注

练习#

练习 1:
为两个节点打标签 zone=cn-bj1zone=cn-bj2,创建 Pod 仅允许调度到 cn-bj2,并验证结果。

练习 2:
创建两个 Pod,要求 app=webapp=db 不在同一节点(节点级反亲和),观察调度效果。

练习 3:
将硬约束改成软约束,模拟资源不足时的调度行为,记录 kubectl describe pod 的事件变化。