基于openjdk:8u171-alpine构建的java镜像,使用jstack命令打印线程的时候会提示以下错误:

/opt # ps -ef
PID USER TIME COMMAND
1 root 0:28 /usr/lib/jvm/java-1.8-openjdk/bin/java -jar /test/lib/test.jar
66 root 0:00 /bin/sh
70 root 0:00 ps /opt # jstack 1
1: Unable to get pid of LinuxThreads manager thread

使用jmap命令尝试了一下,也是一样的错误。
换了一种启动方式,使用/bin/sh启动docker,然后进入docker手动启动java进程,然后再用jstack命令,就能正常打印。
换了一个centos镜像,手动安装openjdk,在启动docker的时候直接启动java进程,然后进入docker,使用jstack命令,也可以正常打印。

通过这几种尝试,得出的结论是:
使用centos+java镜像,可以正常打印线程堆栈,但是这种方式的缺陷就是镜像太大,大约600M左右;
使用alpine+java镜像,以/bin/sh方式启动docker,然后手动启动java进程,这时java进程的PID不为1,这种方式能够正常打印线程堆栈。这种方式缺点就是java进程如果异常退出了,docker不会检测到,所以无法做自动重启等操作;
使用alpine+java镜像,如果是以直接运行java进程的方式启动docker,也就是说java进程的PID为1,这种方式无法正常打印线程堆栈。

查看了一下github上openjdk官方的问题答复,确实是存在这种情况,并且openjdk的维护成员看上去也无法解决这个问题。
但是有一个曲线解决方法,就是在启动docker的时候先运行一个tini进程,然后通过tini进程去运行java进程。
这种方式java进程的PID不为1,能够打印堆栈,同时如果java进程退出,tini也能检测到,并通知到docker,docker来做相关的处理,完美的解决了这个问题。

参考Dockerfile如下:

FROM openjdk:8u171-alpine
RUN apk add tini
ENTRYPOINT ["tini"]

这里的RUN命令指定在制作镜像的时候通过apk管理工具安装了tini程序。ENTRYPOINT命令指定在运行docker的时候要运行tini程序,具体的java程序作为参数传给tini。
我们有多个java微服务,所以不能把tini装在每个java微服务镜像中,而是装在我们自己的基础镜像中。

具体服务的Dockerfile如下:

FROM java
ADD build/bootScripts /test/bin
ADD build/libs /test/lib
WORKDIR /test
EXPOSE 8080
CMD /test/bin/test

这里的/test/bin/test就是传给tini的实际要执行的启动命令。

参考资料:
https://github.com/docker-library/openjdk/issues/76
https://github.com/krallin/tini/issues/8

openjdk-alpine镜像无法打印线程堆栈和内存堆栈问题的更多相关文章

  1. 程序中打印当前进程的调用堆栈(backtrace)

    为了方便调式程序,产品中需要在程序崩溃或遇到问题时打印出当前的调用堆栈.由于是基于Linux的ARM嵌入式系统,没有足够的空间来存放coredump文件. 实现方法,首先用__builtin_fram ...

  2. alpine 镜像 java 日志中文问号乱码

    0x00 前言 吾使用 alpine 作为基础镜像构建了 jdk8 镜像,为线上业务的 java 微服务架构提供支持,但是有容器运行的 java 服务中打印的日志中一旦出现中文,就会出现诸如以下的 ? ...

  3. JVM 找出最耗 cpu的线程 并打印线程栈

    监控JVM中最占cpu的线程 top -Hp pid JVM中最占cpu的线程ID -o THREAD,tid,time | awk 'BEGIN {count=0; } { if($2>0.3 ...

  4. sh: /etc/init.d/sshd: not found Docker中的Alpine镜像安装sshd无法启动

    问题描述 在Alpine镜像中安装了openssh-server和openssh之后,无法执行ssh localhost.发现未启动服务,开启服务时报以下错误 / # ls /etc/init.d/s ...

  5. 一个带bash,带glibc,中国时区,非root用户可运行crond命令的基于alpine镜像的Dockerfile

    这个镜像现在说起来简单, 带bash(增加执行脚本的兼容性,带GLIBC,中国时区,非root用户可运行crond命令-安全) 但让我开始陷入时,真的让我有段时间有点爆了. 比如,将filebeat文 ...

  6. 编译一个支持django及mysqlclient连接的alpine镜像

    一切都不难,难的就是在alpine镜像里. 最后,使用了网上编译好mysqlclient的镜像,才搞定. 记录一下. 一,基础镜像Dockerfile https://github.com/tnir/ ...

  7. Docker学习笔记:Alpine镜像+Python3安装+http服务器

    编写Dockerfile文件使用最新的Alpine镜像并安装Python3环境,如下: 因为python高于3.4则不会默认安装pip,需要手动安装. 试了很多其他办法都没安装上,唯有下载get-pi ...

  8. 一个神奇的bug:OOM?优雅终止线程?系统内存占用较高?

    摘要:该项目是DAYU平台的数据开发(DLF),数据开发中一个重要的功能就是ETL(数据清洗).ETL由源端到目的端,中间的业务逻辑一般由用户自己编写的SQL模板实现,velocity是其中涉及的一种 ...

  9. linux信号机制 - 用户堆栈和内核堆栈的变化【转】

    转自:http://itindex.net/detail/16418-linux-%E4%BF%A1%E5%8F%B7-%E5%A0%86%E6%A0%88 此文只简单分析发送信号给用户程序后,用户堆 ...

随机推荐

  1. <TLE>奇偶剪枝hdoj1010

    (奇偶剪枝)转自百度百科,讲的非常棒: http://baike.baidu.com/link?url=3g5bW7LszRVOVvFDFp6cL0ZZnAaOLUdpaNjc2leHoxkKU9Eh ...

  2. bzoj4517[Sdoi2016]排列计数(组合数,错排)

    4517: [Sdoi2016]排列计数 Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 1792  Solved: 1111[Submit][Stat ...

  3. Vant入门

    Vant是什么 简介 Vant是有赞开源的一套基于Vue2.0的Mobile组件库.通过Vant,可以快速搭建出风格统一的页面,提升开发效率.目前已有近50个组件,这些组件被广泛使用于有赞的各个移动端 ...

  4. 温习LOGO语言

    LOGO是什么? LOGO语言是一种早期的编程语言,也是一种与自然语言非常接近的编程语言,它通过"绘图"的方式来学习编程,对初学者特别是儿童进行寓教于乐的教学方式. LOGO语言创 ...

  5. hdu1233 还是畅通工程 基础最小生成树

    //克鲁斯卡尔 #include<iostream> #include<algorithm> using namespace std; ; struct node { int ...

  6. flask跨域问题

    在Flask开发RESTful后端时,前端请求会遇到跨域的问题.下面是解决方法: 使用 flask-cors库可以很容易的解决   1 pip install flask-cors 两种方法,一个是全 ...

  7. AIDL(1):简介

    Android 接口定义语言 (AIDL) 1.AIDL是什么 AIDL(Android 接口定义语言)与您可能使用过的其他 IDL 类似. 您可以利用它定义客户端与服务使用进程间通信 (IPC) 进 ...

  8. 18.3.2从Class上获取信息(内部类接口等)

    内部类 接口.枚举.注释类型

  9. forward和sendRedirect的区别

    部分内容转自:http://blog.csdn.net/zhouysh/article/details/380364和http://blog.csdn.net/frank_jay/article/de ...

  10. Backbone学习记录(6)

    路由 backbone将路由规则和一个方法名绑定到一起,来控制单页的hash,以及单页的前进后退. var UserRouter = Backbone.Router.extend({ routes: ...