15.11.3 容器日志与事件诊断
容器日志与事件诊断是定位运行异常的核心手段,应建立“日志标准化、事件可追溯、问题可复现”的闭环流程。生产环境优先将日志统一采集到集中平台,同时保留节点侧快速定位能力,结合容器运行时事件与系统层日志进行关联分析。
原理草图:日志与事件关联路径
1. 日志类型与定位思路
- 业务日志:应用输出(stdout/stderr)与应用内部日志文件,优先检查最近错误、异常堆栈、超时与重试。
- 容器运行时日志:容器启动失败、退出码、重启策略触发。
- 系统日志:内核 OOM、磁盘异常、网络抖动等系统级异常。
- 事件日志:Docker 事件流,定位创建/销毁、拉取镜像失败、健康检查失败。
2. 安装与基础配置(日志轮转)
- 目标:启用 json-file 日志驱动并设置轮转,避免磁盘被占满。
- 文件路径:/etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "5"
}
}
# 使配置生效
systemctl daemon-reload
systemctl restart docker
# 验证日志驱动与轮转参数
docker info | grep -E "Logging Driver|log-opts"
3. 关键命令与示例(含说明)
- 查看容器日志(最近 1 小时,尾部 200 行)
docker logs --since 1h --tail 200 web-app
# 说明:--since 控制时间窗口;--tail 限制行数,避免输出过大
- 查看容器状态与退出码
docker ps -a --filter "name=web-app"
docker inspect web-app | grep -E "State|ExitCode|Error|OOMKilled"
# 说明:ExitCode=0 正常退出;OOMKilled=true 表示被内核杀死
- 订阅事件流(最近 1 小时)
docker events --since 1h --filter container=web-app
# 说明:可定位 create/start/die/pull/health_status 等事件
- 系统层异常(OOM、文件系统错误)
dmesg -T | grep -i -E "oom|killed|ext4|xfs|error"
journalctl -u docker --since "1 hour ago"
# 说明:dmesg 提供内核级异常,journalctl 提供 dockerd 服务日志
4. 典型故障与日志特征 + 排错
- 启动失败:镜像拉取错误、入口命令不存在、依赖未就绪
日志特征:exec: "xxx": executable file not found、pull access denied
# 排错步骤:确认镜像、入口命令与依赖服务
docker inspect web-app | grep -E "Image|Entrypoint|Cmd"
docker pull myrepo/web-app:1.0
- 频繁重启:进程崩溃或健康检查失败
日志特征:ExitCode=1、unhealthy
# 排错步骤:检查健康检查与容器进程
docker inspect web-app | grep -A3 -E "Health|Test"
docker logs --since 10m web-app
- OOM 被杀:内存不足或限制过低
日志特征:OOMKilled=true,系统日志出现Out of memory
# 排错步骤:查看内存限制并调整
docker inspect web-app | grep -E "Memory|OOMKilled"
# 重新运行示例(增加内存限制)
docker run -d --name web-app --memory 512m myrepo/web-app:1.0
- 日志缺失:应用未输出到 stdout/stderr 或日志未挂载到卷
处理:调整应用日志输出策略或配置日志侧车采集
# 示例:将应用日志输出到 stdout
# 假设应用支持 LOG_TO_STDOUT=1
docker run -d --name web-app -e LOG_TO_STDOUT=1 myrepo/web-app:1.0
5. 事件关联分析流程(可复现)
1. 确认时间范围与影响范围(服务、节点、容器数量)。
2. 查看容器退出码与 OOM 标记。
3. 拉取容器日志定位异常语句或栈。
4. 结合 docker events 与系统日志确定触发源。
5. 复现与验证:本地或测试环境复现并修复。
6. 端到端示例:构造异常并定位
- 目标:构造 OOM 事件并完成定位
# 1) 启动一个内存限制很小的容器(busybox)
docker run -d --name oom-test --memory 20m busybox sh -c "x=; while true; do x=$x$(date); done"
# 2) 观察容器状态
docker ps -a --filter "name=oom-test"
docker inspect oom-test | grep -E "OOMKilled|ExitCode"
# 3) 查询系统日志
dmesg -T | tail -n 20
# 预期效果:
# - 容器退出,OOMKilled=true
# - dmesg 中出现 Out of memory
7. 日志采集与保留策略(可执行配置示例)
- 推荐 stdout/stderr 统一输出,避免容器内写临时文件丢失。
- 生产环境设置轮转与大小限制,并配合集中平台(ELK/EFK/Loki)。
# 启动容器时指定日志驱动参数(覆盖全局)
docker run -d --name web-app \
--log-driver json-file \
--log-opt max-size=50m \
--log-opt max-file=3 \
myrepo/web-app:1.0
# 验证日志文件位置(json-file 默认路径)
ls -lh /var/lib/docker/containers/$(docker inspect -f '{{.Id}}' web-app)/*.log
8. 常见排查技巧
- 日志中无异常但服务不可用:检查端口绑定、网络规则、健康检查。
- 日志大量重复:排查重试策略或依赖服务不可达。
- 时间戳混乱:确认容器时区与 NTP 同步。
- 高并发下日志丢失:检查日志驱动与磁盘 IO,必要时使用异步采集方案。
9. 练习
1. 配置 daemon.json 开启日志轮转并验证生效(docker info)。
2. 启动一个带健康检查的容器,模拟失败后观察 docker events 与 docker inspect 输出。
3. 构造一次 OOM 事件,记录 docker logs 与 dmesg 关联结果。
4. 将应用日志改为 stdout 输出,验证容器日志文件增长且轮转正常。