背景
在生产环境中,我们常常会遇到一个服务部署了多个副本(容器)的情况。当服务出现异常(例如 Go 程序发生 panic)时,我们需要快速定位是哪个容器出了问题,并查看具体的堆栈信息。如果逐个容器执行 docker logs 再 grep,效率低下。本文介绍几种在宿主机上一次性查看所有相关容器日志并过滤 panic 的方法,尤其适合 Kubernetes 集群中的节点直接操作。
环境准备
首先,查看当前运行的容器,确认要监控的服务名称(这里以 backend 为例):
bash
docker ps | grep backend
可以看到有多个容器运行,我们需要同时查看它们的日志 ,并过滤出包含 panic 的行。
方法一:一次性查看所有容器的近期日志并过滤 panic
适用场景:快速排查最近一段时间是否有 panic 发生,不需要持续监控。
命令
bash
docker ps --filter "name=backend" --format "{{.ID}}" | xargs -I {} sh -c 'echo "===== Container {} =====" && docker logs --tail 200 {} 2>&1' | grep -i panic -B 2 -A 5
命令拆解
docker ps --filter "name=backend" --format "{``{.ID}}"--filter "name=backend":只筛选容器名中包含backend的容器(根据你的实际情况调整关键词)。--format "{``{.ID}}":只输出容器 ID,便于后续处理。
xargs -I {}:将每个容器 ID 赋值给{},然后执行后面的命令。sh -c '...':执行一个 shell 命令串。echo "===== Container {} =====":打印分隔线,标识当前日志来自哪个容器。docker logs --tail 200 {} 2>&1:取每个容器最近 200 行日志,并将标准错误重定向到标准输出(因为 panic 可能输出到 stderr)。
grep -i panic -B 2 -A 5:忽略大小写匹配panic,并显示匹配行的前 2 行和后 5 行,便于查看上下文堆栈。
输出效果
如果存在 panic,会显示类似:
===== Container 2aa39b02c002 =====
[2026-08-28 10:23:45] panic: runtime error: invalid memory address
[2026-08-28 10:23:45] goroutine 123 [running]:
[2026-08-28 10:23:45] main.handleRequest(...)
...
===== Container 45fb08fe5cb5 =====
(无输出)
变形命令
-
只看日志内容,不显示容器分隔符(适合进一步处理):
bashdocker ps --filter "name=backend" --format "{{.ID}}" | xargs -I {} docker logs --tail 500 {} 2>&1 | grep -i panic -
调整
--tail行数(例如取最近 1000 行):bashdocker ps --filter "name=backend" --format "{{.ID}}" | xargs -I {} sh -c 'echo "===== Container {} =====" && docker logs --tail 1000 {} 2>&1' | grep -i panic -B 3 -A 8 -
如果不想限制行数,直接取全部日志(日志量巨大时慎用):
bashdocker ps --filter "name=backend" --format "{{.ID}}" | xargs -I {} sh -c 'echo "===== Container {} =====" && docker logs {} 2>&1' | grep -i panic -B 2 -A 5
方法二:实时跟踪所有容器的日志并过滤 panic
适用场景:持续监控,当新产生 panic 时立即看到。
命令
bash
docker ps --filter "name=backend" --format "{{.ID}}" | xargs -I {} docker logs -f {} 2>&1 | grep -i panic
说明
docker logs -f:类似tail -f,持续输出新增日志。- 其他部分与方法一相同。
- 按下
Ctrl+C退出跟踪。
注意事项
-
由于是实时输出,如果多个容器同时打印日志,可能会交错,但
grep会过滤出所有包含panic的行,不会丢失。 -
如果你想在实时输出中同时看到容器 ID,可以改进命令,但更为复杂。一般 panic 日志中会包含 goroutine 信息,足以定位问题。
-
如果希望只跟踪最近一段时间内的日志(例如最近 10 分钟),可以添加
--since 10m:bashdocker ps --filter "name=backend" --format "{{.ID}}" | xargs -I {} docker logs -f --since 10m {} 2>&1 | grep -i panic
常见问题与注意事项
- 日志驱动问题 :如果
docker logs没有输出,可能是容器使用了journald或none驱动。可以通过docker inspect查看日志驱动,然后改用journalctl查看。 - 容器过滤条件 :
--filter "name=backend"是基于容器名的部分匹配,如果你的容器名完全不同,请调整关键词。也可以使用--filter "label=..."等其他过滤方式。 - 新旧容器区分 :滚动更新时,新旧容器会同时存在一段时间。如果只关心最新版本,可以结合
--since时间或容器启动时间来筛选。 - grep 大小写 :
-i参数可忽略大小写,确保匹配panic、Panic、PANIC等。 - 输出过多 :如果日志量极大,建议先取最近行数(
--tail),避免终端卡死。
总结
- 方法(
xargs+docker logs --tail+grep) 适合快速回顾,一次性获取所有容器的近期 panic 信息。 - 方法(
xargs+docker logs -f+grep) 适合实时监控,持续跟踪新产生的 panic。
这两种方法都已在生产环境中验证有效,简单高效,无需额外安装工具。如果你还使用 Kubernetes,也可以结合 kubectl 或 stern 实现类似效果。
希望本文能帮助你在排查容器 panic 时节省时间。如有问题,欢迎留言交流!