GKE+Java環境におけるjvisualvmの利用方法

# はじめに

Google Kubernetes Engine + Java (Spring Boot)環境における、jvisualvmの利用方法について試したことを記載しています。

# 環境

```
  +--------+      +-------------------------+     +-----------------------+
  |        |      |                         |     |                       |
  |   PC   | +--> |   GCE: tunnel serever   | +-> |   GKE: applications   |
  |        |      |                         |     |                       |
  +--------+      +-------------------------+     +-----------------------+
```
 - PC:GCEにssh接続可能なマシン。PCにてjconsole,jvisualvmを実行する。
 - tunnel serverは、GKEと同一ネットワーク(通信可能なネットワーク)に存在する適当なインスタンス。Cent OS 7。
 - GKE:applicationsは、`openjdk:8u171-jre-alpine` ベースのcontainerイメージを利用している。<br>※コンテナ内に、jps,jconsoleコマンドが存在しない。

この前提となるSpring Bootアプリケーションは、、https://github.com/h-r-k-matsumoto/spring-boot-sample となります。jibを使ってdockerイメージまで作成しちゃっています。
細かい設定などは、上記アプリケーションのpom.xml、kubernetsの設定を参照してください。

# 事前準備

## java起動時オプションの設定
jmxのリモート接続を許可するように設定する必要があります。
起動時オプションとして下記を設定します。

```
-Dcom.sun.management.jmxremote.port=7199
-Dcom.sun.management.jmxremote.rmi.port=7199
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
```
※jibを使う場合は
　https://github.com/h-r-k-matsumoto/spring-boot-k8s-jib/blob/master/pom.xml#L67-L70
を参考にしてください。

## podのIP確認
podのipを確認しておく必要があります。
`kubectl get pod -o wide` コマンドにて各podのipを確認しておきます。

```
$ kubectl get pod -o wide
NAME                                  READY     STATUS    RESTARTS   AGE       IP          NODE
spring-boot-sample-7d4448cf7b-9nh8v   1/1       Running   0          29m       10.36.2.8   gke-cluster-example-default-pool-26c288d4-vn4x
spring-boot-sample-7d4448cf7b-czqpj   1/1       Running   0          29m       10.36.1.5   gke-cluster-example-default-pool-26c288d4-mcdh
$
```

以降に記載する手順は、監視対象のアプリケーションのIPとして `10.36.2.8` として記載しています。

# ツールの利用

## sshでトンネル接続

下記コマンドにて、PCとtunnel serverの接続を行います。
`--` の前のコマンド部分は、Google Cloud Consoleにて[Compute Engine]→[VMインスタンス]→[SSH]→[gcloudコマンドを表示]からコピペすればOKです。
`--` の後ろのコマンドは、通常のsshコマンドのオプションです。7199に対する動的ポート転送となります。

```
$ gcloud compute --project xxxxx ssh --zone xxxxx "tunnnel-server"  -- -N -D 7199
```

## jvisualvmでの接続

1. 下記コマンドでjvisualvmを起動します。<br>`$ jvisualvm -J-DsocksProxyHost=localhost -J-DsocksProxyPort=7199   -J-DsocksNonProxyHosts=` <br><br>
2. [リモートホストを追加]をクリックします。
<img src="https://qiita-image-store.s3.amazonaws.com/0/268550/5629a688-d984-be6c-cb06-d01c0c97e058.png" alt="jvisualvm01" width="600px">
<br><br>
3. [podのIP確認](#podのip確認) で確認したIPを入力します。<br><br>
4. [JMX接続を追加]をクリックします。
<img src="https://qiita-image-store.s3.amazonaws.com/0/268550/b0cd4160-89c4-fff2-0fd5-8c9754f6fbb1.png" alt="jvisualvm02" width="600px"><br><br>
5. 接続として、 `10.36.2.8:7199` を入力します。これ以外はデフォルトのままで大丈夫です。<br><br>
6. [開く]をクリックします。
<img src="https://qiita-image-store.s3.amazonaws.com/0/268550/f9762aae-0c86-0c56-11d9-7b1896e73b39.png" alt="jvisualvm03" width="600px"><br><br>
7. これで接続環境です。CPUプロファイリングなども問題なく利用できます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/268550/06070b1f-b311-18b1-c291-db7f4abec34b.png" alt="jvisualvm04" width="600px">


# 参考

- https://cloud.google.com/community/tutorials/ssh-tunnel-on-gce
- https://docs.oracle.com/javase/jp/8/docs/technotes/guides/net/proxies.html
- https://docs.oracle.com/javase/jp/8/docs/technotes/tools/windows/jvisualvm.html
- https://github.com/GoogleContainerTools/jib
- https://github.com/h-r-k-matsumoto/spring-boot-sample