先说结论:升级前别急着改包源
生产环境里,升级失败很少只因为“版本装不上”。更常见的是:节点升级后containerd看起来是running,但 kubelet 连不上 CRI;Pod 卡在ContainerCreating,最后发现 pause 镜像拉不到;节点变成NotReady,根因是 kubelet 和 containerd 的 cgroup driver 没对齐。
今天 A 篇已经把升级链路讲完整:[[2026-07-01 Kubernetes 1.36 + containerd 2.3 生产升级实战:CRI、版本兼容与避坑清单]]。这篇 B 篇只做一件事:把升级前最该跑的检查命令整理成一张可执行清单。
执行顺序建议固定为:
先确认升级对象:控制面、kubelet、containerd 当前版本。
再确认控制面看到的节点状态是否可信。
接着检查 kubelet 到 containerd 的 CRI 入口。
然后看 containerd 配置、pause 镜像、cgroup。
最后看日志和备份条件,确认可以灰度、可以回滚。
组件边界:这 12 条命令到底覆盖哪条链路
升级前检查的对象不是单个二进制,而是这条链路:
kubectl / apiserver -> kubelet -> CRI endpoint -> containerd -> runc / snapshotter / Pod sandbox
kubectl get nodes看到的是控制面视角,crictl info看到的是 CRI 视角,containerd config dump看到的是运行时配置视角,journalctl看到的是服务现场。它们不能互相替代。
1.kubectl version
kubectl version
用途:确认客户端和服务端版本,避免拿错误 kubeconfig 或错误 kubectl 客户端操作生产集群。
重点看:
Server Version是不是这次计划升级的控制面基线。Client Version是否明显落后,尤其是跨多个小版本时不要直接拿旧客户端做关键变更。
异常判断:
如果命令连不上 apiserver,先处理访问、证书或 kubeconfig 问题,不要进入节点升级。
如果客户端和服务端版本偏差过大,先换匹配版本的
kubectl,再继续检查。
2.kubelet --version
kubelet --version
用途:确认当前节点 kubelet 版本,判断节点是否已经被人手工升级过,或者不同批次节点版本是否混乱。
正常现象:同一升级批次内节点版本一致,且符合 Kubernetes 版本偏差策略。
异常判断:
同一批次里 kubelet 版本不一致,先分组,不要全量一起升级。
如果节点上没有
kubelet命令或路径异常,先确认发行版安装方式和 systemd 单元文件。
3.containerd --version
containerd --version
用途:确认当前 containerd 版本和打包来源,避免目标版本、OS 仓库、节点实际版本三者不一致。
重点看:
版本号是否符合升级计划。
是否来自发行版仓库、官方包、还是历史手工安装。
异常判断:
如果
containerd不存在,但节点仍上报 containerd runtime,先用systemctl status containerd和which containerd查路径。如果不同节点版本散乱,先记录版本盘点表,再决定升级批次。
4.kubectl get nodes -o wide
kubectl get nodes -o wide
用途:从控制面视角确认节点状态、kubelet 版本、节点 IP、OS 镜像和容器运行时汇报。
重点看:
STATUS是否全是Ready。VERSION是否和节点本机kubelet --version对得上。CONTAINER-RUNTIME是否显示预期运行时,例如containerd://...。
异常判断:
已经存在
NotReady节点时,先排障,不要把升级和旧故障混在一起。控制面看到的 runtime 和节点本机不一致,优先查 kubelet 汇报和 CRI endpoint。
5.kubectl describe node <node-name>
kubectl describe node <node-name>
用途:确认 Node Conditions、Events、资源压力和 kubelet 最近上报的异常。
重点看:
Ready、MemoryPressure、DiskPressure、PIDPressure、NetworkUnavailable。Events 里是否有
PLEG、container runtime、cgroup、image、network相关提示。
异常判断:
有资源压力时,先处理磁盘、inode、内存或 PID 问题。
有 runtime 相关 Event 时,继续跑第 6 到第 12 条命令定位 CRI、containerd 和日志。
CRI 入口检查:先确认 kubelet 连的是谁
6.cat /etc/crictl.yaml
cat /etc/crictl.yaml
用途:确认crictl默认连接哪个 CRI endpoint。虽然 kubelet 不一定直接读取这个文件,但它能帮你快速发现节点上常用排障入口是否还指向旧 runtime。
建议内容:
runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false
正常现象:runtime-endpoint和image-endpoint都指向 containerd socket。
异常判断:
如果还指向 Docker shim、CRI-O 或不存在的 socket,先修正
/etc/crictl.yaml,否则后面的crictl info结论不可信。修改前保留旧文件:
cp -a /etc/crictl.yaml /etc/crictl.yaml.$(date +%F-%H%M%S).bak。
7.ls -l /run/containerd/containerd.sock
ls -l /run/containerd/containerd.sock
用途:确认 containerd CRI socket 文件是否存在,以及权限是否异常。
正常现象:能看到一个 socket 文件,通常类似:
srw-rw---- 1 root root ... /run/containerd/containerd.sock
异常判断:
No such file or directory:先查systemctl status containerd,再看 containerd 是否启动失败。权限异常:普通用户跑
crictl失败不代表 CRI 不通,生产节点建议用sudo crictl info验证。
8.sudo crictl info
sudo crictl info
用途:直接验证 CRI 连通性,确认 kubelet 所依赖的 runtime 信息能被正常返回。
正常现象:返回 JSON,能看到 runtime、config、sandbox image、cgroup、snapshotter 等信息。
异常判断:
connection refused:优先查 socket 和 containerd 服务状态。context deadline exceeded:查 containerd 是否卡死、节点 IO 是否异常、CRI 插件是否可用。no such file or directory:回到第 6、7 条,检查 endpoint 和 socket 路径。
containerd 配置检查:服务 running 不代表配置正确
9.sudo containerd config dump | grep -n "sandbox_image"
sudo containerd config dump | grep -n "sandbox_image"
用途:确认 Pod Sandbox 使用的 pause 镜像。升级后 Pod 卡在ContainerCreating,常见原因之一就是 pause 镜像不可达。
正常现象:sandbox_image指向当前网络环境可拉取的镜像地址,企业环境里最好是内网 registry 或已验证的 mirror。
异常判断:
指向外网且节点不能访问时,先配置 mirror 或私有仓库。
指向历史私仓但镜像已被清理时,先补镜像,再升级。
10.sudo containerd config dump | grep -n "SystemdCgroup" -A 5 -B 5
sudo containerd config dump | grep -n "SystemdCgroup" -A 5 -B 5
用途:确认 containerd 侧 runtime 的 cgroup 配置,避免 kubelet 和 containerd 在 cgroup driver 上不一致。
正常现象:containerd 侧配置与 kubelet 侧cgroupDriver对齐。使用 systemd 的生产节点通常应让 kubelet 和 containerd 都走 systemd cgroup。
异常判断:
如果 containerd 是
SystemdCgroup = false,但 kubelet 是systemd,不要直接全量改。先选单节点 drain,备份配置,灰度重启,再验证 Pod 创建。如果输出里找不到字段,先确认 containerd 配置版本和 runtime 配置路径,不要按旧版本路径硬改。
11.grep -n "cgroupDriver" /var/lib/kubelet/config.yaml
grep -n "cgroupDriver" /var/lib/kubelet/config.yaml
用途:确认 kubelet 使用的 cgroup driver。
正常现象:能看到类似:
cgroupDriver: systemd
异常判断:
如果文件不存在,先用
systemctl cat kubelet查 kubelet 启动参数,确认--config指向哪里。如果 kubelet 和 containerd 不一致,先备份
/var/lib/kubelet/config.yaml和/etc/containerd/config.toml,再灰度修正。
日志检查:升级前先看最近 200 行
12.journalctl -u kubelet -n 200 --no-pager
journalctl -u kubelet -n 200 --no-pager
用途:确认升级前 kubelet 是否已经持续报错。已有故障不处理,升级后只会把问题扩大。
重点看关键词:
PLEGcontainer runtimeCRIcgroupfailed to create pod sandboxImagePullBackOffx509NetworkPluginNotReady
异常判断:
看到 CRI 或 runtime 错误,回到第 6 到第 10 条。
看到镜像拉取或证书错误,先处理 registry、mirror、CA 或 imagePullSecret。
看到 CNI 错误,先查 CNI 配置和插件,不要把问题归因到 containerd 升级。
补充命令:
systemctl status containerd --no-pager journalctl -u containerd -n 200 --no-pager
用途:确认 containerd 是否反复重启,是否有 registry、snapshotter、runtime、shim 相关错误。
配置变更前必须做的备份
只要涉及/etc/containerd、/var/lib/kubelet/config.yaml、systemd drop-in 或 runtime endpoint,升级前必须先保留现场。
sudo mkdir -p /root/k8s-upgrade-backup/$(date +%F)
用途:创建当天备份目录。
sudo cp -a /etc/containerd /root/k8s-upgrade-backup/$(date +%F)/containerd
用途:备份 containerd 配置、证书目录和 registry 配置。
sudo cp -a /var/lib/kubelet/config.yaml /root/k8s-upgrade-backup/$(date +%F)/kubelet-config.yaml
用途:备份 kubelet 主配置。
sudo systemctl cat kubelet > /root/k8s-upgrade-backup/$(date +%F)/kubelet-systemd.txt sudo systemctl cat containerd > /root/k8s-upgrade-backup/$(date +%F)/containerd-systemd.txt
用途:保留 systemd 启动参数和 drop-in 现场,便于回滚对比。
sudo crictl info > /root/k8s-upgrade-backup/$(date +%F)/crictl-info-before.json sudo containerd config dump > /root/k8s-upgrade-backup/$(date +%F)/containerd-config-before.toml
用途:保留 CRI 和 containerd 生效配置,而不只是备份静态文件。
一页式升级前检查表
| 检查项 | 命令 | 正常现象 | 异常现象 | 下一步 |
|---|---|---|---|---|
| 控制面版本 | kubectl version | 客户端、服务端版本符合升级计划 | 连不上 apiserver,或版本偏差过大 | 先确认 kubeconfig、证书和版本偏差规则 |
| kubelet 版本 | kubelet --version | 同批节点版本清楚,可分批管理 | 节点版本散乱 | 先按版本分组,不要全量升级 |
| containerd 版本 | containerd --version | 当前版本和来源明确 | 包源、目标版本、实际版本不一致 | 先确认 OS 仓库和安装方式 |
| 节点列表 | kubectl get nodes -o wide | 节点 Ready,runtime 汇报为预期 containerd | NotReady 或 runtime 汇报异常 | 先查 kubelet 汇报和 CRI |
| Node 详情 | kubectl describe node <node-name> | Conditions 正常,无持续异常 Events | Pressure、PLEG、runtime、CNI 异常 | 先解决现有故障 |
| CRI endpoint | cat /etc/crictl.yaml | 指向unix:///run/containerd/containerd.sock | 指向旧 Docker/CRI-O socket 或空配置 | 修正 endpoint 后再验证 |
| socket 文件 | ls -l /run/containerd/containerd.sock | socket 存在且权限合理 | 文件不存在或权限异常 | 查 containerd 服务和启动日志 |
| CRI 连通性 | sudo crictl info | 返回 runtime 信息 | refused、timeout、no such file | 查 endpoint、socket、服务和 CRI 插件 |
| pause 镜像 | containerd config dump | grep sandbox_image | 镜像地址可从节点拉取 | 外网不可达或私仓缺镜像 | 配置 mirror/私仓并先验证拉取 |
| containerd cgroup | containerd config dump | grep SystemdCgroup | 与 kubelet cgroup driver 对齐 | SystemdCgroup与 kubelet 不一致 | 先单节点灰度修正 |
| kubelet cgroup | grep cgroupDriver /var/lib/kubelet/config.yaml | 与 containerd 侧一致 | 文件缺失或配置不一致 | 查 kubelet--config,备份后修正 |
| kubelet 日志 | journalctl -u kubelet -n 200 --no-pager | 无持续 runtime、CRI、cgroup、image 错误 | PLEG、CRI、cgroup、镜像错误持续出现 | 先排障,再进入升级窗口 |
异常怎么判断
如果 12 条命令里有异常,先按下面顺序处理,不要直接进入升级:
| 异常类型 | 常见信号 | 先查什么 | 处理建议 |
|---|---|---|---|
| 版本不一致 | kubectl get nodes与本机版本不一致 | kubelet --version、节点分组 | 拆批次,先升一组,不要混合全量升级 |
| CRI 连不上 | crictl inforefused / timeout | /etc/crictl.yaml、socket、systemctl status containerd | 先修 endpoint 或服务,再继续 |
| cgroup 不对齐 | kubelet 是systemd,containerd 不是 | kubelet config、containerd runtime 配置 | 备份后单节点灰度修正 |
| pause 镜像不可达 | Pod sandbox 创建失败 | sandbox_image、crictl pull、containerd 日志 | 配置 mirror 或私仓镜像 |
| 日志已有错误 | PLEG、runtime、CNI、image pull 持续出现 | kubelet/containerd 最近 200 行日志 | 先排障,不把旧故障带进升级 |
发布前执行 checklist
- 12 条命令已在每一类节点上跑过:控制面节点、普通工作节点、GPU/特殊运行时节点。
- 节点按版本、OS、运行时、业务重要性分组,升级批次清楚。
/etc/containerd、/var/lib/kubelet/config.yaml、systemd drop-in 已备份。crictl info和containerd config dump的升级前输出已保存。- pause 镜像、业务镜像、Harbor/mirror、CA 证书在节点侧验证过。
- kubelet 和 containerd 日志没有持续 CRI、PLEG、cgroup、镜像拉取错误。
- 已确定 drain、升级、验证、uncordon、回滚的操作人和窗口。
总结
升级 Kubernetes 和 containerd 之前,最怕的是“以为只是升级包,实际上动了整条运行时链路”。这 12 条命令的价值不在于复杂,而在于把升级前最容易漏的入口固定下来:版本、节点、CRI、containerd 配置、cgroup、日志和备份。
建议把本文作为升级窗口前的执行单。只有当这些检查都能解释清楚,才进入 drain、升级、重启、验证和放量。遇到不一致,不要用“具体情况具体分析”糊过去,先定位到版本、CRI、cgroup、镜像仓库或日志其中一层,再决定是否继续。
下一篇建议阅读:crictl 实战指南:没有 docker 命令后,Kubernetes 节点该怎么排障?
参考资料
Kubernetes 文档:Container Runtimes,Container Runtimes | Kubernetes
Kubernetes 文档:Debugging Kubernetes nodes with crictl,Debugging Kubernetes nodes with crictl | Kubernetes
Kubernetes 文档:Version Skew Policy,Version Skew Policy | Kubernetes
containerd 文档:CRI plugin configuration,https://github.com/containerd/containerd/blob/main/docs/cri/config.md