【问题标题】:How to connect with JMX from host to Docker container in Docker machine?如何在 Docker 机器中将 JMX 从主机连接到 Docker 容器?
【发布时间】:2016-05-29 17:35:59
【问题描述】:

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

我的主机的网络是 192.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 

【问题讨论】:

  • 它是由 docker-java 库启动的......它不是那么重要,但是当我执行“docker-machine ssh”并在其中“docker ps -a”时,我可以看到我的容器有这个端口绑定/暴露:ad6be9184855 company/tomcat:8.0.30 0.0.0.0:1099->1099/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8009->8009/tcp, 0.0。 0.0:8080->8080/tcp

标签: tomcat networking docker jmx docker-machine


【解决方案1】:

我认为问题可能是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 连接到注册表,则注册表会向客户端提供 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 端口的相同问题......

似乎没有针对此问题的开箱即用解决方案。但是,正如here 所建议的那样,可以在容器启动时同时提供 JMX 端口和外部主机名(或 IP)作为环境变量。然后可以在 JMX 配置中使用这些:

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"

不是很好,但它应该可以工作......

【讨论】:

  • 是的,这种方法有效,我和你一样想通了,我只是忘了写一个答案:) 谢谢。
  • 顺便说一句:这也适用于我(Java 7、Tomcat 7),但我还必须在 CATALINA_OPTS 中添加 -Dcom.sun.management.jmxremote= 才能使其正常工作。仅仅拥有单独的属性是不够的。
  • @nwinkler 当然你是对的。我更新了答案以包含缺少的系统属性com.sun.management.jmxremote
  • 请注意,您可能仍会遇到有关端口映射的问题。内部端口必须等于 docker 容器的外部端口(必须等于$JMXPORT-var)。否则 JMX 注册表返回的存根将无法连接。此外,您的 Dockerfile 需要公开所有用于 JMX 的潜在端口,这实际上是不可行的。 TLDR:更好地使用其他东西进行监控
  • @fab 你不必在Dockerfile中使用EXPOSE,也可以在运行时定义:docker run --expose。
【解决方案2】:

如果有人对此有问题。我已经使用以下参数在 docker 容器中启动了 java 进程:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9876 
-Dcom.sun.management.jmxremote.rmi.port=9876 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Djava.rmi.server.hostname=<name of the docker container>

重要的部分是设置 docker 容器的名称。暴露容器中的端口 9876。我还设置了一个 ssh 连接并将 9876 转发到 localhost。

以下内容进入您的 SSH 配置:

LocalForward 127.0.0.1:9876 127.0.0.1:9876

我还在本地机器上设置了 /etc/hosts

127.0.0.1 <name of the docker container>

现在将您的控制台连接到“docker 容器的名称”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 2018-01-09
    • 1970-01-01
    • 2017-04-08
    • 2016-01-05
    • 2018-11-28
    相关资源
    最近更新 更多