最近在一个Kubernetes集群部署 Rook-Ceph 时遇到了一个问题:OSD Pod 的主容器能正常启动,但 sidecar 容器却一直报 RunContainerError。折腾了一番,最后发现是节点上装的终端安全软件导致的。
问题现象
部署完成后检查 Pod 状态,发现 node-1 上有几个 Pod 异常:
kubectl get po -n rook-ceph -o wide | grep -v Running
NAME READY STATUS RESTARTS AGE
rook-ceph-osd-2-5bfd79754f-k8smh 0/2 RunContainerError 0 3m14s
rook-ceph-tools-8bd944548-gh29z 0/1 RunContainerError 223 26h查看 Pod 事件,得到的错误信息是:
Warning Failed Error: context deadline exceeded
Message: failed to create containerd task: failed to create shim task: context canceled: unknown奇怪的是,同样的镜像、同样的配置,node-2 和 node-3 上的 Pod 都正常,唯独 node-1 出问题。更奇怪的是 OSD Pod 的主容器 osd 能正常启动并进入 active 状态,但 log-collector 这个 sidecar 容器就是起不来。
排查过程
首先查看了 containerd 的日志:
journalctl -u containerd --since "10 minutes ago" | grep -i error日志里都是超时错误:
level=error msg="StartContainer for xxx failed" error="failed to create containerd task: failed to create shim task: context deadline exceeded: unknown"containerd 报超时,说明某个环节卡住了。为了缩小排查范围,绕过 Kubernetes 直接用 ctr 测试容器启动,发现普通容器能正常跑起来。
这时候注意到 rook-ceph-tools 这个 Pod 也一直起不来,看了一眼它的配置,发现设置了 tty: true。再想想 log-collector 的启动命令是 /bin/bash -m,-m 参数会启用 job control,也涉及 TTY 操作。会不会是 TTY 相关的问题?
试了一下带 --tty 参数启动容器:
# 普通容器 - 正常
ctr -n k8s.io run --rm registry.example.com/ceph/ceph:v19.2.0 test echo hello
# 输出: hello
# 带 TTY 的容器 - 卡住
ctr -n k8s.io run --rm --tty registry.example.com/ceph/ceph:v19.2.0 test-tty /bin/bash -c "echo hello"
# 无响应果然卡住了。在 node-2 上执行同样的命令,完全正常。问题锁定在 node-1 这台机器上。
既然进程卡住了,那就看看它卡在哪。找到了卡住的 runc init 进程,查看其内核调用栈:
cat /proc/<PID>/stack输出如下:
[<0>] wait_woken+0x50/0x60
[<0>] n_tty_read+0x569/0x630
[<0>] tty_read+0x121/0x250
[<0>] jt_get_file_buffer+0x8d/0xc0 [resguard_linux]
[<0>] se_check_close_post+0x14d/0xd60 [resguard_linux]
[<0>] filter_close_post+0x1fc/0x240 [resguard_linux]
[<0>] hook_x64_sys_call+0x9e/0xd0 [syshook_linux]调用栈里出现了 resguard_linux 和 syshook_linux 这两个内核模块。一看名字就猜出是安全软件加载的。进程卡在 TTY 相关的系统调用上,而这些调用被安全模块拦截了。
对比了 node-1 和 node-2 的内核模块:
# node-1
lsmod | grep -E "resguard|syshook"
resguard_linux 643072 2
syshook_linux 135168 1
# node-2
lsmod | grep -E "resguard|syshook"
# (无输出)果然,node-1 上装了某终端安全软件,而其他两个节点没有。
原因分析
该安全软件通过内核模块 hook 系统调用来实现安全防护。syshook_linux 负责拦截系统调用,resguard_linux 则实现具体的安全检测逻辑。这种 TTY 拦截机制通常用于防止反弹 Shell 攻击、审计终端操作等场景。
问题在于,容器运行时需要为某些容器分配 PTY。当容器配置了 tty: true,或者启动命令需要 job control 时,containerd 会尝试分配伪终端。安全软件的内核模块拦截了这个过程,导致操作阻塞,最终 containerd shim 等待超时。
回过头看受影响的容器:log-collector 的启动命令是 /bin/bash -m,-m 参数启用 job control,需要进行 TTY 操作;rook-ceph-tools 则直接在 spec 里配置了 tty: true。这就解释了为什么它们会卡住。
解决方案
经过查看,找到了这个安全软件有自带的卸载脚本,可以直接用:
/usr/local/wsssr_defence_agent/uninstall卸载后再次查看:
# 查看模块依赖
lsmod | grep -E "resguard|syshook|secmodel"
# 按顺序卸载(先卸载依赖的模块)
rmmod resguard_linux
rmmod syshook_linux
rmmod secmodel_linux 2>/dev/null
# 验证模块已卸载
lsmod | grep -E "resguard|syshook"重建受影响的 Pod:
kubectl delete pod -n rook-ceph -l osd=2
kubectl delete pod -n rook-ceph -l app=rook-ceph-toolsPod 立刻就能正常启动了。
这次是为了快速恢复服务临时卸载了安全软件,后续还是要联系安全团队,把容器运行时的进程(containerd-shim-runc-v2、runc 等)加入白名单,避免安全防护与容器环境冲突。
总结
这次能快速定位问题,主要靠对比正常和异常节点的差异。发现只有一台节点有问题后,用 ctr run --tty 确认是 TTY 相关的问题,然后看 /proc/<PID>/stack 找到卡在哪,一下就看到安全软件的内核模块了。
说起来,这台节点是后来加的,装了安全软件但其他节点没装,配置不一致才导致这个坑。以后在 K8s 节点上装安全软件之前,还是得先测一下对容器的影响,不然出了问题不好排查。