Dockerコンテナ内のJAVAプロセスに対してJMX接続する
外部からDockerコンテナ内のJAVAプロセスにJMX接続する場合、すんなり接続できませんでした。
大体のサイトでは、以下のようにすれば接続できると記載されてますが、このままコピペしてもJMX接続できません。
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote=TRUE
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.port=9990
-Dcom.sun.management.jmxremote.rmi.port=9990
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
なぜかというとDockerコンテナ上でJAVAプロセス起動しているということは
windows(JConsoleなどのJMXクライアント) => Dockerサーバ(IPアドレスXXX) => Dockerコンテナ(IPアドレスYYY)
のようにIPアドレスXXXを経由してDockerコンテナ(IPアドレスYYY)に接続しようとしていることです。
Dockerコンテナに対してJMX接続しているからNGで、特殊な方法が必要なのでは?ということはなく、以下のような構成になっているということです。
windows(JConsoleなどのJMXクライアント) => 踏み台サーバ => JAVAアプリが動いているサーバ
なので、直接JConsole=>Dockerコンテナ(IPアドレスYYY)には接続することができません。
Dockerコンテナへ「0.0.0.0:9990->9990/tcp」を設定しているだけではダメでした。
重要なところは、java.rmi.server.hostname、com.sun.management.jmxremote.port、com.sun.management.jmxremote.rmi.portで
java.rmi.server.hostnameは、JMXクライアントがJMXサーバのポート(com.sun.management.jmxremote.port)に接続した際に、
JMXサーバ=>JMXクライアントへここへ接続してくれ、というIPアドレスを教えるようです。
なのでここで設定するものは、Dockerサーバ(IPアドレスXXX)で、以下のようにする必要があります。
-Djava.rmi.server.hostname=Dockerサーバ(IPアドレスXXX)
次のJMXクライアントの動きとしては、com.sun.management.jmxremote.rmi.portのポートに接続しにいきますが
これが設定されていないとJMXサーバがランダムで決めるようです。
ということはDockerコンテナへ「0.0.0.0:9990->9990/tcp」を設定していても、com.sun.management.jmxremote.rmi.portのポートがランダムで決まってしまうため、9990以外のポートはJMXクライアントが接続できないため接続エラーとなってしまいます。
com.sun.management.jmxremote.rmi.portはcom.sun.management.jmxremote.portと同じポートでも問題ないため、9990にしてしまえば「0.0.0.0:9990->9990/tcp」が有効なため接続できるようになります。
最終的には以下のように設定する必要があります。
-Djava.rmi.server.hostname=Dockerサーバ(IPアドレスXXX)
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote=TRUE
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.port=9990 ※Dockerコンテナへ外部接続を許可したポート
-Dcom.sun.management.jmxremote.rmi.port=9990 ※Dockerコンテナへ外部接続を許可したポート
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false