crictl / nerdctl —— K8s 节点上的容器排查

运维工具手册 06-容器与编排 6.2 KB 原文

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. 常见坑

  1. crictl ps 看不到容器:默认只看运行中,加 -a。
  2. endpoint 不对:报 connect: no such file or directory,检查 /etc/crictl.yaml 或 --runtime-endpoint。
  3. crictl 与 K8s 版本不匹配:会提示版本偏差,尽量用与集群同小版本的 crictl。
  4. nerdctl ps 看不到 K8s 容器:必须在 k8s.io 命名空间(-n k8s.io)。
  5. crictl rm 后 Pod 状态错乱:kubelet 会重建,但如果删的是沙箱,可能留下"幽灵 Pod",用 kubectl delete pod --force --grace-period=0 清理。
  6. crictl logs 无输出:容器日志驱动不是 json-file(如 journald),改用 journalctl -u containerd 或看 /var/log/pods。
  7. 容器 ID 前缀冲突:给长一点。
  8. CRI-O 与 containerd 命令相同但行为细节不同:日志路径、inspect 字段有差异。
  9. 节点上有 docker 又有 containerd:不要混用,K8s 用的是 containerd,docker ps 看到的是另一套。
  10. 权限:crictl 需要 root 或 docker 组成员。
  11. nerdctl build 需要 buildkit:未启用会报错,nerdctl build --buildkit-host 或装 buildkit。
  12. 不要在节点上手改容器配置文件: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 看退出码。