systemd杀不掉docker daemon的根本原因是dockerd忽略SIGTERM且子进程未纳入同一cgroup;关键service配置包括Type=notify、KillMode=control-group、KillSignal=SIGQUIT、Restart=always等。

systemd 为什么杀不掉 docker daemon 进程
常见现象是执行 systemctl stop docker 后,dockerd 进程还在,甚至容器照常运行。根本原因在于 systemd 默认按 kill -TERM 发信号,而 dockerd 主动忽略 SIGTERM(它只响应 SIGHUP 或 SIGUSR1 做热重载),且其子进程(如 containerd、runc)未被纳入同一 cgroup,systemd 无法递归清理。
实操建议:
- 确认 dockerd 启动时是否加了
--init或通过dockerd --no-new-privileges等参数干扰进程树归属 - 检查
/etc/docker/daemon.json是否配置了"live-restore": true—— 开启后 dockerd 收到SIGTERM直接忽略,必须关掉才能让 systemd 正常 stop - 临时修复:在 service 文件里加
KillMode=control-group和KillSignal=SIGQUIT,强制终结整个 cgroup
docker.service 文件里哪些字段最关键
不是所有默认生成的 docker.service 都可靠,尤其自建或升级后容易漏掉关键控制项。核心是让 systemd 能感知 dockerd 的生命周期,而不是“启动完就放手”。
实操建议:
- 必须设
Type=notify:dockerd 启动后会调用sd_notify("READY=1"),systemd 才认为服务真正就绪;否则systemctl start docker可能立刻返回,但实际 daemon 还没 bind socket - 务必配
Restart=always+RestartSec=5:避免因 OOM 或 panic 导致 dockerd 意外退出后无人拉起 - 禁用
StartLimitIntervalSec或设宽松值(如600):否则连续 crash 三次后 systemd 会永久拒启,掩盖真实问题 - 示例片段:
[Service] Type=notify KillMode=control-group KillSignal=SIGQUIT Restart=always RestartSec=5 StartLimitIntervalSec=600
docker daemon 启动失败但 journal 里没报错
典型表现:systemctl status docker 显示 failed,但 journalctl -u docker 只有 “Started Docker Application Container Engine”,没后续日志。本质是 dockerd 在 notify systemd 前就崩溃了,systemd 根本收不到失败通知,日志断在起点。
实操建议:
- 先绕过 systemd 直接跑:
sudo dockerd --debug --log-level=debug,看终端输出哪行卡住或 panic - 重点排查
/var/run/docker.sock权限(需属主root:docker)、/etc/docker/daemon.jsonJSON 格式错误、存储驱动不匹配(如 ext4 上启用了overlay2却没开启 d_type 支持) - 若用 systemd-run 临时测试,加
--scope --collect参数,确保崩溃时仍留 core dump
containerd 进程脱离 docker 管理怎么办
docker 20.10+ 默认内嵌 containerd,但若手动装过独立 containerd、或升级不干净,可能出现两个 containerd 进程:一个由 systemd 管理(containerd.service),另一个被 dockerd fork 出来却未挂入 cgroup。结果是 systemctl stop docker 后,containerd 还在,下次 start docker 时端口冲突或状态混乱。
实操建议:
- 查进程树:
ps auxf | grep containerd,确认是否有非/usr/bin/containerd路径的实例(比如/usr/local/bin/containerd) - 停掉所有 containerd:
sudo systemctl stop containerd,再删掉/var/run/containerd和/var/lib/containerd(注意备份镜像元数据) - 确保
/etc/docker/daemon.json中没写"containerd": "/path/to/other/containerd.sock"—— 这会让 dockerd 复用外部 containerd,破坏一体化管理
DockerDaemon 和 systemd 的边界其实很薄:它既不是传统守护进程,也不是完全符合 systemd 规范的现代服务。最容易被忽略的是 Type=notify 和 live-restore 的互斥性——开一个,另一个就失效,而错误日志往往藏在 silent crash 里。










