一、背景

平时用的镜像是:

eclipse-temurin:8-jre-focal
  • 优点:小、稳定、适合生产
  • 缺点:没有 jmap/jstack/jps/jinfo 等工具
  • 也就是说,如果 JVM 出问题(死锁、内存泄漏、线程堵塞),你无法用这些经典工具排查

二、解决方案:临时挂载 JDK 容器排查

1️⃣ 核心思路

Docker 容器里有一个 PID namespace(进程空间)概念:

  • 每个容器进程都有自己的 PID namespace
  • 默认情况下,一个容器看不到另一个容器里的进程
  • 可以通过 --pid=container:<容器ID> 来共享进程空间

所以,你可以:

  1. 业务容器运行 JRE(轻量)
  2. 起一个新的 临时 JDK 容器
  3. 通过 --pid=container:<业务容器ID> 让这个临时容器看到业务容器里的 Java 进程
  4. 在 JDK 容器里用 jmap/jstack 等工具直接操作业务容器里的 JVM

2️⃣ 举个例子

假设你业务容器叫 app,运行 JRE:

docker run -d --name app eclipse-temurin:8-jre-focal java -jar /app/app.jar
  • 业务正常运行,JRE 就够
  • 发生问题,例如死锁或内存泄漏

你可以临时起一个 JDK 容器:

docker run -it --rm \
  --pid=container:app \
  openjdk:8u322-jdk-bullseye bash

然后在这个容器里:

# 查看 JVM 进程
jps -l

# dump 堆
jmap -dump:format=b,file=/tmp/heap.bin <pid>

# 打印线程
jstack <pid>

这样,你不用在生产容器里安装完整 JDK,也能做排查。

3️⃣ 优点

  • 生产容器保持轻量(JRE)
  • 不暴露 JDK 工具(安全性高)
  • 排查灵活,问题发生时才临时挂载
  • 完全可自动化(CI/CD + K8s debug 流程)

4️⃣ 注意事项

  • 临时 JDK 容器最好和业务容器同一台宿主机,否则 PID 不共享
  • 堆 dump / jstack 文件要注意存储位置
  • 排查结束后,临时容器销毁,不留痕迹

💡 一句话总结

平时轻量运行 JRE,出问题用临时 JDK 容器挂载 PID namespace 来排查
这就是生产环境安全、轻量又可排障的标准做法。

作者:张三  创建时间:2026-02-02 20:30
最后编辑:张三  更新时间:2026-02-02 20:30