K8S集群从CRI-O切换容器运行时至Docker 主节点drain失败处理
故障原因
cordon、drain操作失败通常是三类问题导致:
- 执行命令的账号未加载管理员级别的kubeconfig,权限不足
- drain默认会拒绝驱逐DaemonSet管控Pod、挂载emptyDir的Pod、无控制器绑定的裸Pod,缺少对应跳过参数就会直接报错退出
- 双节点集群没有控制面冗余,如果你先操作master节点,驱逐过程中控制面组件(etcd、kube-apiserver等)被关停会直接导致集群API断连,命令超时失败
前置修复(解决cordon/drain报错)
- 所有kubectl操作优先在master节点用root账号执行,非root账号执行前先加载管理员配置:
export KUBECONFIG=/etc/kubernetes/admin.conf - drain节点时统一带上以下参数,跳过无法驱逐的系统级Pod:
kubectl drain <节点名> --ignore-daemonsets --delete-emptydir-data --force
参数说明:
--ignore-daemonsets:跳过DaemonSet管控的Pod,这类Pod和节点生命周期绑定,节点恢复后会自动拉起,不影响切换--delete-emptydir-data:允许删除挂载emptyDir临时存储的Pod,系统核心组件均使用该类存储,确认无业务在emptyDir存持久化数据即可使用--force:强制驱逐无ReplicaSet/Deployment/StatefulSet等控制器绑定的裸Pod
双节点集群CRI从CRI-O切换Docker的标准操作流程
核心原则:双节点无冗余,绝对不能同时操作两个节点,必须先切换worker节点,确认业务、集群状态全正常后,再切换master节点
worker节点切换步骤
- 标记worker节点不可调度,驱逐节点上的业务负载:
kubectl cordon <worker节点名称> # 确认节点状态变为SchedulingDisabled后执行驱逐 kubectl drain <worker节点名称> --ignore-daemonsets --delete-emptydir-data --force
驱逐完成后,原本跑在worker上的业务Pod会暂时处于Pending状态,属于正常现象。
2. 登录worker节点,停kubelet服务、禁用CRI-O:
systemctl stop kubelet systemctl disable crio --now
- 安装Docker CE与cri-dockerd组件(K8s 1.24及以上版本已移除内置dockershim,必须通过cri-dockerd对接Docker),安装完成后启动docker、cri-dockerd服务并设置开机自启。
- 修改kubelet的CRI端点配置,配置文件默认路径为
/var/lib/kubelet/kubeadm-flags.env,将其中--container-runtime-endpoint参数的值从CRI-O默认的unix:///var/run/crio/crio.sock修改为cri-dockerd的socket地址unix:///var/run/cri-dockerd.sock。 - 重载系统配置,启动kubelet:
systemctl daemon-reload systemctl start kubelet
- 等待1-2分钟,执行
kubectl get nodes确认worker节点状态变为Ready,可在worker节点执行crictl info | grep runtimeType校验,返回值为docker即表示CRI对接正常。 - 解除worker节点的调度封锁:
kubectl uncordon <worker节点名称>
观察3-5分钟,等所有Pending状态的业务Pod全部在worker节点拉起、运行正常后,再开始master节点的切换操作。
master节点切换步骤
- 标记master节点不可调度,驱逐节点负载:
kubectl cordon <master节点名称> kubectl drain <master节点名称> --ignore-daemonsets --delete-emptydir-data --force
驱逐master过程中kube-apiserver会出现10-30秒的短暂不可用,属于正常现象,不要中途中断命令。
- 登录master节点,停kubelet服务、禁用CRI-O:
systemctl stop kubelet systemctl disable crio --now
- 和worker节点操作一致:安装Docker CE、cri-dockerd,启动服务并设置开机自启。
- 修改master节点
/var/lib/kubelet/kubeadm-flags.env中的--container-runtime-endpoint参数为cri-dockerd的socket地址。 - 重载系统配置,启动kubelet:
systemctl daemon-reload systemctl start kubelet
- 等待2分钟左右,执行
kubectl get nodes确认两个节点均为Ready状态,执行kubectl get pods -A确认所有系统组件、业务Pod均为Running状态。 - 解除master节点的调度封锁:
kubectl uncordon <master节点名称>
回滚预案
如果切换过程中节点持续NotReady超过5分钟,立刻将kubelet配置中的--container-runtime-endpoint改回CRI-O的socket地址,启动crio服务和kubelet,先恢复集群状态再排查问题。临时测试完成后需要切回CRI-O时,按照上述先worker后master的顺序,反向修改CRI端点、停Docker服务启动CRI-O即可。
内容的提问来源于stack exchange,提问作者johnny k
相关产品推荐
相关产品推荐

