使用 Cryostat 监控 Quarkus JVM 模式

Cryostat 是一款利用您运行在 HotSpot JVM 上的 Java 应用程序中已有的 JDK Flight Recorder (JFR) 框架的分析和监控工具。Cryostat 提供了一个集群内的收集中心,可以轻松安全地从集群外部访问您的 JDK Flight Recorder 数据。Cryostat 是一个云原生应用程序,主要针对在 OpenShift 上部署,因此本指南将假定您也在 OpenShift 上部署 Quarkus 应用程序以简化操作。

在本文中,我们将探讨如何配置 Quarkus 应用程序以允许 Cryostat 连接到它们,从而使 Cryostat 能够与 Quarkus 通信,并提供其 JDK Flight Recorder 收集、存储和分析工具。

Automated Analysis Report in the Cryostat web-client UI
图 1. Cryostat 自动分析报告
Grafana dashboard displaying metrics from Cryostat
图 2. Cryostat Grafana 仪表板

Cryostat 与 Quarkus 的注意事项

Quarkus 以其在标准 JVM 模式(构建会生成 .JAR 文件,在运行时由 JVM 加载和运行)或原生模式(构建会生成本地二进制文件,可直接执行)下进行构建的能力而闻名。Cryostat 依赖于 JDK Flight Recorder (JFR),JFR 在 Quarkus 原生模式下仅受部分支持;并且依赖于 JDK Management Extensions (JMX),在撰写本文时,JMX 在原生模式下不受支持。这意味着,不幸的是,只有 JVM 模式的 Quarkus 应用程序可以配置为与 Cryostat 一起使用。

Cryostat 入门

在 OpenShift 上入门 Cryostat 非常快速简单——只需从 OperatorHub 安装即可

Cryostat Operator in the OpenShift OperatorHub
图 3. Cryostat 安装

然后创建一个 Cryostat CR 资源实例,让 Operator 知道您想要部署一个 Cryostat 实例。此时您也可以选择一些配置选项,但我们暂时假设使用默认设置。

A created Cryostat CR in the OpenShift Console
图 4. Cryostat 创建

Cryostat 通信

Cryostat 使用 JMX 与运行在 HotSpot JVM 上的应用程序(包括但不限于 Java 和 Scala 应用程序)进行通信。JMX 是一项标准的 Java 技术,它允许工具连接到应用程序并通过各种底层传输协议执行操作或检索数据。如果您在 JVM 模式下构建和部署 Quarkus 应用程序,那么 JMX 支持已内置且开箱即用。有两种方法可以启用应用程序上的 JMX。

方法 1:在运行时启用

可以通过设置 JVM 系统属性来启用 JMX

-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 中嵌套设置其 DeploymentDeploymentConfig 中的此环境变量。此方法启用 JMX 不需要重新构建 Quarkus 应用程序,只需重新部署即可。

方法 2:在构建时启用

可以通过编辑 src/main/docker/ 下的 Dockerfile.jvm 文件,将与之前相同的 JVM 系统属性添加到容器化的 Quarkus 应用程序中。下面是一个来自基本 Quarkus 项目的示例 Dockerfile.jvm - 请注意已添加的 ENV JAVA_OPTS_APPEND 行,用于附加 JVM 属性并公开端口号

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 需要知道如何以及在哪里找到该应用程序。有两种方法可以实现这一点:自动发现和自定义目标。自动发现是首选方法,并且默认启用。自定义目标可用于弥补未满足自动发现条件的已部署应用程序目标,但已知这些目标可通过网络访问。

自动发现

Cryostat 可以自动发现目标应用程序,并使用其发现的远程 JMX 服务 URL 进行连接。自动发现取决于部署平台——在撰写本文时,Cryostat 在 OpenShift/Kubernetes 上部署时将使用 OpenShift/Kubernetes API 来发现 Endpoints 对象。如果没有可用的 OpenShift/Kubernetes API 服务器,Cryostat 将回退到使用 Java Discovery Protocol (JDP)。无论哪种情况,自动发现的目标都会与自定义目标合并。如果使用 OpenShift/Kubernetes Endpoints 发现,则目标应用程序应具有关联的 Service 对象,该对象公开一个用于集群内部 JMX 流量的端口。此端口必须使用端口号 9091,或名为 jfr-jmx,Cryostat 才能将其识别为目标应用程序。

自定义目标

这是 Cryostat 客户端(最终用户或其他自动化工具)告知 Cryostat 如何以及在哪里查找单个目标应用程序实例的一种方式。自定义目标定义的核心就是一个网络可访问的远程连接 JMX URL 和一个人类可读的别名。您可以通过在 Cryostat Web 客户端中点击目标选择下拉菜单上的 +(加号)图标,或使用您喜欢的 HTTP 客户端来创建这些。

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

添加自定义目标定义后,connectUrl 可以在 Cryostat HTTP API 中需要 targetId URL 参数的任何地方使用。

有关 Cryostat 的更多信息,请参阅以下链接: