KubernetesでのJava Flight Recorderの手動記録
これは、追加のツールが利用できないコンテナ化された環境でKeycloakのJava Flight Recorder記録を作成する方法について説明しています。
概要
Java Flight Recorder(JFR)は、Java仮想マシンのイベント(フレイムグラフに組み立てることができるスレッドダンプを含む)を記録し、パフォーマンス分析に使用できます。本格的なセットアップでは、Cryostatを使用したパフォーマンスメトリクスのキャプチャが自動化された方法を提供し、カスタムKeycloakイメージは不要です。そのようなセットアップが利用できない場合は、以下の手順に従ってJFRをキャプチャしてください。
これは、OpenShift内ではasync profilingが利用できないため(私の知る限り)、async profilingを使用していません。したがって、記録にはセーフポイントバイアス問題が発生します。コンテナ内のJavaプロファイリングを参照してください。 |
詳細については、OracleのJDK Mission Control、およびBaeldungのFlight Recorderを使用したJavaアプリケーションの監視を参照してください。
Keycloakイメージの準備
次の手順では、Java Flight Recordingを開始するためにコンテナ内にjcmd
が存在し、コンテナから記録を取得するためにkubectl cp
を使用できるようにtar
が存在する必要があります。
古いバージョンのKeycloakにはこれらのツールが含まれていますが、新しいバージョンのKeycloakイメージには、イメージをより小さく、より安全にするために含まれていません。したがって、最初のステップは、これらのツールを使用してカスタムKeycloakイメージを作成することです。これを行うには、Keycloakイメージをスクラッチから作成するか、必要なパッケージでKeycloakイメージを更新する2つの方法があります。
Keycloakをスクラッチからビルドする
KeycloakのメインリポジトリからKeycloakのカスタムディストリビューションをビルドしている場合は、quarkus/container/Dockerfile
ファイルを変更し、次の行を交換します。
RUN bash /tmp/ubi-null.sh java-17-openjdk-headless glibc-langpack-en
を次のように変更します。
RUN bash /tmp/ubi-null.sh java-17-openjdk-devel tar glibc-langpack-en
次に、KubernetesでのデプロイメントにカスタムKeycloakイメージを使用するの説明に従って、イメージをビルドします。
イメージにRPMパッケージを追加する
コンテナに関するKeycloakドキュメントには、パッケージを追加する方法に関するセクションが含まれています。2つのパッケージjava-17-openjdk-devel tar
を追加するには、次のようなDockerfileを使用します。
FROM registry.access.redhat.com/ubi9 AS ubi-micro-build
RUN mkdir -p /mnt/rootfs
RUN dnf install --installroot /mnt/rootfs java-17-openjdk-devel tar --releasever 9 --setopt install_weak_deps=false --nodocs -y; dnf --installroot /mnt/rootfs clean all
FROM quay.io/keycloak/keycloak
COPY --from=ubi-micro-build /mnt/rootfs /
次に、KubernetesでのデプロイメントにカスタムKeycloakイメージを使用するの説明に従って、イメージを使用します。
JVMオプションの更新
Keycloak 23以降では、Keycloakがデフォルトで512を使用するため、-XX:FlightRecorderOptions=stackdepth JVMオプションをオーバーライドする必要はなくなりました。 |
Keycloakは、その呼び出しに非常に深いスタックトレースを使用します。フレイムグラフを使用できるようにするには、次のJVMオプションを追加してスタックフレームの数を増やします。
-XX:FlightRecorderOptions=stackdepth=512
Keycloak Operatorを使用している場合、これはKeycloakのCustomResourceを介してKeycloakイメージに渡すことができます。
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
spec:
unsupported:
podTemplate:
spec:
containers:
- env:
- name: JAVA_OPTS_APPEND
value: >
-XX:FlightRecorderOptions=stackdepth=512
Operatorによって管理されているStatefulSetまたはDeploymentを実行している場合は、Operatorを停止し、StatefulSetまたはDeploymentを手動で更新して、Javaオプションを追加または拡張することを検討してください。
記録の開始
記録を開始するには、コンテナ内でコマンドを発行します。
kubectl exec -n namespace pod -- jcmd 1 JFR.start duration=60s filename=/tmp/recording.jfr settings=/usr/lib/jvm/java/lib/jfr/profile.jfc
値1
は、すべてのQuarkusベースのKeycloakコンテナのデフォルトであるJavaプロセスのプロセスIDです。Wildflyベースのディストリビューションの場合、これは異なるプロセスIDである可能性があります。探しているプロセスIDを見つけるには、パラメータなしでjcmd
を使用して、すべてのJavaプロセスIDを一覧表示します。
Podで複数のコンテナが実行されている場合は、CLIオプション-c container
を追加します。
profile.jfc
には、キャプチャする内容に関する指示が含まれています。profile.jfc
は、JVMに同梱されている標準プロファイルの1つであり、「プロファイリング」を意味します。多くの情報を収集し、数分間情報を収集することを目的としています。1分間の記録でも約5メガバイトのデータが収集されるため、時間間隔を短くしてください。必要な情報を収集するために必要に応じて調整してください。
記録の取得
記録を取得するには、次のコマンドを発行します。
kubectl cp -n namespace keycloak pod:/tmp/recording.jfr recording.jfr --retries 999
Podで複数のコンテナが実行されている場合は、CLIオプション-c container
を追加します。
CLIオプション--retries 999
は、そうしないと失敗する可能性がある大きなファイルのダウンロードを再開するのに役立ちます。
記録の分析
詳細については、Java Flight Recorder記録の分析を参照してください。