# 实验前置:清理与打标签

## 清理之前的 Pod
kubectl delete pods -all

## 给 node1 打上磁盘类型标签 (SSD)
kubectl label nodes node1 disk=ssd

## 给 node2 打上磁盘区域标签 (Zone Top)
kubectl label nodes node2 zone=top

# 实验一:NodeSelector 与 NodeAffinity (定向调度)

目标:让 Pod 必须运行在 node1(SSD 节点),并优先选择 node2(但因为 node1 是硬性条件,最终会留在 node1)。

1、创建文件

affinity-test.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: affinity-pod
spec:
  containers:
  - name: nginx
    image: nginx
  nodeSelector:
    disk: ssd # 硬限制:只能去 node1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - top # 软限制:虽然想去 top(node2),但被上面的 ssd(node1) 拽住了
  • preferredDuringSchedulingIgnoredDuringExecution:调度时倾向于满足,但运行时如果环境变了则忽略”.简称软亲和性 (Soft Affinity)

  • weight: 1:权重。如果满足条件,给这个节点加 1 分。在复杂环境下,分数最高的节点胜出。

  • operator: In:匹配逻辑。表示节点的标签值必须在 values 列表(top)中。

2、验证

kubectl apply -f affinity-test.yaml
kubectl get pod affinity-pod -o wid
## 这里可以看见 Pod 运行在 node1 上

# 实验二:Taints & Tolerations(排他性调度)

目标:给 node2 加上污点,模拟需要额外付费或带 GPU 的特殊节点,普通 Pod 不准进来.

1、给 Node2 打上污点


kubectl taint nodes node2 hardware=gpu:NoSchedule

Kubernetes 的污点效果主要有三种,NoSchedule 是最常用的一种:

NoSchedule:“不准进来”。 如果一个 Pod 没有明确写明能够“容忍(Tolerate)”这个污点,那么新的 Pod 绝对不会被调度到这个节点上。但是,已经在节点上运行的 Pod 不受影响。

PreferNoSchedule:“尽量别进来”。 这是软性限制。调度器会尽量避免把 Pod 放到这个节点,但如果别的节点都满了,它还是会妥协。

NoExecute:“统统赶走”。 这是最狠的。不仅新 Pod 进不来,如果节点上现有的 Pod 没有对应的容忍度,会立刻被**驱逐(Evict)**出去。

验证污点有没有打上

kubectl describe node node2  grep Taints

2、创建一个没有任何容忍度的普通 Pod

kubectl run normal-pod --image=nginx
kubectl get pod normal-pod -o wide

这里会发现这个 Pod 不会去 node2,即使 node1 满了或者挂了,也会 Pending,

3、创建一个能容忍污点的 Pod

编辑 gpu-pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  nodeSelector:
    zone: top # 我们指定它去 node2
  tolerations:
  - key: "hardware"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule" # 只有声明了这一行的 Pod 才能进 node2
  containers:
  - name: nginx
    image: nginx

4、验证

kubectl apply -f gpu-pod.yml
kubectl get pod gpu-pod -o wide

可以发现 gpu-pod 成功运行在node2 上了

# 实验三:驱逐实验

目标:当前街道突然变得不可用时,看看 Pod 会发生什么

1、观察当前:gpu-pod 在 node2 上运行

2、升级污点:将 NoSchedule 改为 NoExecute(立即驱逐不容忍的 Pod)


## 先删除旧污点,在打新污点
kubectl taint nodes node2 hardware:NoSchedule-
kubectl taint nodes node2 hardware=gpu:NoExecute

3、见证驱逐

可以提前在另一个终端窗口执行


kubectl get pods -w

会发现 gpu-pod 瞬间进入 Terminating 状态并消失了

这是因为 Tolerations 里写的是 NoSchedule,它不容忍 NoExecute。

# 实验后打扫

## 1. 删掉所有 Pod
kubectl delete pod --all

## 2. 移除节点标签
kubectl label nodes node1 disk-
kubectl label nodes node2 zone-

## 3. 移除节点污点
kubectl taint nodes node2 hardware:NoExecute-

## 4. 确认 Master 是否有污点(保持默认就好,除非你想让 Master 也跑 Pod)
kubectl describe node master  grep Taints

# 总结

NodeSelector:是强制性的匹配。

NodeAffinity:更灵活,Required 是必须满足,Preferred 是尽量满足。

Taints (污点):是节点的属性,用来拒绝 Pod。

Tolerations (容忍度):是 Pod 的属性,用来克服污点。

NoSchedule vs NoExecute:前者只影响 Pod 调度,后者会把已经在跑的 Pod 赶走。

命令


## 查看所有标签
kubectl get nodes --show-labels

## 查看特定标签(比如自定义的 disK 和 zone)
kubectl get nodes -L disk -L zone