执行docker stop命令能否安全关闭容器内的mongod进程?
结论
执行docker stop命令不能安全关闭当前配置下的mongod进程,存在数据损坏、脏数据残留的风险。
核心原因
docker stop的默认信号逻辑:只会向容器内PID为1的进程发送SIGTERM信号,等待默认10秒超时后如果进程未退出,就会发送SIGKILL强制销毁容器内所有进程。- 当前容器内PID 1是执行noauth.sh脚本的
sh进程,不是mongod:启动mongod时加了--fork参数,该参数会让mongod以守护进程模式运行,fork出子进程后父shell会进入等待状态,最终mongod运行在PID 9的位置,不具备直接接收docker发送信号的资格。 - 普通shell作为PID 1进程时,默认不会把收到的SIGTERM信号转发给它启动的子进程:也就是说发送给PID 1 sh进程的终止信号,根本不会传递到PID 9的mongod,mongod收不到需要正常关闭的通知。
- 超时后docker会直接强杀所有进程:mongod没有机会执行内存数据刷盘、关闭连接、清理预写日志等安全退出流程,相当于直接断电关闭数据库。
修复方案
可选择任意一种调整方式实现安全关闭:
- 去掉mongod启动参数里的
--fork,让mongod以前台模式运行,直接作为PID 1进程存在
修改noauth.sh的最后一行,移除--fork参数即可:
调整后脚本启动mongod时会被mongod进程占据前台,不会退出,mongod自然成为PID 1,可直接收到SIGTERM信号执行安全关闭流程。/home/mongo/mongo_server/bin/mongod --shardsvr --dbpath /home/mongo/mongo_data/ --bind_ip 0.0.0.0 --port $1 - 如果必须保留fork模式,需要在脚本中添加信号捕获转发逻辑,让PID 1的shell收到SIGTERM时主动把信号发给mongod,等mongod退出后再结束脚本:
#!/bin/bash if [ ! -d /home/mongo/mongo_data/data_$2/ ];then mkdir -p /home/mongo/mongo_data/ fi # 启动fork模式的mongod /home/mongo/mongo_server/bin/mongod --shardsvr --fork --dbpath /home/mongo/mongo_data/ --bind_ip 0.0.0.0 --port $1 # 捕获SIGTERM信号,转发给mongod进程并等待其正常退出 term_handler() { kill -SIGTERM $(pidof mongod) wait $(pidof mongod) exit 0 } trap 'term_handler' SIGTERM # 前台阻塞等待子进程信号 wait - 也可以引入
tini这类轻量init进程作为PID 1,自动完成信号转发和僵尸进程回收,不过这种方式需要额外在自定义镜像中安装tini、修改启动入口,操作相对繁琐。
验证方法:执行
docker stop后查看MongoDB运行日志,如果没有出现shutdown complete的日志行,就说明mongod是被强制杀死的,没有走正常关闭流程。
内容的提问来源于stack exchange,提问作者AlanBlue
相关产品推荐
相关产品推荐

