如何在Docker的CoreOS、Ubuntu系统中获取线程转储?
正确收集Docker容器内Java应用的线程转储方法
嘿,你的命令完全搞错语法啦!kill -3、jstack和docker exec不能这么混在一起用,我给你整理了几种靠谱的方法,不管是CoreOS还是Ubuntu基础的Docker容器都能用:
方法一:直接在容器内用jstack导出(推荐)
如果容器里已经安装了JDK(jstack是JDK专属工具,JRE里没有哦),这是最直接的方式:
- 第一步,找到容器内的Java进程ID:
这个命令会列出容器里所有的Java进程,你能看到对应应用的PID(比如输出里的docker exec appsnap jps -l123 com.your.app.Main,123就是我们要的PID)。 - 第二步,导出线程转储到宿主机的文件:
转储文件会保存在你当前的宿主机目录,加了时间戳也方便后续区分不同时间的转储。docker exec appsnap jstack 123 > ./thread_dump_$(date +%Y%m%d_%H%M%S).log
方法二:用kill -3触发转储(适合只有JRE的场景)
如果容器里只有JRE,没法用jstack,可以给Java进程发SIGQUIT信号(也就是kill -3),Java进程收到后会自动把线程转储输出到容器的日志里:
- 先找到容器内的Java PID:
从输出里找到应用的PID(注意要排除grep自身的进程哦)。docker exec appsnap ps aux | grep java - 发送信号:
docker exec appsnap kill -3 <你的Java PID> - 最后导出容器日志获取转储:
打开这个文件就能看到完整的线程转储内容了。docker logs appsnap > ./thread_dump_from_log.log
方法三:宿主机通过nsenter调用jstack(进阶场景)
如果宿主机安装了JDK和nsenter工具,也可以绕过docker exec直接进入容器的命名空间操作:
- 先获取容器在宿主机上的PID:
比如得到docker inspect -f '{{.State.Pid}}' appsnap456这个数值。 - 再用方法一或方法二找到容器内的Java PID(假设是
123),然后执行:
这个方法适合一些特殊场景,但日常排查用方法一就足够顺手了。nsenter -t 456 -m -p jstack 123 > ./thread_dump_nsenter.log
额外注意事项
- 如果是Ubuntu基础镜像,容器里没装JDK的话,可以临时进入容器安装:
docker exec -it appsnap apt-get update && apt-get install openjdk-11-jdk-headless -y - 如果应用是用非root用户运行的,执行
docker exec时要指定对应用户,避免权限问题:docker exec -u appuser appsnap jstack 123 > thread_dump.log
内容的提问来源于stack exchange,提问作者ashok
相关产品推荐
相关产品推荐

