容器跑着跑着没反应了,容器日志第一件事就是命令看日志。Docker 查看容器日志的容器日志核心命令就一个:docker logs。别小看它,命令参数用对了能省很多时间。容器日志
最基本的命令用法是 docker logs 容器ID或名称。比如你有个容器叫 web-app,容器日志直接 docker logs web-app,命令它会把容器启动以来所有写到 stdout 和 stderr 的容器日志内容全部打印出来。注意,命令是容器日志全部。如果容器跑了三天,命令日志量可能直接刷屏,容器日志终端滚半天都滚不到头。命令我一般会先加 --tail 控制一下。容器日志
docker logs --tail 100 web-app 只看最后 100 行。这个参数很实用,排查最近一次报错时基本够用。--tail 0 表示不看历史,只等新日志,配合 -f 用效果最好。
-f 就是 follow,跟 tail -f 一个意思。容器还在跑的时候,你想实时盯着输出,就 docker logs -f web-app。终端会挂在那里,有新日志就冒出来。按 Ctrl+C 退出,容器不受影响。我调试定时任务时经常这么干,挂着去干别的,出问题切回来就能看到。
时间过滤也很有用。--since 和 --until 接受两种格式:一种是相对时间,比如 --since 10m 表示最近十分钟,--since 1h 是最近一小时;另一种是绝对时间戳,像 --since 2024-01-15T10:00:00。这两个参数可以组合,比如查昨天下午两点到四点的日志:docker logs --since 2024-01-14T14:00:00 --until 2024-01-14T16:00:00 web-app。有一次线上接口突然大量超时,我就是用这个方式把故障时间窗口的日志单独拉出来,很快定位到是下游数据库连接池被打满了。
默认情况下 docker logs 同时输出 stdout 和 stderr。如果你只想看错误流,加 -t 没用,那个是加时间戳的。要分离流,得在容器启动时做文章,或者用 docker logs 2>/dev/null 这种 shell 重定向,不过它分不清哪行来自哪个流。更靠谱的做法是容器里把错误写到单独文件,然后 docker exec 进去看。
说到 -t,加上它每行日志前面会带 RFC3339 格式的时间戳。排查时序问题时很有必要,尤其是多个服务日志混在一起看的时候。但要注意,时间戳是 Docker 收到日志的时间,不是应用自己打的时间。两者可能有毫秒级偏差,一般不影响判断。
还有个细节:docker logs 只能看 json-file 或 journald 日志驱动下的日志。如果容器启动时用了 --log-driver=none,那就什么都看不到。另外,日志文件默认存在 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log,磁盘满的时候记得来这里清理。我习惯在 docker run 时加上 --log-opt max-size=10m --log-opt max-file=3,防止单个容器日志把磁盘写爆。
组合使用才是日常。比如实时看最近五分钟的日志并带时间戳:docker logs --since 5m -t -f web-app。再比如只看最后 50 行且不跟随:docker logs --tail 50 web-app。这些命令敲多了自然就记住,不用死记硬背。
最后提一句,docker logs 看的是容器主进程的输出。如果应用把日志写进了容器内的文件而不是 stdout,这个命令就无能为力了。这时候要么改应用配置输出到控制台,要么 docker exec 进去 cat 或者 tail。所以容器化应用的最佳实践之一,就是日志直接打给 stdout/stderr,剩下的交给 Docker 和日志驱动去处理。