问题引入
JMX(即Java Management Extensions),如果你在网上搜索如何配置JMX,你就会看到这样的一堆配置
-Djava.rmi.server.hostname=
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.rmi.port=
-Dcom.sun.management.jmxremote.port=
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
然后你就会发现在docker下,怎么弄都不对。
JMX分析
JMX其实需要注册三个端口,其作用为:
端口1: 接收注册请求,JMX客户端(如
jvisualvm
)在连接时,需要填写的端口号端口2: 用于远程连接,可以与端口1使用同一个端口号
端口3: 用于本地连接,随机(这个端口在实际业务场景中,不需要去指定,我暂时没研究如何指定这个端口)
排坑
坑点1 JMX端口仅暴露1个
由于JMX是在远程监控的情况下是需要两个端口的,所以在Docker环境下很可能就会出现因为端口没映射全而导致的失败
解决办法也很简单,就是把端口1和端口2设置为同一个端口即可,这样也可以减少端口映射过多而产生的端口冲突
-Dcom.sun.management.jmxremote.rmi.port=8888
-Dcom.sun.management.jmxremote.port=8888
注:
8888
这个端口是我随便写的,在合法范围内都可以
坑点2 java.rmi.server.hostname配置导致JMX连接失败
坑点1其实在网络上已经有大把大把现成的文章了,而对于坑点2,则在于java.rmi.server.hostname
这个配置。我个人认为这个是因为JMX诞生比较早,所以JMX并没有适配容器化,这就导致了第二个坑点。
java.rmi.server.hostname
配置失败的体现在于,你的JMX客户端,会在连接中卡顿很久,这其实就是JMX尝试连接,但连接不上导致的。
JMX客户端根据你填写的IP和PORT去查找JMX服务,这时候你的服务端会返回这个java.rmi.server.hostname
和com.sun.management.jmxremote.rmi.port
,JMX客户端再根据这两个值去连接。
那么在docker环境下,你配置的java.rmi.server.hostname
很可能就配置错了,你需要保证这个java.rmi.server.hostname
是客户端直接可连的,并且这个com.sun.management.jmxremote.rmi.port
也是可以直接访问的。
我使用的环境是我用我的笔记本去监控运行在服务器K8S集群中的服务,这种情况下,我需要把java.rmi.server.hostname
配置为这个集群所使用的映射服务IP,
如果你的映射服务IP过多,这就会很麻烦,因为每次修改
java.rmi.server.hostname
需要重启,而重启等同于重新部署,这就导致有可能不匹配,这个问题可能需要想办法绑定,或者自己手动用kubectl
做映射
并且你还需要保证com.sun.management.jmxremote.rmi.port
是映射服务所使用的端口。
创建端口映射的时候,就保证你的容器端口和映射端口得是一致的,不然JMX服务返回给JMX客户端的端口,没办法通过端口映射连接了
参考
how-to-connect-with-jmx-from-host-to-docker-container-in-docker-machine