如何在Docker机器上将JMX从主机连接到Docker容器?

当我在主机上直接运行Docker容器时,可以无任何问题地连接到它。

我的主机有networking192.168.1.0/24,主机的IP地址是192.168.1.20。 我的Docker容器有IP地址172.17.0.2。 当我从jconsole连接到172.17.0.2:1099时,它工作。

当我把这个服务放入Docker机器时,不可能连接到它。

我的Docker机器IP为192.168.99.100,容器中有IP地址172.17.0.2,但是当我使用jconsole连接到192.168.99.100:1099时,它不起作用。

重复一遍:

192.168.1.20 — 172.17.0.2:1099起作用

192.168.1.20 —(192.168.99.100 — 172.17.0.2:1099),并从我的主机连接到192.168.99.100:1099不起作用。

值得一提的是,我可以通过Docker机器的外部IP地址访问在Docker机器中容器化的服务,例如:

192.168.99.100 —(192.168.99.100:8080 — 172.17.0.2:8080)

但是,当我使用JMX它只是不工作。

这是Tomcat服务。 我在启动Tomcat实例的脚本中有这个:

CATALINA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n \ -Dcom.sun.management.jmxremote.port=1099 \ -Dcom.sun.management.jmxremote.rmi.port=1099 \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -Djava.rmi.server.hostname=IP address of Docker container 

我认为这个问题可能是java.rmi.server.hostname属性的值。 这需要是JMX客户端用来连接到JVM的主机名或IP地址。 在第一种情况下,使用172.17.0.2:1099直接连接到容器,此设置需要设置为172.17.0.2 。 在后一种情况下,通过192.168.99.100:1099上的docker机器访问容器时,需要将设置设置为192.168.99.100

在我研究一个非常类似的问题(同时被删除)期间,我偶然发现了一个博客条目(同时也被删除了)。 虽然它相当古老,但它给了我一个JMX连接如何工作的想法:

  1. JMX注册中心监听容器的端口<com.sun.management.jmxremote.port>
  2. 如果使用JConsole连接到registry,则registry将JMX服务URL提供给客户端。
  3. 这个URL被客户端用来获得JMX对象

服务URL类似于以下service:jmx:rmi:///jndi/rmi://<java.rmi.server.hostname>:<com.sun.management.jmxremote.rmi.port>/jmxrmi 。 这是你的情况service:jmx:rmi:///jndi/rmi://172.17.0.2:1099/jmxrmi 。 由于该地址只能在docker机器内进行访问,因此无法从远程进行连接。 在我的问题中,我涉及到与RMI端口相同的问题。

这个问题似乎没有一个开箱即用的解决scheme。 但是,可以在启动容器时提供JMX端口和外部主机名(或IP)作为环境variables,如此处所示 。 这些可以在JMXconfiguration中使用:

 docker run -p 1099:1099 \ -e "JMX_HOST=192.168.99.100" \ -e "JMX_PORT=1099" \ company/tomcat:8.0.30 

 CATALINA_OPTS="... \ -Dcom.sun.management.jmxremote=true \ -Dcom.sun.management.jmxremote.port=$JMX_PORT \ -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -Djava.rmi.server.hostname=$JMX_HOST" 

不是很好,但它应该工作…