使用映射端口访问 docker 容器内的 JMX

Posted

技术标签:

【中文标题】使用映射端口访问 docker 容器内的 JMX【英文标题】:Access JMX inside docker container with mapped ports 【发布时间】:2016-05-20 03:12:57 【问题描述】:

我正在尝试使用 JMX 访问在 docker 容器内运行的应用程序。

这类似于this question,并且当 docker 映像内的端口映射到映像外的相同端口时,该解决方案有效。但是,有时我想将端口映射到不同的端口。

我正在托管应用程序中设置这些属性。

-Dcom.sun.management.jmxremote.port=9832 
-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.rmi.port=9832 
-Djava.rmi.server.hostname=192.168.99.100 
-Djava.rmi.server.logCalls=true

当 docker 容器将端口 9832 映射到 9832 时,这可以正常工作。我可以通过 JConsole 或我们自己的应用程序进行连接。如果改为将端口映射到另一个端口,则我无法从 JConsole 或我们的应用程序访问该应用程序。

我怀疑其中一两个端口号需要是外部端口(就像java.rmi.server.hostname 是外部地址,而不是内部地址)。但是,它会因所有四种端口号组合而失败。

其中两种组合不会从服务器产生日志输出。一个(我忘记了)产生这个输出:

Feb 09, 2016 10:35:54 PM org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl start
INFO: AMQ221001: Apache ActiveMQ Artemis Message Broker version 1.1.0 [nodeID=7a6e038e-cf7d-11e5-b566-31dc437b2d1a] 
HTTP Server started at http://0.0.0.0:8161
Feb 09, 2016 10:36:06 PM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(1)-192.168.99.1: [192.168.99.1: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Feb 09, 2016 10:36:08 PM sun.rmi.transport.Transport serviceCall
FINE: RMI TCP Connection(1)-192.168.99.1: [192.168.99.1] exception: 
java.rmi.NoSuchObjectException: no such object in table
    at sun.rmi.transport.Transport.serviceCall(Transport.java:177)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Feb 09, 2016 10:40:24 PM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(2)-192.168.99.1: [192.168.99.1: sun.rmi.transport.DGCImpl[0:0:0, 2]: void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)]

另一个产生这个输出。

HTTP Server started at http://0.0.0.0:8161
Feb 09, 2016 10:14:13 PM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(1)-192.168.99.1: [192.168.99.1: sun.management.jmxremote.SingleEntryRegistry[0:0:0, 0]: java.rmi.Remote lookup(java.lang.String)]
Feb 09, 2016 10:14:17 PM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(1)-192.168.99.1: [192.168.99.1: sun.management.jmxremote.SingleEntryRegistry[0:0:0, 0]: java.rmi.Remote lookup(java.lang.String)]
Feb 09, 2016 10:14:17 PM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(1)-192.168.99.1: [192.168.99.1: sun.management.jmxremote.SingleEntryRegistry[0:0:0, 0]: java.rmi.Remote lookup(java.lang.String)]

鉴于这些故障,我怀疑其中一个或两个端口属性的使用方式有时需要作为内部端口,有时需要作为外部端口。这意味着当端口映射到不同的位置时,JMX 访问是不可能的。

我可以通过telnet 192.168.99.100 <mapped port> 访问映射端口,所以我知道映射正在工作。

【问题讨论】:

您是否在无日志期间检查了防火墙没有阻止 docker 容器暴露的端口? @TyagiAkhilesh 我可以用telnet连接到端口,所以端口是可以访问的。 从内存中,JMX 告诉客户端在初始连接中要连接的第二个端口是什么。所以客户端希望能够连接到应用程序配置的端口。只需使用映射的端口。如果您确实想使用不同的 NAT 端口,请使用 socks 代理。 这个问题我们需要更多的赞。 您是否尝试过使用 2 个不同的端口和不同的映射? 【参考方案1】:

我遇到了同样的问题,连续近三天,我刚刚放弃,我做了一个不太好的解决方案,但它确实有效。所以,我的解决方案是:我没有为 JMX 连接设置一个固定端口并使用不同的外部端口映射它,而是在我的 docker-compose.yml 上创建了一个名为 JMX_MNG_PORT 的环境变量。

...
ports:
  - '9011:9011'
...
environment:
  - JMX_MNG_PORT=9011
...

然后我在 docker-entrypoint.sh 上配置了 JAVA_OPTS 变量来接收 JMX_MNG_PORT。

...
JAVA_OPTS=$JAVA_OPTS -Dcom.sun.management.jmxremote.port=$JMX_MNG_PORT
JAVA_OPTS=$JAVA_OPTS -Dcom.sun.management.jmxremote.rmi.port=$JMX_MNG_PORT
...

现在,在每个正在配置的容器 (docker-compose.yml) 上,我只需要配置 JMX_MNG_PORT 并使用相同的编号公开端口。

记住,我不知道为什么,但是如果您使用另一个端口,那么在 jmxremote.port 和 jmxremote.rmi.port 上配置的那个端口将不起作用。

我希望它能为像我这样的其他人解决问题。

【讨论】:

以上是关于使用映射端口访问 docker 容器内的 JMX的主要内容,如果未能解决你的问题,请参考以下文章

7.Docker技术入门与实战 --- 端口映射与容器互联

07-docker端口映射与容器关联

Docker-端口映射

Docker-端口映射

跟我一起学docker--网络

端口映射与容器互联