
cordon、drain 和 delete 三个命令都会使 node 停止被调度，后期创建的 pod 不会继续被调度到该节点上，但操作的暴力程度却不一样。

## cordon 停止调度（不可调度，临时从 K8S 集群隔离）

- 影响最小，只会将 node 标识为 SchedulingDisabled 不可调度状态。
- 之后 K8S 再创建的 pod 资源，不会被调度到该节点。
- 旧有的 pod 不会受到影响，仍正常对外提供服务。
- 禁止调度命令"kubectl cordon node_name"。
- 恢复调度命令"kubectl uncordon node_name"。（恢复到 K8S 集群中，变回可调度状态）

## drain 驱逐节点（先不可调度，然后排干）

- 首先，驱逐 Node 上的 pod 资源到其他节点重新创建。
- 接着，将节点调为 SchedulingDisabled 不可调度状态。
- 禁止调度命令"kubectl drain node_name --force --ignore-daemonsets --delete-local-data"
- 恢复调度命令"kubectl uncordon node_name"。（恢复到 K8S 集群中，变回可调度状态）
- drain 方式是安全驱逐 pod，会等到 pod 容器应用程序优雅停止后再删除该 pod。
- drain 驱逐流程：先在 Node 节点删除 pod，然后再在其他 Node 节点创建该 pod。所以为了确保 drain 驱逐 pod 过程中不中断服务（即做到"无感知"地平滑驱逐），必须保证要驱逐的 pod 副本数大于 1，并且采用了"反亲和策略"将这些 pod 调度到不同的 Node 节点上了！也就是说，在"多个 pod 副本 + 反亲和策略"的场景下，drain 驱逐过程对容器服务是没有影响的。

需要注意：

- 对节点执行维护操作之前（例如：内核升级，硬件维护等），您可以使用 kubectl drain 安全驱逐节点上面所有的 pod。
- drain 安全驱逐方式将会允许 pod 里面的容器遵循指定的 PodDisruptionBudgets 执行优雅中止。也就是说，drain 安全驱逐可以做到：优雅地终止 pod 里的容器进程。
- kubectl drain 返回成功表明所有的 pod（除了排除的那些）已经被安全驱逐（遵循期望优雅的中止期，并且没有违反任何应用程序级别的中断预算）。
- 然后，通过对物理机断电或者在云平台上删除节点所在的虚拟机，都能安全的将节点移除。

一般线上 K8S 的 PDB（PodDisruptionBudgets）配置的也是符合 Pod 驱逐的理想情况的，即 maxUnavailable 设置为 0，maxSurge 设置为 1：

默认情况下，kubectl drain 会忽略那些不能杀死的系统类型的 pod。drain 命令中需要添加三个参数：--force、--ignore-daemonsets、--delete-local-data

- --force 当一些 pod 不是经 ReplicationController, ReplicaSet, Job, DaemonSet 或者 StatefulSet 管理的时候就需要用--force 来强制执行 (例如:kube-proxy)
- --ignore-daemonsets 无视 DaemonSet 管理下的 Pod。即--ignore-daemonsets 往往需要指定的，这是因为 deamonset 会忽略 unschedulable 标签 (使用 kubectl drain 时会自动给节点打上不可调度标签),因此 deamonset 控制器控制的 pod 被删除后可能马上又在此节点上启动起来，这样就会成为死循环。因此这里忽略 daemonset。
- --delete-local-data 如果有 mount local volumn 的 pod，会强制杀掉该 pod。

drain 禁止调度的操作步骤：

```bash
# *确定要排空的节点的名称*
kubectl get nodes
# *查看pod*
kubectl get po
# *命令node节点开始释放所有pod，并且不接收新的pod进程*
kubectl drain [node-name] --force --ignore-daemonsets --delete-local-data
# *此时可以对该node节点进行平滑维护，后续需要恢复到k8s集群中：*
kubectl uncordon [node-name]
```

## 推荐使用姿势

通常情况下，如果要对 K8S 集群中的一台 Node 节点进行平滑维护，如升级或调整配置。正确的操作：

- cordon 临时从 K8S 集群隔离出来，标识为 SchedulingDisabled 不可调度状态。
- drain 排干该节点上的 pod 资源到其他 node 节点上。
- 对该节点展开平滑维护操作，如升级或调整配置。
- uncordon 恢复，重新回到 K8S 集群，变回可调度状态。

同时注意：为了确保 drain 驱逐 pod 的时候，容器应用服务不中断，必须满足：

- 要驱逐的 pod 副本数量必须大于 1
- 要配置"反亲和策略"，确保被驱逐的 pod 被调度到不同的 Node 节点上
- deployment 采用滚动更新，设置 maxUnavailable 为 0，maxSurge 为 1

