docker inspect -f '{{.State.Pid}}' 返回的是容器 init 进程(PID 1)在宿主机的真实 PID;若 JVM 是 PID 1,该值即为目标 PID;否则需进容器查 ps aux | grep java 或 cat /proc/1/cmdline 确认。
怎么用
拿到容器里 JVM 进程的真实 PID
容器内看到的 PID 是隔离后的,宿主机上查不到;调试必须用宿主机视角的 PID。直接
查不到进程 PID,得先拿到容器的 init 进程在宿主机上的 PID,再从它底下找 Java 进程。
返回的是容器 init 进程(即 PID 1)在宿主机的 PID,不是 Java 进程本身的 PID
Java 进程通常就是 PID 1(比如用
启动),但若用了
、
封装或 supervisord,PID 1 就不是 JVM,得进容器查:
更稳的办法是进容器执行
看 PID 1 是否为 java,避免误杀 shell 或 wrapper 进程
为什么
进去后
报 “Unable to open socket file”
因为 JVM 默认只允许同用户、同 namespace 的进程 attach,而
启动的 shell 虽然在同一个容器里,但它的
指向的是容器 rootfs,而
需要访问目标 JVM 的
下的 .java_pid 文件——这个文件默认由 JVM 在启动时创建,但权限受限或路径被挂载覆盖就找不到了。
JVM 必须加启动参数
(JDK 8u191+ / JDK 11+)才能正确识别容器环境并生成可访问的 attach socket
如果没加参数,
会尝试读
,但该文件可能属主是 root、权限 600,且宿主机挂载的
和容器内不是同一份——常见于用
映射时权限错乱
临时解法:进容器后用
切换到 JVM 启动用户再执行(别用 root 直接跑 jstack,容易因 UID 不匹配失败)
挂载
和
时权限不够,
/
失败怎么办
这些工具依赖读取
下的内存、线程、maps 等信息,而 Docker 默认只挂载了容器自己的
,里面看不到完整进程视图;强行挂载宿主机
又会导致路径混乱和权限拒绝。
最简方案:用
启动容器(或
),这样容器内
就是宿主机视角,
才能读到真实数据
但注意:启用
后,容器内
会看到所有宿主机进程,需配合
限制权限,否则
可能因目标进程 UID 不匹配被拒
若不能开 host PID namespace,改用
(不推荐)或直接在宿主机用
——前提是 JVM 启动时加了
调试用的挂载目录权限错乱:比如
或
容器内写不了
不是所有挂载都“自动适配”,尤其当宿主机目录属主是普通用户、而容器里 JVM 以非 root 用户运行时,
或
不生效,
写文件直接 Permission denied。
检查挂载点实际权限:
,对比宿主机
;常见问题是宿主机目录属组不是容器用户所在组,或没有 group-writable 权限
启动容器时显式指定 UID/GID:
,确保容器内用户对挂载目录有写权限
更稳妥的做法是让 JVM 进程自己创建 dump 目录,并在启动前用
(写在 entrypoint 里),避免依赖挂载点初始状态
真正卡住人的往往不是命令记不住,而是 PID namespace、用户 UID、挂载传播模式(shared/slave)、JVM attach listener 开关这四者没对齐。少一个,
就静默失败,连错误都不报。
docker inspectdocker inspectdocker inspect -f '{{.State.Pid}}' java -jar app.jarsh -centrypointdocker exec ps aux | grep java cat /proc/1/cmdlinedocker exec -itjstackdocker exec/proc//root jstack/tmp-XX:+UseContainerSupport -XX:+UnlockDiagnosticVMOptions -XX:+PrintContainerInfojstack/tmp/.java_pid/tmp-v /tmp:/tmpsu -c 'jstack ' java_user /proc/sysjstatjmap/proc// /proc/procdocker run --pid=hostdocker update --pid=host /procjstat -JVM--pid=hostps--userjmap -histodocker exec --privilegedjstack -XX:+StartAttachListener/tmp/datachmodchownjmap -dumpdocker exec ls -ld /tmp ls -ld /host/tmpdocker run -u 1001:1001 -v /host/tmp:/tmp:rwmkdir -p /tmp/dumps && chown java_user:java_group /tmp/dumpsjstack