容器日志默认由json-file驱动写入/var/lib/docker/containers//-json.log,但推荐应用输出到stdout/stderr由docker接管;生产采集应使用支持offset tracking的工具如filebeat或fluentd。

容器日志默认存在哪里?/var/lib/docker/containers 但别直接读
容器日志默认由 json-file 驱动写入宿主机的 /var/lib/docker/containers/<container-id>/<container-id>-json.log</container-id></container-id>,文件名带 -json.log。但这不是推荐采集路径——Docker 可能轮转、压缩或清理它,且多个容器日志混在一起时难以关联服务名。
更稳的做法是让应用把日志输出到 stdout / stderr,由 Docker 守护进程统一接管。只要不显式配置 --log-driver=none 或用 syslog 等外部驱动,就默认走这个路径。
- 检查当前容器日志驱动:
docker inspect <container-name> | jq '.HostConfig.LogConfig.Type'</container-name> - 确认日志是否真在 stdout:运行
docker logs <container-name></container-name>能看到内容,说明没被重定向到文件 - 避免挂载
/var/lib/docker/containers到采集工具里——权限不稳定,Docker 进程可能正在写入,导致文件句柄冲突或截断
docker logs --follow 适合调试,不适合长期采集
用 docker logs --follow <container></container> 看实时日志很顺手,但它本质是调用 Docker API 的 /containers/{id}/logs 接口,每次连接都是新流,不带游标、不保序、无法断点续传。一旦采集进程重启,就会丢掉中间日志。
生产环境必须用支持位置追踪(offset tracking)的方案,比如 fluentd 的 in_tail 插件或 filebeat 的 harvester,它们会记录已读文件的 inode + offset,即使容器重启、日志轮转也能接上。
-
filebeat默认启用close_inactive: 5m,但容器退出后日志文件可能残留,需配close_removed: true防止句柄泄漏 - 若用
tail -F手写脚本采集,遇到日志轮转(copytruncate或rotate)会丢失最后几行,因为tail依赖 inotify,而轮转可能先删后建,触发重监听延迟 - 不要用
cat /path/*.log | ...一次性读取——容器日志是持续追加的,这种做法只能抓快照
用 journalctl -u docker 查不到容器 stdout 日志
journalctl -u docker 只显示 Docker daemon 自身的日志,比如镜像拉取失败、容器启动报错等;容器内应用打到 stdout 的日志不会进入 systemd journal,除非你显式配置了 log-driver=journald 并重启 dockerd。
验证是否生效:运行 docker run --rm alpine echo hello 后执行 journalctl -t docker | grep hello,有输出才说明日志进了 journal。否则查不到,不是命令不对,是驱动没配。
- 修改
/etc/docker/daemon.json加"log-driver": "journald",然后sudo systemctl restart docker - 注意:journald 默认限制单条日志最大 64KB,超长日志会被截断,且 journal 存储位置(
/var/log/journal)可能被 logrotate 清理,需调SystemMaxUse - 如果已有大量容器在跑,改驱动后旧容器仍用原驱动,必须
docker stop && docker start才生效
容器日志时间戳不准?看 docker logs 和应用输出的时区差异
容器内应用打印的时间戳(比如 Python 的 datetime.now())默认用容器本地时区,而 docker logs 输出的外层时间戳是宿主机时区。两者不一致时,你会看到“应用说现在是 14:00,docker logs 却标成 06:00”。
根本原因:Docker 不修改容器内进程的时区设置,也不转换日志内容里的时间字符串。它只给每条日志加一个宿主机时间戳(即日志被写入 -json.log 文件的那一刻)。
- 解决办法一:在容器启动时挂载宿主机时区:
-v /etc/localtime:/etc/localtime:ro,或设环境变量TZ=Asia/Shanghai - 解决办法二:让应用统一输出 UTC 时间,并在采集端做时区转换(如 Logstash 的
datefilter) - 别依赖
docker logs --since做精确时间过滤——它的精度是秒级,且基于宿主机时间戳,和应用日志里的时间字段无关
真正难处理的是多容器共享日志路径、日志格式无结构、或应用自己 fopen 写文件绕过 stdout。这些情况没法靠 Docker 原生机制兜底,得从应用侧改或加 sidecar 容器捕获文件流。










