日志定位:系统日志(dmesg、journalctl)的采集与关键字段解读
镜像加载失败,说白了就是内核在启动阶段或者运行时,没能把镜像文件正确挂载到内存里。这时候你第一反应是什么?我个人的习惯是——先别急着重启,先把系统日志捞出来看看。
系统日志是内核和关键服务留下的“案发现场”。你想想看,镜像加载失败这种问题,十有八九会在 dmesg 或者 journalctl 里留下痕迹。今天我们就来聊聊怎么采集这些日志,以及怎么看懂里面的关键字段。
1. dmesg:内核的“实时监控”
dmesg 是内核环缓冲区(ring buffer)的导出工具。说白了,内核每干一件事,都会往这个缓冲区里写一条记录。镜像加载、设备识别、驱动初始化……全在这里。
1.1 什么时候用 dmesg?
- 系统刚启动,镜像加载失败,连登录界面都进不去
- 热插拔设备后,镜像挂载报错
- 内核模块加载失败,怀疑是镜像路径或权限问题
1.2 采集命令
# 查看所有内核日志
dmesg
# 实时跟踪新日志(类似 tail -f)
dmesg -w
# 只看最后 50 条
dmesg | tail -50
# 保存到文件,方便后续分析
dmesg > /tmp/kernel_log_$(date +%Y%m%d_%H%M%S).txt
我的小技巧: 如果系统已经挂了,连终端都进不去,可以在 GRUB 启动时按
e 编辑内核参数,加上 earlyprintk=vga,这样启动日志会直接输出到屏幕上。我曾经靠这个在无网络、无串口的机器上抓到了镜像加载失败的根因。
1.3 关键字段解读
dmesg 的输出格式大致是:
[ 5.123456] <日志级别> <模块名>: <消息内容>
| 字段 | 含义 | 实战关注点 |
|---|---|---|
| 时间戳 | 系统启动后的秒数(精确到微秒) | 看事件发生的先后顺序,定位第一个报错 |
| 日志级别 | 内核定义的严重等级(0-7) | 重点关注 err(3)、crit(2)、alert(1) |
| 模块名 | 产生日志的内核模块或驱动 | 比如 loop、overlay、ext4 等 |
| 消息内容 | 具体的错误描述 | 包含文件路径、错误码、设备节点等关键信息 |
镜像加载失败的典型 dmesg 报错:
[ 12.345678] loop0: detected capacity change from 0 to 1048576
[ 12.345679] EXT4-fs (loop0): VFS: Can't find ext4 filesystem
[ 12.345680] overlayfs: failed to resolve 'lowerdir': -2
看到 -2 了吗?这是内核错误码,对应 ENOENT,意思是“文件或目录不存在”。说白了,就是镜像文件路径写错了,或者文件被删了。
2. journalctl:systemd 的“日志管家”
如果你的系统用的是 systemd(现在绝大多数 Linux 发行版都是),那 journalctl 就是你的首选。它不光收集内核日志,还收集所有 systemd 管理的服务日志。
2.1 什么时候用 journalctl?
- 镜像加载失败,但系统还能部分运行(比如 SSH 还能连)
- 需要查看某个特定服务(如
docker、containerd)的日志 - 需要按时间范围、优先级、单元名等条件过滤
2.2 采集命令
# 查看所有日志(从当前启动开始)
journalctl
# 只看内核日志(相当于 dmesg 的增强版)
journalctl -k
# 查看本次启动的日志
journalctl -b
# 查看上一次启动的日志(系统崩溃后重启,看上次的日志)
journalctl -b -1
# 实时跟踪新日志
journalctl -f
# 按优先级过滤(只显示错误及以上)
journalctl -p err
# 按服务名过滤
journalctl -u docker.service
# 按时间范围过滤
journalctl --since "2024-01-01 10:00:00" --until "2024-01-01 11:00:00"
# 保存到文件
journalctl -b > /tmp/system_log_$(date +%Y%m%d_%H%M%S).txt
注意: journalctl 默认只保留最近几次启动的日志。如果系统频繁重启,旧日志会被自动清理。我建议在生产环境上配置
SystemMaxUse=500M 和 MaxRetentionSec=7day,确保关键日志不会丢失。
2.3 关键字段解读
journalctl 的输出格式更丰富:
Jan 15 10:30:45 hostname kernel: loop0: detected capacity change from 0 to 1048576
Jan 15 10:30:45 hostname dockerd[1234]: failed to mount overlay: no such file or directory
| 字段 | 含义 | 实战关注点 |
|---|---|---|
| 时间戳 | 系统本地时间(精确到秒) | 与 dmesg 的时间戳对应,交叉验证 |
| 主机名 | 产生日志的主机 | 多节点环境时区分来源 |
| 服务名 | 产生日志的进程或服务 | 比如 kernel、dockerd、containerd |
| PID | 进程 ID | 配合 ps 或 systemctl status 进一步排查 |
| 消息内容 | 具体的日志信息 | 包含错误码、文件路径、调用栈等 |
3. 实战:镜像加载失败的日志定位流程
嗯,这里我画了一张流程图,帮你理清思路。遇到镜像加载失败,按这个顺序查,基本不会漏。
4. 避坑指南:我踩过的那些坑
做运维这些年,我在日志采集上栽过不少跟头。分享几个典型的,你遇到了可以少走弯路。
- 坑一:dmesg 日志被覆盖 —— 我曾经在一台高负载的机器上查问题,dmesg 里只看到最后几百条记录,前面的全被新日志冲掉了。后来我养成了习惯:出问题第一时间
dmesg > /tmp/dmesg_save.txt,先保存再说。 - 坑二:journalctl 默认不持久化 —— 有一次系统崩溃后重启,我想看上次的日志,结果
journalctl -b -1告诉我没有日志。为什么?因为/var/log/journal目录不存在,日志只存在内存里。解决方案:mkdir -p /var/log/journal && systemd-tmpfiles --create --prefix /var/log/journal。 - 坑三:只看错误级别,忽略上下文 —— 镜像加载失败,你看到
overlayfs: failed to resolve 'lowerdir': -2,以为只是路径问题。但如果你往前翻几条日志,可能会发现loop0: detected capacity change from 0 to 1048576,说明镜像文件本身已经被识别了,只是挂载参数不对。上下文很重要。
5. 总结:日志采集的黄金法则
我的三条原则:
- 先保存,再分析 —— 日志是易失的,尤其是 dmesg 的环形缓冲区。第一时间保存到文件。
- 从内核到服务,逐层排查 —— 先看 dmesg 有没有内核报错,再看 journalctl 里相关服务的日志。不要跳过内核层直接查应用层。
- 关注第一个报错 —— 很多时候后面的报错都是连锁反应。找到第一个错误,就找到了根因。