web-dev-qa-db-ja.com

Java JMXを使用してEC2で実行されているインスタンスに接続する方法

Java AmazonのEC2クラスターで実行されているアプリケーションに接続できません。「JMXポート」(通常はRMIレジストリポート)の両方を許可していますおよび問題のインスタンスのセキュリティグループへのサーバーポート(ほとんどの作業を行います)。Jconsoleは接続しているように見えますが、ハングして情報が表示されません。

Javaを次のように実行しています。

Java -server -jar foo.jar other parameters here > Java.log 2>&1

私たちは試しました:

  • ポートにTelnetconnectしますが、情報は表示されません。
  • Ssh経由でremote-X11を使用してインスタンス自体でjconsoleを実行すると、接続して情報が表示されます。したがって、JREはローカルにエクスポートしています
  • セキュリティグループのすべてのポートを開きます。ウィー。
  • tcpdumpを使用して、トラフィックが他のポートに送信されないようにします。
  • ローカルでのシミュレーション。ローカルJREまたはネットワーク上の他の場所で実行されているJREには、同じアプリケーションパラメータを使用していつでも接続できます。

Java -version出力:

OpenJDK Runtime Environment (IcedTea6 1.11.5) (Amazon-53.1.11.5.47.amzn1-x86_64)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

余談ですが、私たちは Simple JMX パッケージを使用しています。これにより、RMIレジストリとサーバーポートの両方を設定できます。通常、RMIレジストリによって半ランダムに選択されます。次のJMX URIのようなものでこれを強制することもできます。

service:jmx:rmi://localhost:" + serverPort + "/jndi/rmi://:" + registryPort + "/jmxrmi"

最近では、サーバーとレジストリの両方に同じポートを使用しています。以前は、レジストリポートとしてXを使用し、X+1は、セキュリティグループのルールを簡単にするためのサーバーポートです。 jconsoleのレジストリポートまたは使用しているJMXクライアントに接続します。

AmazonのEC2クラスターで実行されているJavaアプリケーションへの接続に問題があります。

問題は2つの不足している設定の組み合わせであることがわかります。 1つ目は、JREがipv4を優先し、v6を優先しないことを強制します。これは(おそらく)v4アドレスを介して接続しようとしているため必要でした。

-Djava.net.preferIPv4Stack=true

実際のブロッカーは、JMXクライアントが接続するhostnameとポートで応答するRMIポートに最初に接続することによってJMXが機能するという事実でした。追加の設定なしで、リモートクライアントがルーティングできない10.X.X.X仮想アドレスであるボックスのローカルIPを使用します。サーバーのexternalホスト名またはIPである次の設定を追加する必要がありました。この場合、サーバーのエラスティックホスト名です。

-Djava.rmi.server.hostname=ec2-107-X-X-X.compute-1.amazonaws.com

EC2インスタンスを自動化しようとしている場合(そして、なぜそうしないのか)の秘訣は、実行時にこのアドレスを見つける方法です。これを行うには、アプリケーションのブートスクリプトに次のようなものを追加する必要があります。

# get our _external_ hostname
RMI_Host=`wget -q -O - http://169.254.169.254/latest/meta-data/public-hostname`
...
Java -server \
    -Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=$RMI_Host \
    -jar foo.jar other parameters here > Java.log 2>&1

上記のwgetコマンドの不可解な169.254.169.254 IPは、EC2インスタンスがそれ自体について要求できる情報を提供します。これには、認証済みの呼び出しでのみ使用可能なタグが含まれていないことに失望しています。

最初はextern ipv4アドレスを使用していましたが、起動時にJDKがサーバーポートへの接続を試みているようです。外部IPを使用している場合は、タイムアウトになるまでアプリケーションの起動時間が遅くなっていました。 public-hostnameはローカルで10ネットアドレスに解決され、外部でpublic-ipv4に解決されます。したがって、アプリケーションは高速で起動し、JMXクライアントは引き続き機能します。ウフー!

