Java Kubernetes 容器中无法执行 jsp jstat 等诊断命令
Kubernetes 诊断工具 JVM About 5,449 words现象
Java
的jps
、jstat
等诊断命令在Kubernetes
的Pod
中失效。
jps
jps
没有任何输出。
bash-4.4$ jps
bash-4.4$
jstat
jstat
显示无法找到进程为1
的Java
服务。
bash-4.4$ jstat -gccause 1
sun.jvmstat.monitor.MonitorException: 1 not found
at jdk.internal.jvmstat/sun.jvmstat.perfdata.monitor.protocol.local.PerfDataBuffer.<init>(PerfDataBuffer.java:84)
at jdk.internal.jvmstat/sun.jvmstat.perfdata.monitor.protocol.local.LocalMonitoredVm.<init>(LocalMonitoredVm.java:68)
at jdk.internal.jvmstat/sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostProvider.getMonitoredVm(MonitoredHostProvider.java:77)
at jdk.jcmd/sun.tools.jstat.Jstat.logSamples(Jstat.java:107)
at jdk.jcmd/sun.tools.jstat.Jstat.main(Jstat.java:70)
Caused by: java.lang.IllegalArgumentException: Could not map vmid to user Name
at java.base/jdk.internal.perf.Perf.attach(Native Method)
at java.base/jdk.internal.perf.Perf.attachImpl(Perf.java:272)
at java.base/jdk.internal.perf.Perf.attach(Perf.java:202)
at jdk.internal.jvmstat/sun.jvmstat.perfdata.monitor.protocol.local.PerfDataBuffer.<init>(PerfDataBuffer.java:64)
... 4 more
备注
jcmd
同样也无法列出Java
服务,但可以使用jcmd <pid>
。
因为容器中Java
的进程ID
为1
,所以可以直接使用jcmd 1
。
排查
查看日志
查看日志可以看到started by ?
,Java
无法知道目前的用户是谁。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.0)
Starting TestApplication using Java 11.0.16 on ns-test-677777bcb5-t7c4g with PID 1 (/app/test.jar started by ? in /app)
user.name
使用jshell
获取用户名称显示?
。
jshell> System.getProperty("user.name")
$1 ==> "?"
PerfData
因为jps
、jstat
、jcmd
等命令都使用PerfData
生成的数据,而PerfData
默认是存储在/tmp/hsperfdata_<username>
下的,并且监控信息以进程号存储在该文件夹下。
查看/tmp
目前发现,hsperfdata_root
目录下并没有进程为1
的文件。
bash-4.4$ ls -al /tmp
total 20
drwxrwxrwt 1 root root 4096 Jul 21 16:48 .
drwxr-xr-x 1 root root 4096 Jul 21 14:36 ..
drwxr-xr-x 2 root root 4096 Aug 4 2022 hsperfdata_root
drwx------ 2 1000 root 4096 Jul 21 14:36 tomcat-docbase.8081.3799688995221812322
drwx------ 3 1000 root 4096 Jul 21 14:36 tomcat.8081.6049079183157077699
whoami
从/tmp
目录发现,从hsperfdata_root
文件夹得知Java
推断是root
用户,而日志显示是started by ?
。从文件夹的信息看到用户是1000
。
使用whoami
命令查看,得到目前是以1000
用户启动。
bash-4.4$ whoami
whoami: cannot find name for user ID 1000
Dockerfile
查看Dockerfile
,发现以1000
用户启动了Java
进程。
FROM openjdk:11-oraclelinux8
ADD target/test-0.0.1-SNAPSHOT.jar /app/test.jar
USER root
RUN chmod -R 777 /app
RUN chown 1000:1000 -R /app
WORKDIR /app
USER 1000
CMD ["java","-jar","test.jar"]
/etc/password
查看容器中的用户有哪些,发现并没有1000
这个用户。
Dockerfile
中并没有添加用户的操作。
bash-4.4$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
hsperfdata_root
后又发现hsperfdata_root
还是在2022
年8
月创建的,猜想是该镜像发布的时间。
所以Java
进程压根就没有生成PerfData
文件夹。
用户 1000
以1000
用户启动Java
进程是为了安全考虑,但这又给诊断带来了麻烦,必须兼顾安全和诊断。
解决
方法一
在Dockerfile
中增加添加用户的操作。(不做演示了)
方法二
使用nobody
。
同时给/tmp
也改成了nobody
所属。
FROM openjdk:11-oraclelinux8
ADD target/test-0.0.1-SNAPSHOT.jar /app/test.jar
USER root
RUN chmod -R 777 /app /tmp
RUN chown nobody:nobody -R /app /tmp
WORKDIR /app
USER nobody:nobody
CMD ["java","-jar","test.jar"]
查看日志,发现服务能正确识别启动用户,started by nobody
。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.0)
Starting TestApplication using Java 11.0.16 on ns-test-677777bcb5-t7c4g with PID 1 (/app/test.jar started by nobody in /app)
查看/tmp
,发现生成了hsperfdata_nobody
文件夹。
bash-4.4$ ls -al /tmp
total 24
drwxrwxrwx 1 nobody nobody 4096 Jul 21 16:59 .
drwxr-xr-x 1 root root 4096 Jul 21 16:59 ..
drwxr-xr-x 2 nobody nobody 4096 Jul 21 17:01 hsperfdata_nobody
drwxrwxrwx 1 nobody nobody 4096 Aug 4 2022 hsperfdata_root
drwx------ 2 nobody nobody 4096 Jul 21 16:59 tomcat-docbase.8081.10018640566863022563
drwx------ 3 nobody nobody 4096 Jul 21 16:59 tomcat.8081.4651009197921297871
查看/tmp/hsprefdata_nobody
文件夹,发现生成了以进程号为名称的文件1
。
bash-4.4$ ls -al /tmp/hsperfdata_*
/tmp/hsperfdata_nobody:
total 40
drwxr-xr-x 2 nobody nobody 4096 Jul 21 17:01 .
drwxrwxrwx 1 nobody nobody 4096 Jul 21 16:59 ..
-rw------- 1 nobody nobody 32768 Jul 21 17:22 1
/tmp/hsperfdata_root:
total 8
drwxrwxrwx 1 nobody nobody 4096 Aug 4 2022 .
drwxrwxrwx 1 nobody nobody 4096 Jul 21 16:59 ..
再次使用jps
、jstat
、jcmd
等诊断命令,能正常使用。
bash-4.4$ jps
1 test.jar
58 Jps
bash-4.4$ jstat -gccause 1
S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT LGCC GCC
31.54 0.00 95.67 66.39 96.44 88.50 36 0.245 2 0.077 - - 0.322 Allocation Failure No GC
bash-4.4$ jcmd
1 test.jar
84 jdk.jcmd/sun.tools.jcmd.JCmd
bash-4.4$
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