在 Kubernetes 中手动进行 Java 飞行记录器记录

这描述了如何在没有额外工具的情况下,为容器化环境中的 Keycloak 创建 Java 飞行记录器记录。

概述

Java 飞行记录器 (JFR) 记录 Java 虚拟机的事件,包括线程转储,然后可以将其组装成火焰图,并可用于分析性能。在一个功能完善的设置中,使用 Cryostat 捕获性能指标 提供了一种自动化方法,并且不需要自定义 Keycloak 镜像。如果此类设置不可用,请按照这些说明捕获 JFR。

这没有使用异步分析,因为在 OpenShift 内部 AFAIK 中不可用。因此,记录将具有安全点偏差问题。请参阅 在容器中分析 Java

准备 Keycloak 镜像

以下程序需要容器中存在 jcmd 才能启动 Java 飞行记录,以及 tar 才能使用 kubectl cp 从容器中检索记录。

虽然较旧版本的 Keycloak 包含这些工具,但较新的 Keycloak 镜像版本不包含它们,以使镜像更小更安全。因此,第一步是创建包含这些工具的自定义 Keycloak 镜像。有两种方法可以做到这一点:从头开始创建 Keycloak 镜像,或者使用必要的软件包更新 Keycloak 镜像。

从头开始构建 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 关于容器的文档 包含关于如何添加软件包的部分。要添加两个软件包 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 开始,不再需要覆盖 -XX:FlightRecorderOptions=stackdepth JVM 选项,因为 Keycloak 默认使用 512。

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 是 Java 进程的进程 ID,它是所有基于 Quarkus 的 Keycloak 容器的默认值。对于基于 Wildfly 的发行版,这可能是不同的进程 ID。使用不带参数的 jcmd 列出所有 Java 进程 ID 以找到您要查找的进程。

如果 Pod 中运行着多个容器,请添加 CLI 选项 -c container

profile.jfc 包含关于要捕获内容的说明。profile.jfc 是 JVM 附带的标准配置文件之一,代表 “性能分析”:它收集大量信息,并应收集几分钟的信息。一分钟的记录将已经收集约 5 兆字节的数据,因此请寻求较短的时间跨度。根据需要调整它以收集您需要的信息。

检索记录

要检索记录,请发出以下命令

kubectl cp -n namespace keycloak pod:/tmp/recording.jfr recording.jfr --retries 999

如果 Pod 中运行着多个容器,请添加 CLI 选项 -c container

CLI 选项 --retries 999 有助于恢复大型文件的下载 否则可能会失败

分析记录

有关详细信息,请参阅 分析 Java 飞行记录器记录