これが他の誰かを助けることを願っています。今日は3時間かかります。

JMXサーバーに強制的にサーバーおよびを指定したポートで起動して、EC2セキュリティグループでそれらをブロックできるようにするには、次の回答を参照してください。

特定のポートで実行されているrmiregistryを閉じる方法

編集:

この問題が再発しました。 Java JMXコードは、ボックスのホスト名に対していくつかのホスト名ルックアップを行っており、それらを使用してJMX接続の接続と確認を試みているようです。

この問題は、ボックスのローカルホスト名をボックスのローカルIPに解決する必要があるという要件のようです。たとえば、/etc/sysconfig/networkHOSTNAME=server1.foobar.comがある場合、server1.foobar.comでDNSルックアップを実行すると、10-NET仮想アドレスに到達するはずです。独自の/etc/hostsファイルを生成していましたが、ローカルホストのホスト名がファイルにありませんでした。これにより、アプリケーションが起動時に一時停止するか、まったく起動しなくなりました。

最後に

JMXの作成を単純化する1つの方法は、my SimpleJMXパッケージ を使用することです。

39
Gray

2番目の回答ごと Amazon EC2へのJMX接続が失敗する理由 、ここでの問題は、デフォルトでRMIポートがランダムに選択され、クライアントがJMXポートとRMIポートの両方にアクセスする必要があることです。 jdk7u4以降を実行している場合、RMIポートはアプリのプロパティで指定できます。次のJMX設定でサーバーを起動すると、うまくいきました。

認証なし:

-Dcom.Sun.management.jmxremote 
-Dcom.Sun.management.jmxremote.port=9999 
-Dcom.Sun.management.jmxremote.rmi.port=9998 
-Dcom.Sun.management.jmxremote.ssl=false 
-Dcom.Sun.management.jmxremote.authenticate=false 
-Djava.rmi.server.hostname=<public EC2 hostname>

認証あり:

-Dcom.Sun.management.jmxremote 
-Dcom.Sun.management.jmxremote.port=9999 
-Dcom.Sun.management.jmxremote.rmi.port=9998 
-Dcom.Sun.management.jmxremote.ssl=false 
-Dcom.Sun.management.jmxremote.authenticate=true 
-Dcom.Sun.management.jmxremote.password.file=/path/to/jmxremote.password
-Djava.rmi.server.hostname=<public EC2 hostname>

また、インスタンスのEC2セキュリティグループでポート9998〜9999を開きました。

14
mmindenhall

SSHトンネルを使用した少し異なるアプローチ

  1. (リモートマシン上)以下のフラグをJVMに渡します。

-Dcom.Sun.management.jmxremote.port=1099 -Djava.net.preferIPv4Stack=true -Dcom.Sun.management.jmxremote.ssl=false -Dcom.Sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=127.0.0.1

  1. (リモートマシン上で)どのポートを確認するJava使用を開始した

netstat -tulpn | grep Java

tcp 0 0 0.0.0.0:37484 0.0.0.0:* LISTEN 2904/Java tcp 0 0 0.0.0.0:1099 0.0.0.0:* LISTEN 2904/Java tcp 0 0 0.0.0.0:45828 0.0.0.0:* LISTEN 2904/Java

  1. (ローカルマシン上)すべてのポートにSSHトンネルを作成します

ssh -N -L 1099:127.0.0.1:1099 ubuntu@<ec2_ip> ssh -N -L 37484:127.0.0.1:37484 ubuntu@<ec2_ip> ssh -N -L 45828:127.0.0.1:45828 ubuntu@<ec2_ip>

  1. (ローカルマシン上)Java Mission Control by "localhost:1099"で接続します
6
Timofey

グレイの答えがうまくいきましたが、TCPポート0から65535まで開く必要があるか、入りません。私はと思いますメインのJMXポートに接続してから、別のポートを割り当てることができます このブログの投稿 から取得しました。

1
Eric Pugh