docker コンテナで動かしている Java プロセスの jstat を採る話。
以下のように実行してみると。。
$ docker exec -t --user 1000 {container-id} jstat -gc 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)
PID 1 がないというのだけど、java プロセスは確かに PID=1 で動いてる。。?
エラーメッセージで調べてみると、以下のような記事が見つかった。
jdk6u23 で jps/jstat が動作しないあるある
https://tksmd.hatenablog.com/entry/20110119/p1
jps、jstat は /tmp/hsperfdata_{ユーザ名}
というディレクトリを見て対象プロセスの情報を得るので、/tmp
の部分がプロパティで変更されてるとうまく動かないというものでした。
試してみると、Java の調査コマンドで確かに jps、jstat が動きません。
- ×
jps
- ×
jstat -gc 1
- 〇
jstack 1
- 〇
jmap -histo:live 1
- 〇
jcmd 1 GC.heap_info
ただし、記事にあるように /tmp
の部分は変更されていません。
hsperfdata
ディレクトリは Java プロセス起動時に作られるとあるのに、該当のディレクトリができていません。
どうやら、hsperfdata_{ユーザ名}
とあるように、実行ユーザの UID に対するユーザがないと対象のディレクトリが作られないようですね。
docker 実行時に実行ユーザの UID だけ指定してユーザを切り替えていたのがダメだったようです。
$ docker exec -t --user 1000 {container-id} id
uid=1000 gid=0(root) groups=0(root) ★UIDに対するユーザがいない
というわけで、Java コンテナの起動スクリプト(entrypoint.sh) 内で UID に対するユーザを作るようにしてみました。
UID=${UID:-1000}
useradd -m -u ${UID} myuser
実行ユーザが設定できています。
$ docker exec -t --user 1000 {container-id} id
uid=1000(myuser) gid=0(root) groups=0(root)
hsperfdata
ディレクトリも作られるようになりました。
$ docker exec -t --user 1000 {container-id} ls -1 /tmp
hsperfdata_myuser
:
これで、無事 jstat が採れるようになりました。
$ docker exec -t --user 1000 {container-id} jstat -gc 1
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT CGC CGCT GCT
0.0 5120.0 0.0 5120.0 74752.0 10240.0 431104.0 65111.7 75264.0 72714.0 10240.0 9118.1 35 3.934 0 0.000 8 0.397 4.331
// EOF