crictl / nerdctl —— K8s 节点上的容器排查
crictl / nerdctl —— K8s 节点上的容器排查
分类:06 容器与编排 适用:K8s 节点(containerd / CRI-O),crictl 1.2x;nerdctl 1.x 一句话:节点上没有 docker 命令时,用
crictl看容器和日志,用nerdctl做更像 docker 的操作。
1. 它解决什么问题
- K8s 节点上
docker ps不存在(1.24+ 移除了 dockershim),怎么查容器? - Pod 一直
ContainerCreating,节点上到底发生了什么? - 容器日志在
kubectl logs拿不到(容器已退出、kubelet 异常),去节点上捞。 - 需要拉镜像、建容器、调试网络,但要与 CRI 兼容。
2. crictl 与 nerdctl 的分工
| 工具 | 面向 | 特点 |
|---|---|---|
crictl |
CRI 接口 | K8s 原生,管 Pod 沙箱,操作的是 K8s 创建的容器 |
nerdctl |
containerd | 类 docker CLI,可自己 run 容器、build 镜像 |
ctr |
containerd 原生 | 底层,参数难用,一般不用 |
docker |
dockerd | 1.24 后节点上通常没有 |
不要用
docker/nerdctl去删 K8s 的容器,绕过 kubelet 会导致状态不一致。排查用crictl,动作交给kubectl。
3. crictl 配置
# 自动探测 endpoint(多数安装包会配好)
crictl info
# 手动指定
crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps
crictl --image-endpoint unix:///run/containerd/containerd.sock images
持久化到 /etc/crictl.yaml:
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
常见 endpoint:
| 运行时 | socket |
|---|---|
| containerd | unix:///run/containerd/containerd.sock |
| CRI-O | unix:///var/run/crio/crio.sock |
| Docker(旧) | unix:///var/run/dockershim.sock |
4. crictl 常用命令
crictl ps # 运行中的容器
crictl ps -a # 含已退出
crictl ps -a --name <关键字> # 按名字过滤
crictl pods # Pod 沙箱列表
crictl pods --name <pod名>
crictl images
crictl img # images 简写
crictl stats # 资源使用
crictl info # 运行时信息与配置
crictl version
看日志(最常用)
crictl logs <container-id>
crictl logs -f <container-id> # 实时
crictl logs --tail 100 <container-id>
crictl logs --since 10m <container-id>
crictl logs -t <container-id> # 时间戳
容器 ID 支持前缀匹配(前几位即可)。
进入容器
crictl exec -it <container-id> sh
crictl exec -it <container-id> /bin/bash
crictl exec <container-id> cat /etc/hosts
查看详情
crictl inspect <container-id> | jq .
crictl inspect <container-id> | jq '.status'
crictl inspectp <pod-id> | jq . # Pod 沙箱详情
crictl inspecti <image-id> # 镜像详情
镜像操作
crictl pull nginx:1.25
crictl rmi <image-id>
crictl rmi --prune # 清理未使用镜像
删除
crictl rm <container-id> # 删除容器(K8s 可能重建)
crictl rmp <pod-id> # 删除 Pod 沙箱
crictl stopp <pod-id> # 停止沙箱
生产优先
kubectl delete pod,让 kubelet 正常回收。crictl rm只用于卡死、无法通过 K8s 删除的场景。
5. 与 docker 命令对照
| 目的 | docker | crictl | nerdctl |
|---|---|---|---|
| 运行中容器 | docker ps |
crictl ps |
nerdctl ps |
| 所有容器 | docker ps -a |
crictl ps -a |
nerdctl ps -a |
| 日志 | docker logs |
crictl logs |
nerdctl logs |
| 进容器 | docker exec -it |
crictl exec -it |
nerdctl exec -it |
| 详情 | docker inspect |
crictl inspect |
nerdctl inspect |
| 镜像 | docker images |
crictl images |
nerdctl images |
| 拉取 | docker pull |
crictl pull |
nerdctl pull |
| 资源 | docker stats |
crictl stats |
nerdctl stats |
| 构建 | docker build |
不支持 | nerdctl build |
| 运行新容器 | docker run |
不支持 | nerdctl run |
6. nerdctl 常用
nerdctl ps -a
nerdctl images
nerdctl run -d --name web -p 8080:80 nginx:1.25
nerdctl logs -f web
nerdctl exec -it web sh
nerdctl build -t app:1.0 .
nerdctl compose up -d # 兼容 docker-compose.yml
nerdctl stats
nerdctl system df
nerdctl namespace ls # containerd 命名空间
nerdctl -n k8s.io ps # 看 K8s 的容器(重要)
关键点:K8s 的容器在 k8s.io 命名空间下。默认 nerdctl ps 看不到,必须加 -n k8s.io。
7. 实战场景
7.1 Pod 起不来,节点上确认容器状态
kubectl get pod -o wide # 1. 拿到所在节点
kubectl describe pod <pod> # 2. 看 Events
ssh <node>
crictl pods --name <pod名前缀> # 3. 找沙箱
crictl ps -a | grep <pod名前缀> # 4. 找容器与状态
crictl logs <容器ID> # 5. 看日志
crictl inspect <容器ID> | jq '.status' # 6. 退出码
7.2 容器已退出,kubectl logs 为空
# Pod 还在,容器重启过
kubectl logs <pod> --previous
# Pod 已被删除,去节点上找日志文件
ls /var/log/pods/<namespace>_<pod>_<uid>/
cat /var/log/pods/<ns>_<pod>_<uid>/<container>/0.log
日志轮转后的文件是 0.log.20261105-...,crictl logs 读不到历史轮转文件。
7.3 镜像拉不下来
crictl pull registry.example.com/app:1.2.3
# 报错直接看原因:认证、网络、证书
crictl images | grep app
节点上拉取成功但 Pod 仍失败 → 检查 imagePullSecrets、kubelet 的 registry 配置(/etc/containerd/config.toml 的 registry.mirrors)。
7.4 清理节点磁盘
crictl rmi --prune # 清理未使用镜像
crictl images | wc -l
du -sh /var/lib/containerd/
journalctl -u kubelet --since '-1h' | grep -i 'imageGC\|evict'
K8s 有镜像回收阈值(imageGCHighThresholdPercent),配置不当会撑满磁盘。
7.5 在节点上临时起一个调试容器
nerdctl run -it --rm --network host nicolaka/netshoot
# 或直接共享故障容器的命名空间
nerdctl run -it --rm --net container:<容器ID> nicolaka/netshoot
8. 常见坑
crictl ps看不到容器:默认只看运行中,加-a。- endpoint 不对:报
connect: no such file or directory,检查/etc/crictl.yaml或--runtime-endpoint。 crictl与 K8s 版本不匹配:会提示版本偏差,尽量用与集群同小版本的 crictl。nerdctl ps看不到 K8s 容器:必须在k8s.io命名空间(-n k8s.io)。crictl rm后 Pod 状态错乱:kubelet 会重建,但如果删的是沙箱,可能留下"幽灵 Pod",用kubectl delete pod --force --grace-period=0清理。crictl logs无输出:容器日志驱动不是json-file(如 journald),改用journalctl -u containerd或看/var/log/pods。- 容器 ID 前缀冲突:给长一点。
- CRI-O 与 containerd 命令相同但行为细节不同:日志路径、inspect 字段有差异。
- 节点上有 docker 又有 containerd:不要混用,K8s 用的是 containerd,
docker ps看到的是另一套。 - 权限:
crictl需要 root 或 docker 组成员。 nerdctl build需要 buildkit:未启用会报错,nerdctl build --buildkit-host或装buildkit。- 不要在节点上手改容器配置文件:kubelet 会覆盖,改动应通过 ConfigMap/Deployment。
9. 速查表
# crictl
crictl ps / ps -a
crictl pods --name <kw>
crictl logs -f --tail 100 <id>
crictl exec -it <id> sh
crictl inspect <id> | jq '.status'
crictl images / pull / rmi --prune
crictl stats
crictl info
# nerdctl
nerdctl -n k8s.io ps -a
nerdctl compose up -d
nerdctl run -it --rm --network host nicolaka/netshoot
nerdctl system df
# 日志文件
/var/log/pods/<ns>_<pod>_<uid>/<container>/0.log
排查顺序:kubectl describe 看 Events → 节点上 crictl ps -a 看状态 → crictl logs 看日志 → crictl inspect 看退出码。