我有一个在 Kubernetes 中运行的 Java 应用程序。有时我需要调试它,所以我过去常常通过 连接到 jmx 端口kubectl port-forward pods/my-java-app 9010:9010 -n my-java-app
。
我们的监控团队要求能够远程查询 jmx 端口,因此我相应地重新配置了我的 docker-entrypoint.sh:
#!/bin/bash
set -ex
echo "Start docker-entrypoint.sh"
JMXARGS="-Dsun.management.jmxremote.level=FINEST \
-Dsun.management.jmxremote.handlers=java.util.logging.ConsoleHandler \
-Djava.util.logging.ConsoleHandler.level=FINEST \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.port=$JMX_PORT \
-Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT \
-Djava.net.preferIPv4Stack=true"
/usr/local/openjdk-8/bin/java ${JAVA_OPTS} ${JMXARGS} \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:+UseContainerSupport \
-XX:+UseG1GC -DLOG_PATH=${LOG_PATH} \
-DAPP_LOG_FILENAME=${APP_LOG_FILENAME} \
-jar /opt/${JARFILENAME} \
-conf /opt/${CONFFILENAME} \
-server -XX:CompileThreshold=5 \
-Djava.net.preferIPv4Stack=true \
-XX:-OmitStackTraceInFastThrow \
-Dserver.port="${LISTENING_PORT}" \
run myjavaapp
从那时起,我无法使用 kubectl port-foward 从我的计算机查询 jmx。监控团队的监控服务器与 Kubernetes 集群位于同一本地网络上,因此它可以为他们工作,远程查询 JMX。
我怎样才能两全其美?含义:
- 拥有远程端口以满足监控团队的需求
- 通过命令获取端口
kubectl port-forward pods/my-java-app 9010:9010 -n my-java-app
以便进行调试
编辑:
更进一步来说,这里有一些从容器中运行的测试:
root@my-java-app-864d5d487f-99qwl:/usr/local/openjdk-8# java -cp /jmxquery.jar org.nagios.JMXQuery -U service:jmx:rmi://172.29.4.202/jndi/rmi://172.29.4.202:9010/jmxrmi -O java.lang:type=Memory -A HeapMemoryUsage -K used -I HeapMemoryUsage -J used -w 800000000 -c 900000000
JMX OK 53811560
root@my-java-app-864d5d487f-99qwl:/usr/local/openjdk-8# java -cp /jmxquery.jar org.nagios.JMXQuery -U service:jmx:rmi://127.0.0.1/jndi/rmi://127.0.0.1:9010/jmxrmi -O java.lang:type=Memory -A HeapMemoryUsage -K used -I HeapMemoryUsage -J used -w 800000000 -c 900000000
JMX OK 55908712
从我的电脑上,在端口转发之后:
PS C:\dev> kubectl port-forward pods/my-java-app-864d5d487f-99qwl 9010:9010 -n my-java-app
Forwarding from 127.0.0.1:9010 -> 9010
Forwarding from [::1]:9010 -> 9010
Handling connection for 9010
Handling connection for 9010
...
(in another term:)
PS C:\dev> java -cp jmxquery.jar org.nagios.JMXQuery -U service:jmx:rmi://127.0.0.1/jndi/rmi://127.0.0.1:9010/jmxrmi -O java.lang:type=Memory -A HeapMemoryUsage -K used -I HeapMemoryUsage -J used -w 800000000 -c 900000000
JMX CRITICAL Connection timed out: connect
此致,
答案1
您的第二个连接超时了;它并没有被拒绝。因此,我得出结论,JMX RMI 接口(顺便说一句,真讨厌)是单线程的并且阻塞;可能 JMX 客户端在轮询之间保持连接。
JMX RMI 也确实非常慢,这取决于您是否想要抓取大量数据以及您的客户端正在使用哪种 API(jconsole 的缓慢而稳定的方法)或快速而高效的机制,当您遇到缺少序列化接口的 mbean 时,它将因序列化异常而爆发。
一种可能更好的方法(尽管这可能需要更改您的监控)是使用基于 JMX 代理的机制。这是大多数监控提供商(例如 Data Dog、Prometheus)用来收集数据的机制。也可能是一个更好的安全边界。
我只使用过 Prometheus 的 jmx_exporter,但它可能不适合 Nagios。我完全相信会有其他 JMX 代理不会有 JMX RMI 的限制……特别是我认为鬼椒属因通过 HTTP 公开 JMX 而广受欢迎
另一种可能性:如果使用 jconsole(它可以使用 Attach API 将自身注入为代理(?),这就是为什么您不需要设置 JMX RMI 来使用 jconsole)您可能会发现这可以解决 JMX RMI 端口的争用问题。