多个应用节点如何在Kubernetes中暴露JMX?

51
  1. kubernetes中,我可以使用service来公开服务。这很好。
  2. 假设我有1个Web实例和10个Java服务器实例。
  3. 我有一个Windows网关,我习惯通过其上安装的jconsole访问那10个Java服务器实例。
  4. 显然,我不会通过kubernetes service公开所有应用程序的jmx端口。

我有哪些选择? 我应该如何使这个外部的kubernetes集群Windows网关能够访问那10个服务器的jmx端口? 有什么最佳实践吗?

4个回答

143

另一种选择是使用 kubectl port-forward 将 K8 Pod 的 JMX 端口转发到您的本地 PC。

我是这样做的:

1). 将以下 JVM 选项添加到您的应用程序中:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.rmi.port=1099
-Djava.rmi.server.hostname=127.0.0.1

这里的关键在于:

  • 应该使用相同的端口作为 'jmxremote.port' 和 'jmxremote.rmi.port'。这是为了仅转发一个端口。

  • 应该将 127.0.0.1 作为 RMI 服务器主机名传递。这是为了使 JMX 连接通过端口转发工作。

2). 通过 kubectl 将 JMX 端口 (1099) 转发到本地 PC:

kubectl port-forward <your-app-pod> 1099

3). 打开 jconsole 连接到本地端口 1099:

jconsole 127.0.0.1:1099

这种方式使得可以通过JMX调试任何Java Pod,而不必公开暴露JMX通过K8服务(从安全角度来看更好)。

另一个也可能有用的选项是在容器内部将Jolokia代理 (https://jolokia.org/) 添加到Java进程中,以便将JMX代理到HTTP端口并公开或端口转发此HTTP端口以查询JMX over HTTP。


3
这是我遇到过最简单明了的解释,非常有效。谢谢! - Matt Friedman
1
谢谢!非常有帮助 - f-z-N
8
为我们解决问题的是设置-Djava.rmi.server.hostname=127.0.0.1 - jitter
4
我欠你一杯咖啡! - Dmitry Minkovsky
1
我该如何从远程主机连接到这个JMX服务器? - bhavanak
显示剩余5条评论

4

除了 https://dev59.com/x1sW5IYBdhLWcg3wQVb2#39927197 中提到的内容,我想要同时监控同一 Pod 的所有实例,但是由于我们将端口硬编码为 1099,所以只能对一个使用该端口的 pod 进行 portforward,这就很难了。

我使用 Shell 脚本在运行 docker 时动态分配 pod:

Dockerfile CMD /run.sh

run.sh

JMX_PORT=$(((RANDOM % 20)+1099))

echo "Running JMX on Port $JMX_PORT"

java ``eval echo $JAVA_OPTS`` ...

deployment.yml env: - name: JAVA_OPTS value: "-Xms256m -Xmx6144m -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=$JMX_PORT -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT -Djava.rmi.server.hostname=127.0.0.1"

eval 将 JMX_PORT 的值作为 bash 值进行评估,每个 pod 启动时都可能会获得不同的 pod。


3
我们是以下面的方式进行操作的:
  1. 为每个Pod添加一个唯一标签。例如:podid=asdw23443
  2. 使用选择器podid=asdw23443创建新服务。确保在服务中,你通过nodeport或负载均衡器公开Pod上的jmx端口。

如果你在服务中选择了nodeport,因为你正在执行NAT操作,你可能需要为每个需要通过jconsole连接的JVM提供以下JVM参数:

-Djava.rmi.server.hostname=<your-ip-address>

我不确定我理解了,您是说每个Pod实例都有一个Pod ID吗?因此,如果您将其从10扩展到20,则可以访问每个Pod实例而无需负载均衡器?我想要访问特定的Pod实例。 - Jas
我不确定我理解了,您是说每个Pod实例都有一个Pod ID吗?所以如果您将其从10扩展到1000,那么您就会有1000个服务? - Jas
是的,在这种方法中,您必须为每个Pod创建一个服务。如果您有1000个Pod,则应该有1000个服务。 - Dimuthu
我目前遇到的问题是:当我不知道 Pod 将会被调度到哪个 Worker 上时,如何将 JVM arg 设置为正在运行进程的 IP 地址? - joelittlejohn

1

我认为一种方法是给你的pod添加一个标签,使用一个唯一的字符串或ID,例如pod_name,并使用expose命令创建一个新的服务,该服务的选择器为这个唯一的ID\字符串。

kubectl label pods <podname> podname=<podname>
kubectl expose pod <podname> --port=9010 --name=<podname>_jmx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接