由来
起初是 k8s 有几个 node not ready,上去看了下 kubelet 日志刷 container runtime down,重启了下 docker 后还是没用,docker ps 命令都卡住。
环境信息
1 | cat /etc/redhat-release |
排查过程
先停掉docker,然后前台启动加 debug 参数启动
1 | pgrep dockerd |
然后发现卡在这,正常是会像 gin 那样启动输出支持的 http api 路由信息的。开一个窗口,发送 SIGUSR1 信号打印 goroutine 堆栈信息看看卡在哪儿:
1 | pgrep dockerd |
docker 的日志和系统日志都会有下面的类似输出:
1 | Dec 04 22:33:52 xxxx dockerd[3085]: time="2020-12-33T58:15:52.906433650+08:00" level=info msg="goroutine stacks written to /var/run/docker/goroutine-stacks-2020-12-04T223358+0800.log" |
查看了下下面这段比较可疑,daemon/daemon.go:364
附近
1 | goroutine 1 [semacquire, 5 minutes]: |
按照docker info 的信息去找了下对应的 分支代码。364 行一个wg.Wait()
,得看前面的 goroutine 是卡在哪儿,根据前面的堆栈信息,应该是卡在 github.com/docker/docker/daemon.(*Daemon).restore
,也就是 238 行的 daemon.containerd.Restore 方法,卡在wg.Wait()
说明有协程没释放锁,这里containerd.Restore方法的第一行就是锁,里面有个方法c.remote.LoadContainer
,实际上是和docker-containerd通信的。
查看下 docker-containerd 进程:
1 | $ ps aux | grep containerd |
有残留的,杀掉一个试试
1 | kill 11171 |
然后原窗口有输出了一些日志,实际上是执行了 244行的 daemon.containerd.DeleteTask方法,说明思路是对的,进程通信有问题。
1 | ERRO[0172] connecting to shim error=<nil> id=73cfe941e7a948a77783c77f963efc66327323c2603e058e7ab61f85f8e98212 module="containerd/io.containerd.runtime.v1.linux" namespace=moby |
接着处理另一个:
1 | ps aux | grep containerd |
然后前台 debug 的日志没有卡住,正常启动了:
1 | ERRO[0249] connecting to shim error=<nil> id=62b049d16d1fe03c193295329e7055b3e675a5e94b9566eee6accc35820530be module="containerd/io.containerd.runtime.v1.linux" namespace=moby |
服务器上有安全狗,可能和安全狗有关系。