The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

CryostatでQuarkusのJVMモードを監視

Cryostatは、HotSpot JVM 上で動作する Java アプリケーションに既に存在する JDK Flight Recorder(JFR) フレームワークを活用したプロファイリングおよび監視ツールです。Cryostatは、クラスタ内の収集ハブを提供し、クラスタ外からJDK Flight Recorderデータに簡単かつ安全にアクセスすることができます。Cryostatは、主にOpenShiftへのデプロイをターゲットとするクラウドネイティブアプリケーションです。したがって、このガイドでは、わかりやすくするために、QuarkusアプリケーションもOpenShiftにデプロイしているものと仮定します。

この記事では、CryostatがQuarkusと通信し、JDK Flight Recorderの収集、保存、および分析ツールを提供できるように、Quarkusアプリケーションを設定する方法について説明します。

Automated Analysis Report in the Cryostat web-client UI
Figure 1. クライオスタット自動分析レポート
Grafana dashboard displaying metrics from Cryostat
Figure 2. Cryostat Grafana Dashboard

Quarkusを使用したCryostatの注意点

Quarkusは、標準のJVMモード(ビルドにより.JARファイルを生成し、ランタイムにJVMでロードして実行)またはネイティブモード(ビルドにより、直接実行するネイティブバイナリを生成)でビルドできることは有名な話です。CryostatはJDK Flight Recorder(JFR)に依存していますが、これはQuarkusのネイティブモードでは部分的にしかサポートされておらず、JDK Management Extensions(JMX)は執筆時点ではネイティブモードではサポートされていません。つまり、残念ながら、JVMモードのQuarkusアプリケーションしかCryostatで使用するように設定することができません。

Cryostat入門

OpenShiftでCryostatを始めるには、OperatorHubからインストールするだけで、素早く簡単にできます。

Cryostat Operator in the OpenShift OperatorHub
Figure 3. Cryostatインストール

次に、Cryostat CR リソースインスタンスを作成し、Operator に Cryostat インスタンスをデプロイすることを知らせます。この段階で、いくつかの設定オプションを選択することもできますが、ここではデフォルトを前提とします。

A created Cryostat CR in the OpenShift Console
Figure 4. Cryostat作成

Cryostat通信

CryostatはJMXを使用して、HotSpot JVM上で動作するアプリケーション(JavaおよびScalaアプリケーションを含むが、これに限定されない)と対話します。JMXは、ツールがアプリケーションに接続してアクションを実行したり、さまざまな基礎となるトランスポートプロトコルを介してデータを取得したりできるようにする標準のJavaテクノロジーです。QuarkusアプリケーションをJVMモードで構築してデプロイする場合、JMXサポートはすでに組み込まれており、すぐに使用できます。アプリケーションでJMXを有効にするには、2つの方法があります。

方法1:実行時に有効化

JMXは、JVMのシステムプロパティを設定することで有効にすることができます。

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=${RJMX_PORT}
-Dcom.sun.management.jmxremote.rmi.port=${RJMX_PORT}
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.local.only=false

ここで、 ${RJMX_PORT} は、RMIを介したリモートJMXネットワーク接続のために選択したポート番号に置き換えられています。この例では、JMX認証とJMX SSLを無効にしています。実際には、セキュリティ上の理由からこれらは両方とも有効にすべきですが、これらの特定のオプションを構成することは、このガイドの範囲外です。詳細については、 このドキュメントを参照してください。

Quarkusでは、機能豊富なアプリケーション起動スクリプトを使用しており、環境変数を設定するだけで、実行時にJVMシステムプロパティを追加することができます。

JAVA_OPTS_APPEND="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=${RJMX_PORT} -Dcom.sun.management.jmxremote.rmi.port=${RJMX_PORT} -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false"

OpenShiftまたはKubernetesでQuarkusアプリケーションを実行している場合、この環境変数を、アプリケーション ContainerSpec 内の Deployment もしくは DeploymentConfigSpec にネストして設定してみてください 。この方法でJMXを有効にすると、Quarkusアプリケーションを再構築する必要はなく、再デプロイするだけです。

方法2:ビルド時に有効化

コンテナ化されたQuarkusアプリケーションに、以前と同じJVMシステムプロパティを追加するには、 src/main/docker/ の下にある Dockerfile.jvm を編集します。 Dockerfile.jvm 以下は、基本的なQuarkusプロジェクトのサンプルです。JVMプロパティを追加し、ポート番号を公開するために追加された ENV JAVA_OPTS_APPEND の行に注目してください。

FROM registry.access.redhat.com/ubi8/openjdk-11:1.11

ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'


# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/

EXPOSE 8080 ${RJMX_PORT}
USER 185
ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_OPTS_APPEND="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=${RJMX_PORT} -Dcom.sun.management.jmxremote.rmi.port=${RJMX_PORT} -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"

繰り返しますが、このファイルでは、すべての行の ${RJMX_PORT} をポート番号に置き換えてください。

この方法は、ビルド時にリモートのJMXポート番号を知っている必要があり、アプリケーションを再構築して再デプロイする必要があるため、柔軟性に欠けます。

Cryostatディスカバリー

QuarkusアプリケーションでJMXを有効にし、再デプロイしたので、Cryostatと通信する準備ができました。しかし、これが実現する前に、Cryostatはアプリケーションをどこでどのように見つけるかを知る必要があります。これを達成するために、自動検出とカスタムターゲットの2つの方法があります。自動検出は好ましい方法であり、デフォルトで有効になっています。カスタムターゲットは、自動検出の基準を満たさないが、ネットワーク上で到達可能であることが知られている展開されたアプリケーションターゲットのギャップを埋めるために使用することができます。

オートディスカバリー

Cryostat はターゲットアプリケーションを自動的に検出し、検出されたリモート JMX サービス URL を使用して接続することができます。自動検出はデプロイメントプラットフォームに依存します。執筆時点では、OpenShift/Kubernetes にデプロイされた場合、Cryostat は Endpoints オブジェクトを検出するために OpenShift/Kubernetes API を使用します。OpenShift/Kubernetes APIサーバがない場合、CryostatはJava Discovery Protocol (JDP)を使用するようにフォールバックします。いずれの場合も、自動的に検出されたターゲットは、カスタムターゲットにマージされます。OpenShift/Kubernetes Endpoints ディスカバリーが使用される場合、ターゲットアプリケーションは、クラスタ内部のJMXトラフィック用のポートを公開する関連する Service オブジェクトを持つ必要があります。このポートは、Cryostat が意図したターゲットアプリケーションとしてピックアップするために、ポート番号 9091 を使用するか、 jfr-jmx という名前を持っている必要があります。

カスタムターゲット

これは、Cryostat クライアント(エンドユーザまたは他の自動化ツール)が、単一のターゲットアプリケーションインスタンスを見つける方法と場所を Cryostat に指示するための方法です。カスタムターゲット定義は、その中核にある、ネットワークに到達可能なリモート接続JMX URLと人間が読めるエイリアスのみです。これらは、ターゲット選択のドロップダウンで + (プラス)アイコンをクリックするか、お好みのHTTPクライアントを使用して、Cryostatウェブクライアントで作成できます。

curl \
  -X POST \
  -F alias=myapp \
  -F connectUrl=service:jmx:rmi:///jndi/rmi://myapp.my-openshift-cluster.example.com:1234/jmxrmi \
  https://cryostat.my-openshift-cluster.example.com/api/v2/targets

targetId カスタムターゲット定義が追加されると、 connectUrl URLパラメータとして、Cryostat HTTP APIで期待される任意の場所で使用することができます。

Cryostatの詳細については、以下のリンクをご覧ください。