跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Linux containerd 的 shim 与 runc 的 OCI 运行时调试方法

查 containerd shim 卡住需先用 ps 找 PID,再通过 ls -l /proc//fd/ 检查残留 fd,最后用 strace -p 观察阻塞在 wait4/epoll_wait/recvfrom;若 runc 已退出但 shim 仍持 socket,需手动清理对应 runtime 目录。 containerd shim 进程卡住,怎么查它在等什么? shim 进程本身不执行容器,只做 containerd 和 runc 之间的“传话员”;它卡住,通常不是 shim 本身坏了,而是它在等
runc
返回、或等容器进程退出、或等 cgroup 状态就绪。最直接的判断方式是看它的子进程和状态: 用
ps -o pid,ppid,comm,state -C containerd-shim
找出卡住的 shim PID 用
ls -l /proc//fd/
看它是否还持着
initctl
或
console-socket
的 fd(常见于容器没正确 detach) 用
strace -p
观察最后阻塞在哪个系统调用(通常是
wait4
、
epoll_wait
或
recvfrom
) 如果
shim
持有
runc
的 socket 连接但
runc
已退出,说明 runc 崩溃后没清理 socket,需手动 kill 并清理
/run/containerd/io.containerd.runtime.v2.task///
下残留目录 runc exec 进入容器失败,报 “no such process” 或 “container not running” 这不是权限或路径问题,而是
runc
查找容器状态时依赖
state.json
文件,而这个文件由 shim 维护——如果 shim 挂了但容器进程还在,
runc exec
就会找不到合法状态。关键点在于:runc 不直接跟内核打交道,它只读
/run/containerd/io.containerd.runtime.v2.task///state.json
,并据此生成
exec.fifo
和绑定到容器 init 进程的
stdin/stdout/stderr
。 先确认容器是否真在跑:
ps -eo pid,ppid,comm,args | grep
检查
state.json
是否存在且
"status": "running"
;若文件损坏或 status 是
created
,说明 shim 没完成启动流程
runc exec
必须指定
--pid-file
或通过
--root
指向正确的 runc root(默认
/var/run/runc
),否则会去错地方找 state 不要用
runc --root /run/containerd/runc/ exec ...
直接操作——containerd v2 runtime 要求 runc 使用自己的 bundle layout,路径必须匹配 shim 创建时的
bundle
字段 调试 OCI runtime 时,如何让 runc 输出详细日志?
runc
默认静默,但它的日志开关不在命令行参数里,而在环境变量和配置中。真正生效的是
RUNC_LOG
+
RUNC_LOG_LEVEL
,且仅当 runc 编译时启用了 debug 支持(主流发行版包通常关闭了)。 Docker Desktop(linux) 当前 Docker 最新稳定版本之一,主要针对稳定性和兼容性进行了修复优化,适合生产环境与日常开发使用。该版本继续强化 AI 开发支持、容器日志管理以及 Docker Engine 的安全能力,对 Windows/macOS/Linux 平台兼容性进行了进一步优化。 下载 临时启用:运行前加
RUNC_LOG=/tmp/runc.log RUNC_LOG_LEVEL=debug runc --debug run -b
--debug
参数必须显式带上,否则
RUNC_LOG
被忽略 注意日志路径需 shim 进程有写权限(比如 containerd 启动 shim 时用的是
containerd
用户,不是 root) 如果看到
failed to load OCI config: invalid character
,大概率是
config.json
里多了注释或用了 tab 缩进——OCI spec 严格要求纯 JSON,不能有注释、尾逗号、tab containerd 重启后容器消失,但 runc list 还能看到? 这是典型的生命周期管理错位:
runc list
只扫
/var/run/runc
下的 state 文件,而 containerd v2 runtime 把容器状态存在
/run/containerd/io.containerd.runtime.v2.task///state.json
,两者完全不互通。runc 看到的是“孤儿容器”,containerd 认为它们已丢失。 不要直接
runc delete
这些容器——可能残留 cgroup、网络命名空间、mount ns,导致后续创建失败 正确做法是先用
containerd-stress cleanup
(如安装了 containerd-devel 包),或手动清理:
find /run/containerd/io.containerd.runtime.v2.task -name state.json -exec dirname {} \; | xargs -r rm -rf
更稳妥的是启用 containerd 的
oom_score_adj
和
reclaimable
配置,避免因 OOM 导致 shim 异常退出却不通知 containerd 所有生产环境务必开启
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
中的
SystemdCgroup = true
,否则 cgroup v2 下 runc 和 containerd 对 cgroup 路径解析不一致,重启后状态无法对齐 OCI runtime 调试真正的难点不在命令怎么敲,而在于每个组件只认自己那一小段契约:shim 信 state.json,runc 信 bundle 目录结构,containerd 信 shim 的 gRPC 响应。一旦其中一环状态没同步(比如 shim panic 但没删 state.json),整个链就断成两截,得靠交叉验证才能定位真实断点。

相关文章