容器中Java应用PID为1的问题

背景

Dockerfile中如果通过ENTRYPOINT 直接执行java -jar命令,会发现在容器中的java进程id是1,这样无法通过jstack,jmap,jinfo查看JVM相关信息。

  • PID 1~5是Linux的特殊进程。
pid 描述
1 init进程,系统启动的第一个用户级进程,是其他所有进程的父进程,引导用户空间服务
2 kthreadd,内核线程管理
3 migration,用于进程在不同CPU间迁移
4 ksoftirqd,内核中软中断守护线程,用于系统空闲时定时处理软中断事务
5 watchdog,看门狗进程,用于监听内核异常,当系统出现宕机时,可利用watchdog记录宕机时堆栈信息

Dockerfile配置:

1
2
3
4
5
6
7
8
9
# 环境
FROM williamyeh/java8:latest

# 拷贝jar文件
COPY /target/app.jar app.jar
# 设置端口号
EXPOSE 2023
# 运行jar包
ENTRYPOINT ["java", "-jar", "app.jar", "&"]
  • 容器中查询 app.jar pid 为 1
1
2
3
4
5
/ # export LINES=32; export COLUMNS=142
/ # jps -l
1 app.jar
42387 sun.tools.jps.Jps
/ #

方案

避免java应用作为第一个启动的应用。添加tini,作为第一个启动的应用。

  • 运行apk add –no-cache tini
  • 添加tini作为第一个运行的参数[“tini”, “java”, “-jar”, “app.jar”, “&”]

Dockerfile配置

1
2
3
4
5
6
7
8
9
10
# 环境
FROM openjdk:8-jdk-alpine
# 拷贝jar文件
COPY /target/app.jar app.jar
# 运行tini
RUN apk add --no-cache tini
# 设置端口号
EXPOSE 2023
# 运行jar包
ENTRYPOINT ["tini", "java", "-jar", "app.jar", "&"]
  • 容器中查询 app.jar pid 为 7
1
2
3
4
5
6
/ # export LINES=32; export COLUMNS=142
/ # jps -l
434 sun.tools.jps.Jps
354 arthas-boot.jar
7 app.jar
/ #

其他方案

除了使用tini来解决外,通过sh简单再开一个子进程也是可以的:
写好run.sh脚本放到项目中:

1
2
#!/bin/sh
java $JAVA_OPTS -jar tmp/$app.jar
  • 修改dockerfile:
1
2
COPY ./target/$app.jar /tmp
ENTRYPOINT [ "sh","-c","/tmp/run.sh"]