JMX接続をひたすらやっていく

2017.12.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。齋藤です。

今回のこの記事はJava アドベントカレンダー 2017 4日目に向けた記事です。 今日はJMXと格闘した記録をここに書いておきます。

今回は以下の内容について記述します。

  • ローカルのDockerコンテナ上に立ち上げたJVMに対して JMX接続する
  • EC2上に立ち上げたJVMに対して JMX接続する
  • EC2上のDockerコンテナ上に立ち上げたJVMに対して JMX接続する

今回JMX接続先に利用するのはElasticsearchです。

やっていきます。

ローカルのDockerコンテナ上に立ち上げたJVMに対して JMX接続する

まずは手始めに、簡単なところから攻めていきます。 次のコマンドでElasticsearchを起動します。

docker run -d -it -e "ES_JAVA_OPTS=
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.rmi.port=9010 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.local.only=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9010" -p 9010:9010 -p 9200:9200 -p 9300:9300 docker.elastic.co/elasticsearch/elasticsearch:6.0.0

接続してみる

jconsoleの場合はこんな感じ。

jconsole service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi

jvisualvmの場合は 画面立ち上がってからJMX接続をUIで追加してください。

jvisualvm

EC2上に立ち上げたJVMに対して JMX接続する

今回はAmazon Linuxを使います。 インスタンスは t2.mediumです。

EC2(Amazon Linux) に Java8 をインストール

デフォルトのJavaは7なので とりあえず、Javaのインストールから始めます。 次のコマンドでだいたい入ります。

sudo yum install java-1.8.0-openjdk-devel.x86_64 -y
sudo alternatives --config java

EC2にElasticsearchをインストール

今度はElasticsearchのインストールです。

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.0.zip
# sha1sum elasticsearch-6.0.0.zip
unzip elasticsearch-6.0.0.zip
cd elasticsearch-6.0.0/

JMXを有効にしてElasticsearchを起動しておく

ES_JAVA_OPTSにJMXの設定を追加して Elasticsearchを起動しておきます。

ES_JAVA_OPTS="-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.rmi.port=9010 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=9010" \
elasticsearch-6.0.0/bin/elasticsearch > /dev/null &

socksプロトコルで接続できるようにしておく

参考1

ssh -i ~/.ssh/jmx-test.pem -fND 9091 ec2-user@$HOGE_EC2_IP

jconsoleで接続

jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=9200 -J-DsocksNonProxyHosts= service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi

visualvmで接続

jvisualvm -J-DsocksProxyHost=localhost -J-DsocksProxyPort=9200 -J-DsocksNonProxyHosts=

こっちだと動きませんでした。

jvisualvm -J-Dnetbeans.system_socks_proxy=localhost:9200 -J-Djava.net.useSystemProxies=true

EC2上で動いているDockerコンテナに対してJMX接続

今度はEC2上で Dockerを導入して、Docker コンテナとしてElasticsearchを立ち上げて そのElasticsearchに JMX 接続をしてみましょう。

Docker インストールする

sudo yum install docker -y

Docker のデーモンを立ち上げる

sudo service docker start

sudoなしでdockerコマンドを利用するために、ec2-user を docker グループに追加する

次のコマンドを実行すると、sudoなしでdockerコマンドが利用できる。(セキュリティにご注意ください。)

sudo usermod -a -G docker ec2-user

ログアウトしてログインするか、再起動すると次のようにsudoなしでdocker コマンドが利用できます。

docker ps

Elasticsearchを立ち上げるが、コケる。

docker run -it -e "ES_JAVA_OPTS=
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.rmi.port=9010 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.local.only=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9010" -p 9010:9010 -p 9200:9200 -p 9300:9300 docker.elastic.co/elasticsearch/elasticsearch:6.0.0

エラーが発生して落ちました。 次のエラーを見るに、file descriptor と vm.max_map_count が足りないとのこと。

[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
[2]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

Elasticsearchの起動のために設定を追加していく

ホストOSの設定を編集していきます。

まずは vm.max_map_count。 参考

sudo vim /etc/sysctl.conf
# 次の行を追加
vm.max_map_count=262144

次はfile descriptorの設定。これはOSの設定とdocker側の設定をいじります。 ちなみにdocker側の設定を分からず、あたふたしていました。 参考

まずはOS側。

sudo vim /etc/security/limits.conf
# 次の行を追加します
* soft nofile 1000000
* hard nofile 1000000

今度はdocker側の設定を編集します。 参考

sudo vim /etc/sysconfig/docker
# 次の行を追加
# OPTIONS="--default-ulimit nofile=1024:4096"
OPTIONS="--default-ulimit nofile=65536:1000000"

再起動したらだいたいいい感じ。

sudo reboot

というわけで、JMXを有効にして Elasticsearchを立ち上げる

設定をいじったおかげで最初実行した時と同じように次のコマンドで立ち上がりました。

docker run -it -e "ES_JAVA_OPTS=
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.rmi.port=9010 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.local.only=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9010" -p 9010:9010 -p 9200:9200 -p 9300:9300 docker.elastic.co/elasticsearch/elasticsearch:6.0.0

EC2上のDockerで立ち上がってるElasticsearchに対してJMX接続する

普通にEC2上で立ててる時と変わらない感じでアクセスできました。最高。

jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=9200 -J-DsocksNonProxyHosts= service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi
jvisualvm -J-DsocksProxyHost=localhost -J-DsocksProxyPort=9200 -J-DsocksNonProxyHosts=

まとめ

色々遠回りした感じはありますが、最終的に、EC2上のDockerコンテナ上のJVMに接続することができました。 普通にリモートのJVMに接続するのとあまり変わりない形になりました。

これは今回の記事にはあまり関係ないのですが visualvmのネットワーク設定画面を開こうとすると めちゃくちゃ重いことが気になりました・・・。