Java仮想マシン(Java VM)は組込みインストゥルメンテーションを備え、これによってJava Management Extensions (JMX)テクノロジを使用したモニターと管理を行うことができます。これらの組込み管理ユーティリティは通常、Java VMのアウトオブボックスの管理ツールと呼ばれます。適切に計測されたアプリケーションであれば、JMX APIを使用してモニターできます。
すぐに使用できるJMXエージェントを有効にして、Java VMのモニターと管理ができるように構成するには、Java VMの起動時に特定のシステム・プロパティを設定する必要があります。システム・プロパティは、コマンド行で次のように設定します。
java -Dproperty=value ...
このようにシステム・プロパティはいくつでも設定できます。管理プロパティは、値を指定しないとデフォルト値に設定されます。すぐに使用できる管理プロパティの完全なセットについては、表2-1を参照してください。すぐに使用できるモニタリングと管理のプロパティのセクションで説明しているように、構成ファイルでシステム・プロパティを設定することもできます。
注意:
コマンド行からJava VMを実行するには、パスにJRE_HOME/binを追加する必要があります。JRE_HOMEはJava Runtime Environment (JRE)実装が入ったディレクトリです。または、コマンドを入力するときにフルパスを入力することもできます。Java HotSpot VMでサポートされているコマンド行オプションの構文と完全なセットについては、Java Platform, Standard Editionツール・リファレンスのJavaアプリケーション・ランチャのセクションを参照してください。
JMX APIを使用してJavaプラットフォームをモニターするには、次の手順を実行する必要があります。
Java VMの起動時にJMXエージェント(プラットフォームMBeanサーバーの別名)を有効にします。JMXエージェントの有効範囲は次のとおりです。
ローカル・モニタリング、ローカル・システムで実行されるクライアント管理アプリケーション。
リモート・モニタリング、リモート・システムで実行されるクライアント管理アプリケーション。
JMX仕様に準拠したツール(JConsoleなど)でJava VMをモニターします。JConsoleの使用を参照してください。
以前は、Java VMまたはJavaアプリケーションの起動時に、JMXクライアントがローカルJava VMにアクセスできるように次のプロパティを設定していました。
com.sun.management.jmxremote
このプロパティを設定すると、Java VMプラットフォームのMBeanが登録され、プライベート・インタフェースを介してRemote Method Invocation (RMI)コネクタが公開されました。この設定により、JMXクライアント・アプリケーションでローカルJavaプラットフォーム(つまり、JMXクライアントと同じマシンで実行されているJava VM)をモニターすることが可能になります。
現在のJava SEプラットフォームでは、このシステム・プロパティの設定は必要ありません。どのアプリケーションでも、現在のJava SEプラットフォームで起動したものであればAttach APIがサポートされ、ローカル・モニタリングと管理が必要な場合は自動的に使用可能になります。
たとえば、以前ならJava SEのサンプル・アプリケーションNotepadでJMXエージェントを有効にするには、次のコマンドを実行する必要がありました。
% cd JDK_HOME/demo/jfc/Notepad
% java -Dcom.sun.management.jmxremote -jar Notepad.jar
前述のコマンドのJDK_HOMEは、Java Development Kit (JDK)がインストールされるディレクトリです。現在のJava SEプラットフォームでは、次のコマンドを実行してNotepadを起動します。
% java -jar Notepad.jar
Notepadの起動後、Attach APIを使用するJMXクライアントでアウトオブボックスの管理エージェントを有効にして、Notepadアプリケーションのモニターと管理を行うことができます。
注意:
Windowsプラットフォームではセキュリティ上の理由から、ローカル・モニタリングと管理がサポートされるのは、デフォルトの一時ディレクトリが、ファイルおよびディレクトリのアクセス権が設定可能なファイル・システム(たとえば、New Technology File System (NTFS)ファイル・システム)にある場合にかぎられます。アクセス制御が不十分なFile Allocation Table (FAT)ファイル・システムではサポートされません。JConsoleを使用したローカルのモニタリングは、開発とプロトタイプの作成に役立ちます。JConsoleのローカルな使用は、本番環境ではお薦めしません。JConsole自体が相当のシステム・リソースを消費するためです。JConsoleはリモート・システムで使用し、モニター対象のプラットフォームから分離した方がよいでしょう。
それでもローカルのモニタリングにJConsoleを使用する場合は、コマンド・シェルにjconsoleと入力してツールを起動します。引数なしでjconsoleを起動すると、ローカルのJavaアプリケーションがすべて自動検出され、モニター対象とするアプリケーションを選択できるダイアログ・ボックスが表示されます。JConsoleとアプリケーションはどちらも、同じユーザーが実行する必要があります。モニタリングおよび管理システムには、オペレーティング・システムのファイル・アクセス権を使用するためです。
注意:
コマンド行からJConsoleを実行するには、JDK_HOME/binをパスに追加する必要があります。または、コマンドを入力するときにフルパスを入力することもできます。JConsoleの使用を参照してください。デフォルトでは、ローカルで作成されたリモート・オブジェクトについて、クライアントに送信されるリモート・スタブにローカル・ホストのIPアドレスがdotted-quad形式で含まれます。リモート・スタブを特定のインタフェース・アドレスと関連付けるには、java.rmi.server.hostnameシステム・プロパティをそのインタフェースのIPアドレスに設定する必要があります。
リモート・システムからモニタリングと管理を行うには、Java VM起動時に次のシステム・プロパティを設定する必要があります。
com.sun.management.jmxremote.port=portNum
portNumはJMX RMI接続に使用するポート番号です。必ず未使用のポート番号を指定してください。ローカル・アクセス用にRMIコネクタが公開されるのに加えて、このプロパティを設定することにより、jmxrmiという名前を使用して、指定したポートの非公開の読取り専用レジストリに追加のRMIコネクタが公開されます。システム・プロパティを使用してRMIコネクタがバインドされるポート番号: com.sun.management.jmxremote.rmi.port
必ず未使用のポート番号を使用してください。
注意:
セキュリティ用に設定するプロパティに加えて、前述のシステム・プロパティを設定する必要があります。リモート・モニタリングと管理には、権限のない人がアプリケーションの制御やモニターができないように、セキュリティが必要です。デフォルトで、SSL (secure sockets layer)経由のパスワード認証とTLS (Transport Layer Security)が有効になっています。パスワード認証とSSLは別々に無効にすることができます。
Javaプラットフォームでは、認証にプラガブルなログイン・モジュールがサポートされます。組織の認証インフラストラクチャに応じて、任意のログイン・モジュールをプラグインできます。LDAP認証の使用では、Lightweight Directory Access Protocol (LDAP)ベースの認証にcom.sun.security.auth.module.LdapLoginModuleモジュールをプラグインする方法について説明します。
JMXエージェントをリモートで使用可能にすると、「JConsoleによるリモート・モニタリング」に説明するように、JConsoleでアプリケーションをモニタリングできます。プログラムから管理エージェントに接続する方法については、「プログラムによるJMXエージェントへの接続」を参照してください。
このセクションでは、要件に応じて実装可能な異なるパスワード認証方式について説明します。
JMXエージェントでのJMXAuthenticatorの実装は、Java認証・承認サービス(JAAS)テクノロジに基づいています。認証は、ユーザー資格証明をJAASのjavax.security.auth.spi.LoginModuleオブジェクトに渡すことで実行されます。 com.sun.security.auth.module.LdapLoginModuleクラスは、LDAPを使用した認証を可能にします。デフォルトのLoginModuleクラスをLdapLoginModuleクラスで置き換えることができます。
必要なビジネス組織で機能するJAAS構成ファイルを作成します。構成ファイル(ldap.config)の例を次に示します。
ExampleCompanyConfig {
com.sun.security.auth.module.LdapLoginModule REQUIRED
userProvider="ldap://example-ds/ou=people,dc=examplecompany,dc=com"
userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))"
authzIdentity=monitorRole;
};
構成ファイルに示されているオプションの概要を次に示します。
com.sun.security.auth.module.LdapLoginModule REQUIREDオプションは、認証全体を正常に行うためにLdapLoginModuleを使用した認証が必要なことを意味します。 userProviderオプションは、LDAPサーバー、およびユーザー・エントリがあるディレクトリ・ツリー内の位置を特定します。 userFilterオプションは、LDAPディレクトリ内のユーザー・エントリの検索に使用する検索フィルタを指定します。フィルタを使用してディレクトリを検索する前に、トークン{USERNAME}はユーザー名と置き換えられます。authzIdentityオプションは、認証されたユーザーのアクセス・ロールを指定します。例では、認証されたユーザーはmonitorRoleを持ちます。アクセス・ファイルを参照してください。コード例に示されている構成オプションの詳細は、com.sun.security.auth.module.LdapLoginModuleクラスを参照してください。
コマンド行で次のプロパティを設定して、アプリケーションを起動します。
com.sun.management.jmxremote.login.config: このプロパティは、指定したJAAS構成エントリを使用するようJMXエージェントを構成します。java.security.auth.login.config: このプロパティは、JAAS構成ファイルへのパスを指定します。コマンド行の例を次に示します。
java -Dcom.sun.management.jmxremote.port=5000
-Dcom.sun.management.jmxremote.login.config=ExampleCompanyConfig
-Djava.security.auth.login.config=ldap.config
-jar MyApplication.jar
JMXエージェントによってサポートされるファイルベースのパスワード認証メカニズムは、パスワードをクリアテキストで格納し、開発での使用のみを目的としています。本番での使用の場合、認証にSSLクライアント証明書を使用するか、セキュアなログイン構成をプラグインすることをお薦めします。
注意:
警告: クライアントがセキュアではないRMIレジストリ(デフォルト)からリモート・コネクタを取得すると、リモート・コネクタからのパスワード認証でセキュリティの問題が発生する可能性があります。ターゲット・サーバー上で正当なRMIレジストリが起動する前に攻撃者が偽のRMIレジストリを起動すれば、クライアントのパスワードを盗むことができます。このシナリオは、システム・プロパティcom.sun.management.jmxremote.port=portNumでリモート管理を有効にしてJava VMを起動する場合も当てはまります。SSLが有効になっていても同じです。このような攻撃者は発見されることが多いものの、脆弱性があることは確かです。デフォルトでは、リモート・モニタリングでJMXエージェントを有効にすると、JMXエージェントはパスワード認証を使用します。ただし、パスワードを設定する方法は、シングル・ユーザー環境かマルチユーザー環境かによって異なります。
パスワードはパスワード・ファイルにクリアテキストで格納されるため、通常のユーザー名とパスワードをモニタリング用に使用することはお薦めできません。代わりに、monitorRoleおよびcontrolRoleなどのパスワード・ファイルで指定したユーザー名を使用します。パスワードとアクセス・ファイルの使用を参照してください。
JRE_HOME/lib/managementディレクトリのパスワード・ファイルを、次のように設定します。
jmxremote.password.templateをjmxremote.passwordにコピーします。monitorRoleやcontrolRoleなどのロールのパスワードを追加します。JRE_HOME/lib/managementディレクトリのパスワード・ファイルを、次のように設定します。
jmxremote.password.templateをホーム・ディレクトリにコピーし、そのファイル名をjmxremote.passwordに変更します。monitorRoleやcontrolRoleなどのロールのパスワードを追加します。com.sun.management.jmxremote.password.file=pwFilePath
前述のプロパティのpwFilePathは、パスワード・ファイルへのパスです。
リモート・モニタリングのパスワード認証は、デフォルトで有効になっています。パスワード認証を無効にするには、Java VMの起動時に次のシステム・プロパティを設定します。
com.sun.management.jmxremote.authenticate=false
注意:
警告: この構成はセキュアではありません。JMXポート番号およびホスト名を知っている(または推測する)リモート・ユーザーならだれでも、Javaアプリケーションおよびプラットフォームのモニターと制御ができます。開発用には許容される場合があっても、実稼動システムにはお薦めしません。パスワード認証を無効にする場合、「セキュリティの無効化」で説明しているようにSSLを無効にすることもできます。SSLクライアント認証の有効化で説明しているように、パスワードを無効にしてSSLクライアント認証を使用することもできます。
リモート・モニタリングおよび管理を有効にすると、SSLはデフォルトで有効になっています。SSLを使用するには、JMXエージェント(MBeanサーバー)が稼動するシステム上でデジタル証明書を設定して、次にSSLを正しく構成する必要があります。コマンド行ユーティリティkeytoolを使用して、証明書を操作します。
SSLを設定する一般的な手順は次のとおりです。
keytool -genkeyコマンドで鍵ペアを生成します。
keytool -certreqコマンドで認証局(CA)に署名付き証明書を要求します。
keytool -importコマンドで、証明書をキーストアにインポートします。keytoolのドキュメントで証明書のインポートを参照してください。
javax.net.ssl.keyStore |
キーストアの場所 |
javax.net.ssl.keyStoreType |
デフォルトのキーストア・タイプ |
javax.net.ssl.keyStorePassword |
デフォルトのキーストア・パスワード |
javax.net.ssl.trustStore |
トラストストアの場所 |
javax.net.ssl.trustStoreType |
デフォルトのトラストストア・タイプ |
javax.net.ssl.trustStorePassword |
デフォルトのトラストストア・パスワード |
システム・プロパティの設定については、システム・プロパティの設定のセクションを参照してください。
参照:
Java Platform, Standard Editionセキュリティ開発者ガイドのデフォルトのキーストアとトラストストア、ストア・タイプ、およびストア・パスワードのカスタマイズ
リモート・アプリケーションのモニタリングで接続を設定するとき、SSLで保護されているRMIレジストリにRMIコネクタ・スタブをオプションでバインドできます。これにより、適切なSSL証明書を持つクライアントは、RMIレジストリに登録されたコネクタ・スタブを取得できます。RMIレジストリをSSLで保護するには、次のシステム・プロパティを設定する必要があります。
com.sun.management.jmxremote.registry.ssl=true
このプロパティがtrueに設定されている場合、Java VMの起動時に、すぐに使用できる管理エージェントによって、SSLで保護されたRMIレジストリの生成および構成が行われます。このプロパティのデフォルト値はfalseです。ただし、このプロパティはtrueに設定することをお薦めします。このプロパティがtrueに設定されている場合、全面的なセキュリティを施すため、SSLクライアント認証を有効にする必要もあります。
SSLクライアント認証を有効にするには、Java VMの起動時に次のシステム・プロパティを設定します。
com.sun.management.jmxremote.ssl.need.client.auth=true
クライアントSSL認証を使用するには、SSLを有効(デフォルトはfalseに設定されます)にしておく必要があります。このプロパティはtrueに設定することをお薦めします。この構成では、クライアント・システムが有効なデジタル証明書を持つ必要があります。「SSLの使用」の説明に従って、クライアント・システムに証明書をインストールし、SSLを構成する必要があります。前のセクションで述べたように、RMIレジストリのSSL保護を有効にした場合は、クライアントSSL認証をtrueに設定する必要があります。
リモート・モニタリングでSSLを無効にするには、Java VMの起動時に次のシステム・プロパティを設定する必要があります。
com.sun.management.jmxremote.ssl=false
パスワード認証は、「パスワード認証の無効化」の手順に従って無効にしないかぎり、必要になります。
パスワード認証とSSLの両方を無効(つまりすべてのセキュリティを無効)にするには、Java VMの起動時に次のシステム・プロパティを設定する必要があります。
com.sun.management.jmxremote.authenticate=false com.sun.management.jmxremote.ssl=false
注意:
警告: この構成はセキュアではありません。ポート番号およびホスト名を知っている(または推測する)リモート・ユーザーならだれでも、Javaアプリケーションおよびプラットフォームのモニターと制御ができます。さらに、危害の可能性はMBeanで定義する操作に限定されません。最低限のセキュリティ・マネージャもない場合、リモート・クライアントはjavax.management.loading.MLet MBeanを作成し、それを使用して任意のURLから新しいMBeanを作成できます。つまり、リモート・クライアントから、Javaアプリケーションに任意のコードを実行させることができるということです。このような理由から、セキュリティの無効化は、開発時には許容される場合があっても、実稼動システムのセキュリティでは行わないことを強くお薦めします。
SSLが有効な状態でリモート・アプリケーションをモニターするには、JConsoleが稼動しているシステムでtruststoreファイルを設定し、SSLを正しく構成する必要があります。たとえば、keystoreファイルを作成し、次のコマンドでアプリケーション(この例ではServer)を起動します。
% java -Djavax.net.ssl.keyStore=keystore \ -Djavax.net.ssl.keyStorePassword=password Server
Java Platform, Standard Editionセキュリティ開発者ガイドのデフォルトのキーストアとトラストストア、ストア・タイプ、およびストア・パスワードのカスタマイズを参照してください。
keystoreファイルを作成してServerアプリケーションを起動する場合、次のようにJConsoleを起動します。
% jconsole -J-Djavax.net.ssl.trustStore=truststore \ -J-Djavax.net.ssl.trustStorePassword=trustword
JConsoleの使用を参照してください。
この構成により認証されるのは、サーバーのみです。クライアントSSL認証が設定されている場合、同様のkeystoreファイルをJConsoleのキーに渡し、該当するtruststoreファイルをアプリケーションに渡す必要があります。
パスワードおよびアクセス・ファイルは、リモート・モニタリングおよび管理のセキュリティを制御します。これらのファイルは、デフォルトではJRE_HOME/lib/managementにあり、標準のJavaプロパティ・ファイル・フォーマットです。フォーマットに関する詳細は、java.util.Propertiesパッケージの「APIリファレンス」を参照してください。
パスワード・ファイルは、各種ロールとそのパスワードを定義します。アクセス制御ファイル(デフォルトでは、jmxremote.access)は、ロールごとに許可するアクセス権を定義します。ロールを機能させるには、パスワードとアクセス・ファイルの両方にエントリを持つ必要があります。
JRE実装には、jmxremote.password.templateというパスワード・ファイル・テンプレートがあります。このファイルをホーム・ディレクトリのjre_home/lib/management/jmxremote.passwordにコピーして、アクセス・ファイルで定義したロールのパスワードを追加します。
パスワード・ファイルにはパスワードがクリアテキストで含まれるため、必ず所有者だけがこのファイルへの読取りおよび書込みアクセス権を持つようにしてください。セキュリティ上の理由から、システムは所有者だけがファイルを読取り可能であるか確認し、そうでない場合はエラーとして終了します。このため、マルチユーザー環境では、パスワード・ファイルをホーム・ディレクトリなどの非公開の場所に保存する必要があります。
プロパティ名はロールで、関連付けられた値はロールのパスワードです。例2–1に、パスワード・ファイルのエントリの例を示します。
例 2-1パスワード・ファイルの例
# specify actual password instead of the text password monitorRole password controlRole password
Solaris、LinuxまたはmacOSオペレーティング・システムで、パスワード・ファイルのファイル・アクセス権を設定するには、次のコマンドを実行します。
chmod 600 jmxremote.password
デフォルトでは、アクセス・ファイルはjmxremote.accessという名前です。プロパティ名はパスワード・ファイルと同じ領域のIDです。関連する値はreadonlyまたはreadwriteのいずれかにする必要があります。
アクセス・ファイルはロールとそのアクセス・レベルを定義します。デフォルトでは、アクセス・ファイルは次の主要なロールを定義します。
monitorRole: モニタリングのための読取り専用アクセスを許可します。
controlRole: モニタリングおよび管理のために読取り/書込みアクセスを許可します。
readonly: MBeanの属性の読取りアクセスを許可します。これは、モニタリングの場合、このロールのリモート・クライアントから測定値を読み取ることはできるが、実行中のプログラムの環境を変更するアクションは実行できないという意味です。リモート・クライアントはMBeanの通知を待機することもできます。
readwrite: MBeanの属性の読取りおよび書込み、MBeanの属性への操作の呼び出し、MBeanの属性の作成または削除のためのアクセスを許可します。アプリケーションの操作を妨げる可能性があるため、このアクセス権は信頼できるクライアントのみに許可する必要があります。
ロールは、アクセス・ファイル内で1つのエントリだけを持つ必要があります。ロールにエントリがない場合、アクセス権はありません。ロールに複数のエントリがある場合、最後のエントリが優先されます。アクセス・ファイルの事前定義された一般的なロールには、例2-2に示すようなものがあります。
例 2-2アクセス・ファイルの例
# The "monitorRole" role has readonly access. # The "controlRole" role has readwrite access. monitorRole readonly controlRole readwrite
SSLが無効な状態でリモート・アプリケーションをモニターするには、次のコマンドでJConsoleを起動します。
% jconsole hostName:portNum
ホスト名とポート番号を省略して、JConsoleが提供するダイアログ・ボックスに入力することもできます。
すぐに使用できるモニタリングおよび管理のプロパティは、構成ファイルまたはコマンド行で設定できます。コマンド行で指定したプロパティにより、構成ファイル内のプロパティをオーバーライドします。構成ファイルのデフォルトの場所は、jre_home/lib/management/management.propertiesです。次のいずれかのコマンド行プロパティが設定されている場合、Java VMはこのファイルを読み取ります。
com.sun.management.jmxremote
com.sun.management.jmxremote.port
SNMP (Simple Network Management Protocol)による管理では、同じ構成ファイルを使用します。SNMPモニタリングと管理を参照してください。
次のコマンド行オプションで、構成ファイルに別の場所を指定できます。
com.sun.management.config.file=ConfigFilePath
ConfigFilePathは、構成ファイルへのパスです。
表2-1に、すぐに使用できるモニタリングおよび管理のプロパティを示します。
表2-1 すぐに使用できるモニタリングおよび管理のプロパティ
| プロパティ | 説明 | 値 |
|---|---|---|
|
JMXコネクタを使用して、JMXリモート・エージェントおよびローカル・モニタリングを有効にします。このエージェントは、JConsoleおよび(Attach APIを使用する)その他のローカルJMXクライアントによって使用されるプライベート・インタフェースで公開されます。JConsoleがこのコネクタを使用できるのは、エージェントを起動したユーザーがそのコネクタも起動した場合です。このコネクタからの要求については、パスワードまたはアクセス・ファイルはチェックされません。 |
|
|
JMXリモート・エージェントを有効にして、リモートJMXコネクタを作成し、指定したポートで待機します。デフォルトでは、SSL、パスワード、およびアクセス・ファイル・プロパティがこのコネクタに使用されます。また、 |
ポート番号。デフォルトなし。 |
|
RMIコネクタ・スタブを、SSLで保護されたRMIレジストリにバインドします。 |
|
|
SSLを使用してセキュアなモニタリングを可能にします。値が |
|
|
有効にするSSL/TLSプロトコル・バージョンのカンマ区切りのリストを表示します。 |
デフォルトのSSL/TLSプロトコル・バージョン。 |
|
有効にするSSL/TLS暗号化方式のカンマ区切りのリストを表示します。 |
デフォルトのSSL/TLS暗号化方式。 |
|
このプロパティが このプロパティは |
|
|
このプロパティが |
|
|
パスワード・ファイルの場所を指定します。 |
|
|
アクセス・ファイルの場所を指定します。 |
|
|
JMXエージェントがユーザーを認証する場合に使用するJAAS (Java認証・承認サービス)ログイン構成エントリの名前を指定します。このプロパティを使用してデフォルトのログイン構成をオーバーライドする場合は、指定された構成エントリがJAASでロードされたファイルに存在する必要があります。また、構成で指定されたログイン・モジュールは、名前とパスワードのコールバックを使用してユーザーの資格証明を取得する必要があります。詳細は、 |
デフォルトのログイン構成は、ファイルベースのパスワード認証です。 |
JMXエージェントを有効にしたら、クライアントから次のURLを使用してモニタリング・サービスにアクセスできます。
service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi
クライアントがエージェントのコネクタを作成するには、例2-3のように、URLを使用してjavax.management.remote.JMXServiceURLオブジェクトをインスタンス化した後、JMXConnectorFactory.connectメソッドを使用して接続を作成します。
例 2-3 JMXConnectorFactory.connectを使用した接続の作成
JMXServiceURL u = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://" + hostName + ":" + portNum + "/jmxrmi"); JMXConnector c = JMXConnectorFactory.connect(u);
Attach APIを使用するJMXクライアントを作成することで、Java SE 10プラットフォームで起動する任意のアプリケーションに対して、すぐに使用できるモニタリングおよび管理を有効化できます。アプリケーションの起動時にモニター対象として構成する必要はありません。Attach APIは、ツールによってターゲット・アプリケーションのエージェントに接続し、それらのエージェントを起動します。エージェントが起動すれば、JMXクライアント(やその他のツール)は、そのエージェントにかわってJava VMが保持するプロパティ・リストを使用して、そのエージェントのJMXコネクタ・アドレスを取得できます。このリストに含まれるプロパティは、Attach APIを使用するツールからアクセスできます。したがって、アプリケーションから起動したエージェントが構成情報を示すプロパティを生成した場合、その構成情報はアプリケーションに接続するツールから利用できます。
JMXエージェントは、ローカルのJMXコネクタ・サーバーのアドレスからプロパティを生成します。これによって、JMXツールは、起動中のエージェントのコネクタ・アドレスを取得し、これに接続できます。
例 2-4に示すコードをJMXツールで使用すれば、ターゲットVMに接続し、JMXエージェントのコネクタ・アドレスを取得し、これに接続することができます。
例2-4 コネクタへのJMXツールの接続とエージェントのアドレスの取得
static final String CONNECTOR_ADDRESS =
"com.sun.management.jmxremote.localConnectorAddress";
// attach to the target application
VirtualMachine vm = VirtualMachine.attach(id);
// get the connector address
String connectorAddress =
vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
// no connector address, so we start the JMX agent
if (connectorAddress == null) {
vm.startLocalManagementAgent();
// agent is started, get the connector address
connectorAddress =
vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
}
// establish connection to connector server
JMXServiceURL url = new JMXServiceURL(connectorAddress);
JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
例 2-4は、com.sun.tools.attach.VirtualMachineクラスのattach()メソッドを使用して、指定されたJava VMに接続することにより、ターゲットJava VMが稼動中のエージェントに代わって保持するプロパティを、指定されたJava VMで読み取ることができるようになっています。エージェントがすでに実行中の場合は、VirtualMachineクラスのgetAgentProperties()メソッドを呼び出し、そのエージェントのアドレスを取得します。ローカル・コネクタ・アドレスcom.sun.management.jmxremote.localConnectorAddressについて、getAgentProperties()メソッドは文字列プロパティを返します。これを使用すれば、ローカルのJMXエージェントに接続できます。
実行中のエージェントがない場合、jre_home/lib/management-agent.jarからいずれかのエージェントがVirtualMachineクラスによってロードされます。そのコネクタ・アドレスはgetAgentProperties()によって取得されます。
次に、エージェントへの接続を確立するには、このコネクタ・アドレスから構築されたJMXサービスURLのJMXConnectorFactory.connectを呼び出します。
注意:
JDK 10で、Attach APIを使用して、別のdockerプロセスで実行されているjavaプロセスに接続するための新しいサポートが追加されました。Dockerコンテナ内の仮想マシンとLinuxホストの接続を試みる場合は、接続先のJVMのPIDをAttach APIに提供する必要があります。
jpsおよびjcmd -1では別のDockerインスタンス上で実行されているプロセスをリストしないため、プロセスのPIDを取得できません。psなどのツールを使用してPIDを参照し、そのPIDを受け入れるツールのコマンド行にPIDを指定する必要があります。
jmcでは、別のDockerプロセスで実行されているjavaプロセスをリストしません。これらのPIDをツールに明示的に指定する方法は不明です。
すぐに使用できる管理エージェントへのリモート・アクセスは、認証・承認に加え、SSL暗号化によって保護されています。構成を実行するには、システム・プロパティを設定するか、management.propertiesファイルを定義します。ほとんどの場合、すぐに使用できる管理エージェントを使用し、これをmanagement.propertiesファイルで構成すれば、リモートJava VMをセキュアに管理するのに十分です。ただし、さらに高いレベルのセキュリティが必要な場合もあれば、システム構成によってはmanagement.propertiesファイルを使用できない場合もあります。このような場合には、ファイアウォールを通過できるようにRMIサーバーのリモート・オブジェクトを特定のポートにエクスポートすることや、マルチホーム・システムで特定のネットワーク・インタフェースを使用してRMIサーバーのリモート・オブジェクトをエクスポートすることが必要になる場合もあります。このような場合、JMXリモートAPIを使用して直接プログラムから管理エージェントの作成、構成、配備を行うことで、すぐに使用できる管理エージェントの動作を模倣できます。
このセクションでは、すぐに使用できる管理エージェントをまったく同じものとして模倣するJMXエージェントの実装方法を例示します。すぐに使用できる管理エージェントとまったく同様に、例2-5で作成するエージェントはポート3000で実行されます。このエージェントは、password.propertiesというパスワード・ファイルとaccess.propertiesというアクセス・ファイルを持ち、SSL/TLSベースのRMIソケット・ファクトリのデフォルトの構成を実装し、サーバー認証のみを必要とします。この例は、「SSLの使用」で説明しているように、keystoreがすでに作成されていることが前提です。SSL構成の設定方法の詳細は、Java Platform, Standard Editionセキュリティ開発者ガイドのJSSEで使用するキーストアの作成のセクションを参照してください。
すぐに使用できるJMXエージェントを構成で使用してcom.example.MyAppというアプリケーションのモニタリングと管理を有効にするには、次のコマンドでcom.example.MyAppを実行します。
% java -Dcom.sun.management.jmxremote.port=3000 \
-Dcom.sun.management.jmxremote.password.file=password.properties \
-Dcom.sun.management.jmxremote.access.file=access.properties \
-Djavax.net.ssl.keyStore=keystore \
-Djavax.net.ssl.keyStorePassword=password \
com.example.MyApp
注意:
com.sun.management.jmxremote.*プロパティは、コマンド行で渡すかわりに、management.propertiesファイルで指定することもできます。その場合は、システム・プロパティ-Dcom.sun.management.config.file=management.propertiesで、management.propertiesファイルの場所を指定する必要があります。例2-5は、com.example.MyAppで前述のコマンドを使用した場合とまったく同じモニタリングおよび管理ができるJMXエージェントをプログラムによって作成する場合に、記述が必要なコードを示しています。
例2-5 プログラムによるすぐに使用できるJMXエージェントの模倣
package com.example;
import java.lang.management.*;
import java.rmi.registry.*;
import java.util.*;
import javax.management.*;
import javax.management.remote.*;
import javax.management.remote.rmi.*;
import javax.rmi.ssl.*;
public class MyApp {
public static void main(String[] args) throws Exception {
// Ensure cryptographically strong random number generator used
// to choose the object number - see java.rmi.server.ObjID
//
System.setProperty("java.rmi.server.randomIDs", "true");
// Start an RMI registry on port 3000.
//
System.out.println("Create RMI registry on port 3000");
LocateRegistry.createRegistry(3000);
// Retrieve the PlatformMBeanServer.
//
System.out.println("Get the platform's MBean server");
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// Environment map.
//
System.out.println("Initialize the environment map");
HashMap<String,Object> env = new HashMap<String,Object>();
// Provide SSL-based RMI socket factories.
//
// The protocol and cipher suites to be enabled will be the ones
// defined by the default JSSE implementation and only server
// authentication will be required.
//
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf);
// Provide the password file used by the connector server to
// perform user authentication. The password file is a properties
// based text file specifying username/password pairs.
//
env.put("jmx.remote.x.password.file", "password.properties");
// Provide the access level file used by the connector server to
// perform user authorization. The access level file is a properties
// based text file specifying username/access level pairs where
// access level is either "readonly" or "readwrite" access to the
// MBeanServer operations.
//
env.put("jmx.remote.x.access.file", "access.properties");
// Create an RMI connector server.
//
// As specified in the JMXServiceURL the RMIServer stub will be
// registered in the RMI registry running in the local host on
// port 3000 with the name "jmxrmi". This is the same name that the
// ready-to-use management agent uses to register the RMIServer
// stub.
//
System.out.println("Create an RMI connector server");
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:3000/jmxrmi");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
// Start the RMI connector server.
//
System.out.println("Start the RMI connector server");
cs.start();
}
}
次のコマンドでこのアプリケーションを起動します。
java -Djavax.net.ssl.keyStore=keystore \
-Djavax.net.ssl.keyStorePassword=password \
com.example.MyApp
com.example.MyAppアプリケーションにより、JMXエージェントが有効になり、Javaプラットフォームのすぐに使用できる管理エージェントを使用した場合とまったく同様にモニタリングと管理が行われます。ただし、すぐに使用できる管理エージェントで使用するRMIレジストリとそれを模倣した管理エージェントで使用するRMIレジストリとでは、わずかながら重要な違いが1つあります。すぐに使用できる管理エージェントで使用するRMIレジストリは読取り専用です。つまり、これにバインドできるのは単一のエントリであり、一度バインドされたエントリはアンバインドできません。これは例2-5で作成されたRMIレジストリには当てはまりません。
そのほか、どちらのRMIレジストリも、SSL/TLSを使用しないため、セキュアではありません。RMIレジストリは、クライアント認証を必要とするSSL/TLSベースのRMIソケット・ファクトリを使用して作成する必要があります。そうすれば、クライアントの資格証明が悪意のあるRMIサーバーに送信されることはなく、RMIレジストリが信頼できないクライアントにRMIサーバー・スタブへのアクセスを許すこともありません。
SSL/TLS RMIソケット・ファクトリを実装するRMIレジストリは、management.propertiesファイルに次のプロパティを追加することで作成できます。
com.sun.management.jmxremote.registry.ssl=true com.sun.management.jmxremote.ssl.need.client.auth=true
例2-5では、すぐに使用できるJMXエージェントの主な動作を模倣していますが、management.propertiesファイルにある既存のプロパティのすべてを複製しているわけではありません。ただし、com.example.MyAppを適切に変更すれば、別のプロパティを追加できます。
例2-5のコードを使用すればファイアウォールを介してアプリケーションのモニターができますが、すぐに使用できるモニタリング・ソリューションではこれができない場合もあります。com.sun.management.jmxremote.port管理プロパティによりRMI Registryが接続可能なポートが指定されますが、RMIServerおよびRMIConnectionリモート・オブジェクトがエクスポートされるポートは、RMIスタックにより選択されます。リモート・オブジェクト(RMIServerとRMIConnection)を指定されたポートにエクスポートするには、例2-5のように、プログラムによってRMIコネクタ・サーバーを作成する必要があります。ただし、JMXServiceURLは次のように指定する必要があります。
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost:" +
port1 + "/jndi/rmi://localhost:" + port2 + "/jmxrmi");
port1はRMIServerおよびRMIConnectionリモート・オブジェクトがエクスポートされるポート番号、port2はRMIレジストリのポート番号です。
Java SEプラットフォームは、Javaプログラミング言語エージェントによりJava VMで実行中のプログラムを計測するサービスを提供します。インストゥルメンテーション・エージェントを作成すれば、アプリケーションをモニターする場合、そのアプリケーションに新しいコードを追加する必要がなくなります。モニタリングと管理は、アプリケーションのstatic mainメソッドに実装するのではなく、別のエージェント・クラスに実装し、-javaagentオプションを指定することでアプリケーションを起動します。エージェント・クラスを作成してアプリケーションを計測する方法の詳細は、java.lang.instrumentパッケージのAPIリファレンス・ドキュメントを参照してください。
次の手順は、com.example.MyAppのコードを改変して、エージェントにモニタリングおよび管理用の他のアプリケーションを計測させる方法を示しています。
com.example.MyAgentクラスを作成します。 com.example.MyAgentというクラスを作成し、mainメソッドではなくpremainメソッドを宣言します。
package com.example;
[...]
public class MyAgent {
public static void premain(String args) throws Exception {
[...]
com.example.MyAgentクラスの残りのコードは、例2-5に示したcom.example.MyAppクラスとまったく同じです。
com.example.MyAgentクラスをコンパイルします。Premain-Classエントリを使用して、マニフェスト・ファイルMANIFEST.MFを作成します。 エージェントはJavaアーカイブ(JAR)ファイルとして配備されます。JARファイルに含まれるマニフェストの属性は、エージェントを起動するためにロードされるエージェント・クラスを指定します。MANIFEST.MFというファイルを作成し、次の行を挿入します。
Premain-Class: com.example.MyAgent
MyAgent.jarを作成します。JARファイルには必ず次のファイルを入れます。
META-INF/MANIFEST.MF
com/example/MyAgent.class
com.example.MyAgentを使用すれば、モニタリングおよび管理用のアプリケーションを計測できます。次の例では、アプリケーションとしてNotepadを使用します。
% java -javaagent:MyAgent.jar -Djavax.net.ssl.keyStore=keystore \
-Djavax.net.ssl.keyStorePassword=password -jar Notepad.jar
Notepadを起動するとき、-javaagentオプションを使用して、com.example.MyAgentエージェントを指定します。また、com.example.MyAgentアプリケーションが例2-5のcom.example.MyAppアプリケーションと同じコードを複製する場合、RMIコネクタ・サーバーはSSLで保護されているため、keystoreとpasswordの情報を指定します。