背景
起因是,docker 中运行的某个服务 CPU 飙高导致宿主机卡死,不得不强制重启。重启后,发现 docker 无法启动。通过 journalctl -xe 观察日志发现,报"volume store metadata database: timeout"的错误。
在经过漫长的百度之后,发现网上的解决方法只有文章:https://www.coder.work/article/42776 中的解决方法。而这个解决方法是来自 GitHub:https://github.com/moby/moby/issues/22507 的 issue。
解决方法中告诉我,使用命令:
ps axf | grep docker | grep -v grep | awk '{print "kill -9 " $1}' | sudo sh
即可解决问题。
然而,我用命令:
ps -aux | grep docker
发现,我特喵根本没有 docker 在运行好吗???
中间也尝试过在 StackOverFlow 上面的解决方法:https://stackoverflow.com/questions/43537790/
即,将 volume 文件夹下的 metadata.db 文件复制到 metadata.db.bak 进行备份。之后再重启 docker。
然而,我执行 systemctl start docker 后,发现,这玩意运行了两三天,依然处于 activating 状态!显然这也不是问题的终极解决方法。
问题解决:
在尝试了众多网上的方法无果后,我开始自己思考如何解决该问题。
首先,既然网上有人提出,用 kill 命令杀掉 docker 进程可以解决问题,那是否意味着,docker 根目录中的文件正在被某些进程占用呢?
顺着这条思路,我进一步思考。假如我是用 cp -r 命令,将 docker 根目录重新拷贝一份,然后把原 docker 根目录 mv 到新的备份。然后,把通过 cp 命令拷贝过来的目录作为新的 docker 根目录,是不是就可以将原来认为是处在被某个进程占用状态的文件恢复到正常状态?
于是我执行了如下几条命令:
cp -r DOCKER_ROOT/ DOCKER_ROOT_bak/
mv DOCKER_ROOT/ DOCKER_ROOT_timestamp_bak/
mv DOCKER_ROOT_bak/ DOCKER_ROOT/
systemctl start docker
在执行完以上命令后,发现,docker 居然真的跑起来了!再使用:
docker images
docker ps -a
命令。发现,docker 原有的容器、镜像都还在!
可喜可贺,通过这种解决方式真的能解决!
反思:
通过如上解决的过程,我反思了一下为什么会这样。
原因大概是:在 docker 容器中的进程CPU飙高,占满宿主机资源,之后只能强制重启来杀掉进程。然而强制重启后,原有进程在 linux 中 docker 相应文件夹下的文件描述符依然还在,这就导致 docker 在宿主机重启后启动时,认为文件被占用,于是无法启动。
网上的解决思路就是杀掉原有 docker 进程,即可启动新进程。然而,在宿主机宕机的情况下,不存在原有 docker 进程,因此只能通过 cp 的方式,将原有 docker 根目录复制到新目录下,才能解决文件被占用的问题。
附录:
docker 根目录一般在:
/var/lib/docker
目录下。