排查容器问题时,docker logs 是第一步操作。但当它什么也不输出——或者只有一两行无关信息——你该怎么判断容器到底正不正常?
一次真实的排查经历
有次检查 MQTT 服务器(mosquitto)的健康状态,习惯性执行:
docker logs mosquitto
输出只有一行反复出现的 Loading config file。没有设备连接记录,没有版本信息,没有错误——几乎是空的。
第一反应是容器可能出问题了。但 docker ps 显示 Up 2 weeks,端口 1883 和 1884 都在监听,从外部连接测试也返回了正常的 CONNACK。容器明明在跑,为什么没有日志?
根因:日志写到了文件,而不是标准输出
进入容器查配置文件,发现了关键一行:
log_dest file /mosquitto/config/log/mosquitto.log
mosquitto 被配置为把日志写入文件,而不是标准输出。这意味着所有日志信息都走文件,根本不会经过 stdout/stderr——而 docker logs 只捕获 stdout 和 stderr。

这是很多人不知道的一个事实:docker logs 为空,不代表容器没有日志,只是日志不在标准输出上。
类似的情况很常见。Nginx 默认写 access.log 和 error.log 到文件;Java 应用用 log4j/logback 配置文件输出;很多 Docker 镜像的默认配置就是写文件日志。如果你只看 docker logs,可能什么都看不到。
四步排查法
遇到 docker logs 没输出,按这个顺序排查:
Step 1:确认容器确实在跑
# 容器状态
docker ps -a --filter name=<container>
# 进程和端口
docker exec <container> ps aux
docker exec <container> netstat -tlnp
容器状态是 Up、端口在监听,说明容器本身没问题。
Step 2:查应用的日志配置
这是关键一步——看应用把日志写到了哪里。
# 查看容器挂载点(找到配置和日志文件的位置)
docker inspect <container> --format '{{json .Mounts}}' | python3 -m json.tool
# 进入容器查日志配置
docker exec <container> grep -r "log" /etc/ 2>/dev/null
docker exec <container> cat /path/to/config/app.conf
常见的日志配置关键词:log_dest(mosquitto)、access_log/error_log(Nginx)、logging.file(Spring Boot)、LOG_FILE(环境变量)。
Step 3:读文件日志
找到日志文件路径后,直接读:
# 查看日志文件
docker exec <container> ls -la /path/to/logs/
docker exec <container> tail -100 /path/to/logs/app.log
# 实时跟踪
docker exec <container> tail -f /path/to/logs/app.log

如果文件日志也有问题(比如停写了),继续下一步。
Step 4:验证功能是否正常
日志不可靠的时候,直接测试功能:
# 端口连通性
docker exec <container> netstat -tlnp
# 从外部连接测试(以 MQTT 为例)
docker run --rm eclipse-mosquitto mosquitto_pub -h <host> -t test -m "hello"
这次排查中,文件日志因为 epoll 错误也停写了——日志文件最后更新是两年前。但通过端口和连接测试,确认 MQTT broker 实际上在正常工作。
常见原因速查表
| 原因 | 识别方法 | 处理方式 |
|---|---|---|
| 应用写文件日志 | 检查配置中 log_dest/log.file/log4j 等 |
读文件日志,或改配置加 stdout |
| 日志驱动不是 json-file | docker inspect --format '{{.HostConfig.LogConfig.Type}}' |
改为 json-file 或 journald |
| 日志被截断/轮转 | docker inspect --format '{{.HostConfig.LogConfig.Config}}' |
增大 max-size/max-file |
| 容器启动后异常退出 | docker ps -a 看状态 |
看 docker logs 的启动阶段输出 |
| stdout/stderr 被重定向 | docker exec <c> cat /proc/1/fd/1 |
检查 ENTRYPOINT/CMD 中是否有重定向 |
踩坑记录
密码不要猜。这次排查中猜了 10 分钟 MQTT 密码都连不上。实际上凭据存在 Home Assistant 的配置文件 .storage/core.config_entries 里,直接读就行。
mosquitto 不会热加载密码文件。用 mosquitto_passwd 添加用户后,运行中的 broker 不会自动识别,需要重启容器才生效。
docker exec 的路径是容器内的。在宿主机用 heredoc 传命令给 docker exec 时,路径是容器内的,不是宿主机的。
最佳实践
Docker 容器应优先把日志输出到 stdout/stderr,这是 12-Factor App 的日志原则,也是 Docker 的设计意图。stdout 日志可以被 docker logs、日志收集器(Fluentd、Loki)统一采集,不用挨个容器找日志文件。
如果应用必须写文件日志(比如需要按天轮转),至少同时输出一份到 stdout。Nginx 可以这样配:
# 同时写文件和 stdout
access_log /var/log/nginx/access.log;
access_log /dev/stdout;
error_log /var/log/nginx/error.log;
error_log /dev/stderr;
或者用 tail -f 在启动脚本中把文件日志转发到 stdout:
# Dockerfile 中
CMD ["sh", "-c", "tail -F /var/log/app.log & ./app"]
总结
docker logs 为空不等于容器没日志。大多数情况是应用把日志写到了文件,而 docker logs 只看 stdout/stderr。遇到空输出,先查应用日志配置,再读文件日志,最后用功能测试确认容器是否正常。不要被表象迷惑——日志配置才是根因。