dmesg —— 看内核环形缓冲日志
一句话定义
dmesg(display message)显示内核环形缓冲区(kernel ring buffer)里的消息——硬件检测、驱动加载、OOM 杀进程、内核错误、网络接口 link up/down 等。所有"在内核里发生的事"都先到这里。
典型场景
- pod 被 OOM 杀:
dmesg -T | grep -i 'killed process' - 节点丢包:
dmesg | grep -i 'drop\|congestion' - 网卡断开 / 链路 down:
dmesg | grep -i 'link\|eth0' - 硬件错误:
dmesg | grep -i 'mce\|hardware error' - 磁盘 I/O error:
dmesg | grep -iE 'i/o|sector|sda'
dmesg vs journalctl -k 的关系
| 命令 | 看什么 |
|---|---|
dmesg | 直接读内核环形缓冲(内存中、有限大小) |
journalctl -k | 同样是内核日志,但由 journald 收集、持久化(如果配了) |
journalctl --dmesg | 等价 journalctl -k |
环形缓冲会覆盖——满了之后新消息冲掉旧的。机器重启后清空。
- 现场调试 →
dmesg(最快) - 回查历史 →
journalctl -k --since yesterday(如果持久化了)
五个核心 flag
dmesg # 看全部
dmesg -T # 带可读时间戳(**必加**)
dmesg -w # 跟随(类似 tail -f)
dmesg -l err,warn # 按级别
dmesg --since "10 min ago" # 按时间(新版 dmesg)
dmesg -c # 看完清空(小心,旧消息全没了)
-T —— 把秒数翻译成人类可读时间
不加 -T:
[12345.678901] kernel: ...
那个 12345.678901 是自系统启动以来的秒数。看不出来到底什么时候发生的。
加 -T:
[Mon May 27 14:30:00 2026] kernel: ...
永远加 -T。
Ubuntu 默认 dmesg 已经显示绝对时间(取决于内核
printk.time),但 CentOS 老系统不行。-T永远保险。
级别
dmesg -l emerg # 紧急
dmesg -l alert
dmesg -l crit
dmesg -l err # 错误
dmesg -l warn # 警告
dmesg -l notice
dmesg -l info
dmesg -l debug
dmesg -l err,warn # 多个级别
排查"今天有什么内核错误":
dmesg -T -l err,warn | tail
或者:
dmesg -T --level=err,warn,crit --since "1 hour ago"
跟随 -w —— 实时看
dmesg -Tw
# 持续输出新内核消息,Ctrl-C 退出
排查"现在正在发生什么内核事件"。
类似 tail -f 但是是内核日志。
训练营典型场景
场景 1:pod 被 OOMKilled
kubectl get pod my-pod -o yaml | grep -A 5 lastState
# reason: OOMKilled ← 被 OOM 杀
# 节点上看 dmesg
ssh m4 'dmesg -T | grep -iE "oom|killed process" | tail -10'
# [Mon May 27 14:30:00 2026] kernel: out of memory: Kill process 12345 (myapp)
# [Mon May 27 14:30:00 2026] kernel: Killed process 12345 (myapp), UID 0,
# total-vm:1024MB, anon-rss:512MB, file-rss:0MB
anon-rss 是真实占用——和 pod limit 比对。
场景 2:节点丢包 / 网络抖动
dmesg -T | grep -iE 'drop|congestion|conntrack|nf_conntrack'
# kernel: nf_conntrack: table full, dropping packet ← conntrack 满
# kernel: nf_conntrack: nf_conntrack_buckets ...
修:
sysctl -w net.netfilter.nf_conntrack_max=1048576
场景 3:磁盘 I/O 错误
dmesg -T | grep -iE 'i/o error|sector|sda|nvme'
# kernel: I/O error, dev sda, sector 12345678
# kernel: end_request: I/O error, dev sda, sector 12345678
这是真硬件问题信号——盘要坏了。立刻:
- 备份这台机器的数据
- 联系 IDC / 云厂商换盘
- K8s 节点 drain 这个节点
场景 4:内存压力
dmesg -T | grep -iE 'memory|allocation|reclaim'
# kernel: Memory cgroup out of memory: Killed process ... ← cgroup OOM(容器超 limit)
# kernel: SLUB: Unable to allocate memory ... ← 内核分配失败(严重)
场景 5:网卡 link 抖动
dmesg -T | grep -i 'eth0\|link'
# kernel: e1000e: eth0 NIC Link is Down
# kernel: e1000e: eth0 NIC Link is Up 1000 Mbps Full Duplex
网线 / 交换机 / 网卡硬件问题。
场景 6:内核 panic / crash
dmesg -T -l emerg,alert,crit
# 显示最严重的几个
如果有 Kernel panic 或 Oops,是内核 bug 或硬件问题。重启避免,保留 dmesg 输出 报内核 / 硬件厂商。
场景 7:容器运行时报错
dmesg -T | grep -iE 'cgroup|systemd-cgroup|runc|containerd'
# kernel: cgroup: ...
cgroup v1 / v2 配置错、systemd cgroup driver 和 containerd 不匹配等。
看完整原始内容
某些消息在 dmesg 里被换行 / 截断,看完整:
dmesg --raw # 原始格式
dmesg --kernel # 只内核消息(默认)
dmesg --userspace # 用户空间消息(罕见)
JSON 输出(脚本用):
dmesg -J | jq # JSON
dmesg -c —— 看完清空(小心)
dmesg -c > /tmp/dmesg-snapshot.txt
# 读出当前所有 + 清空环形缓冲
# 之后 dmesg 显示的都是清空之后的新消息
dmesg # 只显示新的
需要 root。
用途:故障排查时先 snapshot 当前状态、然后清空、然后等待事件发生——更易抓"事件相关" 的消息。
生产环境少用
-c——清掉的内容如果没存就丢了。
看环形缓冲大小
dmesg | wc -l # 多少行
sysctl kernel.printk_ringbuffer_size # 缓冲大小(字节)
默认 4 MB 左右。改大:
sysctl -w kernel.printk_ringbuffer_size=16777216 # 16 MB(要重新编译内核或 boot param,运行时通常无法改)
更实际:让 journald 持久化 内核日志,环形缓冲不够大也无所谓。
journalctl -k 等价用法
journalctl -k # 同 dmesg
journalctl -k -b # 本次启动
journalctl -k -b -1 # 上一次启动(含重启前的)
journalctl -k --since today
journalctl -k -p err # 按级别
journalctl -k -g "oom" # grep 模式
journalctl -k -b -1 是 dmesg 做不到的——重启后 dmesg 没了,journalctl 还能看上次 boot 的内核日志(前提是 journald 持久化)。
实用的 grep 模板
# OOM
dmesg -T | grep -iE 'oom|killed process|out of memory'
# 网络
dmesg -T | grep -iE 'eth|link|drop|conntrack'
# 磁盘
dmesg -T | grep -iE 'i/o|sector|sd[a-z]|nvme|filesystem'
# K8s / 容器
dmesg -T | grep -iE 'cgroup|runc|container'
# 内存 / SLAB
dmesg -T | grep -iE 'memory|slab|reclaim'
# 安全 / 审计
dmesg -T | grep -iE 'denied|selinux|apparmor|audit'
# 防火墙 / netfilter
dmesg -T | grep -iE 'iptables|netfilter|firewall'
# 最近 1 小时所有 err / warn
dmesg -T --since "1 hour ago" -l err,warn
# 最近 10 行(最简便)
dmesg -T | tail
常见踩坑
坑 1:忘加 -T,看到诡异的秒数
[12345.678] kernel: ...
不是 unix timestamp。是开机后的秒数。算绝对时间要:
date -d "$(uptime -s) + 12345 seconds"
或者直接 dmesg -T。
坑 2:环形缓冲不够大、看不到老消息
dmesg -T | head
# [Mon May 27 13:00:00 2026] kernel: ... ← 几小时前
机器跑久了 / 内核消息多,老的被覆盖。要看更老的:
journalctl -k --since "2026-05-26"
前提:journald 持久化。
坑 3:非 root 用户被拒
$ dmesg
dmesg: read kernel buffer failed: Operation not permitted
kernel.dmesg_restrict = 1 时(许多发行版默认开),非 root 不能读内核日志。
sudo dmesg
# 或者
sysctl -w kernel.dmesg_restrict=0 # 不推荐生产开
K8s 节点上加 CAP_SYSLOG 也能读:
securityContext:
capabilities:
add: ["SYSLOG"]
坑 4:在容器里跑 dmesg 看到的是节点的
kubectl exec my-pod -- dmesg
dmesg 看内核环形缓冲——这是全节点共享的,不是容器隔离的。容器里看到的是节点的内核日志。
这通常是好的——能看到节点级问题(如果 pod 有 SYSLOG 权限)。
坑 5:OOM 信息找不到
dmesg -T | grep -i oom
# 没结果
可能:
- 进程是被 cgroup OOM(容器超 limit)而不是全局 OOM。grep 范围扩大:
dmesg -T | grep -iE 'Memory cgroup|oom_reaper|invoked oom' - 时间太久、被覆盖。看 journalctl:
journalctl -k --since yesterday | grep -i oom
坑 6:误以为 dmesg --since 老内核也支持
dmesg --since "1 hour ago"
# 老 util-linux:unrecognized option '--since'
--since 是 util-linux 2.30+。老系统用:
dmesg -T | awk -v t="$(date -d '1 hour ago' '+%s')" '...'
# 或者直接 journalctl -k --since "1 hour ago"
坑 7:journald 没持久化、重启后 dmesg 全没了
reboot
dmesg -T | head
# 重启之后的,老的全没了
journalctl -k -b -1
# No persistent journal was found.
预防:让 journald 持久化(journalctl.md):
mkdir -p /var/log/journal
systemctl restart systemd-journald
K8s 节点强烈建议这么做——不然故障重启后无从查证。
坑 8:dmesg 显示一堆 audit 噪音
某些 SELinux / AppArmor 系统会把所有 audit 日志塞 dmesg:
dmesg -T | wc -l
# 50000,但其中 49000 是 audit
过滤掉:
dmesg -T | grep -v 'audit:'
# 或者
dmesg -T --console-on # 只看 console 级(去掉 audit / debug)
关联命令
- journalctl ——
-k看持久化的内核日志 - systemctl —— systemd-journald 服务管理
- top —— 看到 wa / 高 CPU 后再 dmesg 验证
- lsof —— dmesg 报 OOM 后看哪个进程占
mcelog—— Memory ECC error 详细日志smartctl—— 看磁盘 SMART 信息(dmesg 报 sector error 后用)