适用:使用 systemd 的 Linux 服务器、常规 rootful Docker Engine;Compose 示例使用
docker composeV2。本文为教学故障场景,错误文本和结果为示意,具体输出以现场为准。
一、遭遇情况:加了日志配置,Docker 反而起不来
运维人员为限制容器日志大小,编辑 /etc/docker/daemon.json 后重启 Docker,结果收到:
Job for docker.service failed because the control process exited with error code.
这条消息只说明服务启动失败,没有告诉你根因。本篇设定的直接原因是 JSON 最后一个字段后多写了逗号。实际现场还可能是配置项拼错,或者 hosts 同时出现在配置文件和启动参数中。
二、原因分析:有三层不同的“配置正确”
第一层,文件是合法 JSON;第二层,字段名称与值能被当前 Docker 版本接受;第三层,文件与 systemd 实际启动参数不冲突。通过 python3 -m json.tool,不代表后两层也通过。

JSON 不支持随意加注释,也不接受末尾多余逗号。日志参数中某些数字还必须以字符串传入,例如 "max-file": "3"。复制网上配置时,应理解每个字段,而不是把多段 JSON 原样拼在一起。
三、排查思路:找到第一条具体错误
1. 读取服务日志和实际启动命令
sudo systemctl status docker --no-pager -l
sudo journalctl -u docker -b -n 120 --no-pager
sudo systemctl cat docker
重点寻找 invalid character、unknown-option 或 specified both as a flag and in the configuration file 一类具体线索。错误文本随版本不同,关键词只用于帮助定位。
Start request repeated too quickly 可能只是多次失败后触发限流,并不是最初原因。往前阅读日志,别停在最后一行。
2. 分别验证文件格式和 Docker 配置
sudo python3 -m json.tool /etc/docker/daemon.json
sudo dockerd --validate --config-file=/etc/docker/daemon.json
前提是服务器有 Python 3,当前 dockerd 支持 --validate,可先用 dockerd --help 确认。校验模式不启动第二个长期运行的 daemon。不要为了试配置,直接再执行一次普通 dockerd 与 systemd 服务争用同一数据目录。
单独校验文件不一定发现 systemd 命令行冲突,所以仍然要对照 systemctl cat docker。例如服务中已经有 -H fd://,再在文件里设置 hosts,就可能导致重复配置。
四、修复实践:保留原文件,只改有证据的问题
先留一份当前配置,便于对比和回退:
sudo cp -a /etc/docker/daemon.json /etc/docker/daemon.json.before-fix
sudoedit /etc/docker/daemon.json
备份文件名若已存在,换一个带时间的名称,避免覆盖旧证据。本案例修正后的日志配置片段如下:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
这是一个最小完整示例,不代表可以覆盖服务器原有的镜像仓库、代理和数据目录配置。实际修复是在原配置上去掉错误逗号,并合并必要字段。
如果日志明确指出 hosts 冲突,而这台服务器并不需要自定义监听地址,可考虑移除误加的 hosts 字段,保留现有 systemd 管理的入口。不要为了绕开冲突顺手开启未受保护的 TCP Docker API。
完成校验后,在已确认的维护窗口恢复服务:
sudo dockerd --validate --config-file=/etc/docker/daemon.json
sudo systemctl reset-failed docker
sudo systemctl start docker
sudo systemctl is-active docker
reset-failed 只是清除失败状态与启动限流记录,不能修复配置。只修改 daemon.json 不需要 systemctl daemon-reload;修改了 systemd unit 或 drop-in 才需要重新加载 systemd 配置。
五、验证与回退:不要只看 active
sudo docker info --format 'LoggingDriver={{.LoggingDriver}} Root={{.DockerRootDir}}'
sudo docker ps -a
sudo journalctl -u docker --since '10 minutes ago' --no-pager
确认数据目录没变、原容器存在、没有新的启动错误。新的日志默认设置主要影响之后创建的容器;已有容器不会自动采用新轮转参数,第 11 篇会给出验证方法。
若修复后仍失败,比较修改前后的配置,恢复此前确认可用的版本,再次校验后启动。不要把 {} 当作通用回退方案,否则可能丢掉必要的 data-root 等设置,让服务器看起来“容器全没了”。
六、总结:让变更先通过校验,再进入服务
这起故障的关键不是“重启了几次”,而是把配置格式、Docker 字段和实际启动参数分开验证。日常变更流程可以固定为:备份 → 最小修改 → 校验 → 受控恢复 → 核对业务。把这一流程做好,很多启动事故就能在重启之前被发现。