Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何从外部访问docker中的JMX接口?_Java_Docker_Jmx_Jmxtrans - Fatal编程技术网

Java 如何从外部访问docker中的JMX接口?

Java 如何从外部访问docker中的JMX接口?,java,docker,jmx,jmxtrans,Java,Docker,Jmx,Jmxtrans,我试图远程监视docker中运行的JVM。配置如下所示: 机器1:在ubuntu机器上的docker中运行JVM(在我的例子中,运行kafka);本机IP为10.0.1.201;在docker中运行的应用程序为172.17.0.85 机器2:运行JMX监控 请注意,当我从机器2运行JMX监视时,它会失败,并出现以下错误(注意:当我运行jconsole、jvisualvm、jmxtrans和节点JMX/npm:JMX时,也会出现相同的错误): 对于每个JMX监视工具,失败时的堆栈跟踪看起来类似

我试图远程监视docker中运行的JVM。配置如下所示:

  • 机器1:在ubuntu机器上的docker中运行JVM(在我的例子中,运行kafka);本机IP为10.0.1.201;在docker中运行的应用程序为172.17.0.85

  • 机器2:运行JMX监控

请注意,当我从机器2运行JMX监视时,它会失败,并出现以下错误(注意:当我运行jconsole、jvisualvm、jmxtrans和节点JMX/npm:JMX时,也会出现相同的错误):

对于每个JMX监视工具,失败时的堆栈跟踪看起来类似于以下内容:

java.rmi.ConnectException: Connection refused to host: 172.17.0.85; nested exception is
    java.net.ConnectException: Operation timed out
    at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
    (followed by a large stack trace)
现在有趣的部分是,当我在运行docker的同一台机器(上面的机器1)上运行相同的工具(jconsole、jvisualvm、jmxtrans和节点jmx/npm:jmx)时,jmx监控工作正常

我认为这表明我的JMX端口处于活动状态并且工作正常,但是当我远程(从机器2)执行JMX监控时,JMX工具似乎无法识别内部docker IP(172.17.0.85)

下面是JMX监控工作的机器1上的相关(我认为)网络配置元素(注意docker ip,172.17.42.1):

这是远程机器(机器2)上的相关网络配置元素,我从中获得JMX错误:

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
    options=3<RXCSUM,TXCSUM>
    inet6 ::1 prefixlen 128 
    inet 127.0.0.1 netmask 0xff000000 
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
    nd6 options=1<PERFORMNUD>

en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether .... 
    inet6 ....%en1 prefixlen 64 scopeid 0x5 
    inet 10.0.1.203 netmask 0xffffff00 broadcast 10.0.1.255
    nd6 options=1<PERFORMNUD>
    media: autoselect
    status: active
lo0:flags=8049 mtu 16384
选项=3
inet6::1预桥128
inet 127.0.0.1网络掩码0xff000000
inet6 fe80::1%lo0预桥64作用域ID 0x1
nd6选项=1
en1:标志=8863 mtu 1500
乙醚。。。。
inet6….%en1预桥64作用域ID 0x5
inet 10.0.1.203网络掩码0xffffff00广播10.0.1.255
nd6选项=1
媒体:自动选择
状态:活动

为了完整起见,以下解决方案有效。JVM运行时应设置特定参数,以启用远程docker JMX监控,如下所示:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=<PORT>
-Dcom.sun.management.jmxremote.rmi.port=<PORT>
-Djava.rmi.server.hostname=<IP>

where:

<IP> is the IP address of the host that where you executed 'docker run'
<PORT> is the port that must be published from docker where the JVM's JMX port is configured (docker run --publish 7203:7203, for example where PORT is 7203). Both `port` and `rmi.port` can be the same. 
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=
-Dcom.sun.management.jmxremote.rmi.port=
-Djava.rmi.server.hostname=
哪里:
是执行“docker run”的主机的IP地址
必须从配置JVM的JMX端口的docker发布的端口(docker run--publish 7203:7203,例如,其中端口为7203)。'port'和'rmi.port'可以相同。
完成后,您应该能够从本地或远程计算机执行JMX监视(jmxtrans、节点JMX、jconsole等)


感谢您使这成为一个非常快速和简单的修复

我发现尝试在RMI上设置JMX是一件痛苦的事情,特别是因为启动时必须指定
-Djava.RMI.server.hostname=
。我们在Kubernetes运行docker图像,在那里一切都是动态的

我最终使用JMXMP而不是RMI,因为这只需要打开一个TCP端口,而不需要主机名

我当前的项目使用Spring,可以通过添加以下内容对其进行配置:

<bean id="serverConnector"
    class="org.springframework.jmx.support.ConnectorServerFactoryBean"/>

(在Spring之外,您需要设置自己的JMXConncetorServer以使其正常工作)

与此依赖关系一起(因为JMXMP是可选扩展,而不是JDK的一部分):


org.glassfish.main.external
jmxremote_可选-重新打包
4.1.1
在启动JVisualVM时,您需要在类路径中添加相同的jar,以便通过JMXMP进行连接:

jvisualvm -cp "$JAVA_HOME/lib/tools.jar:<your_path>/jmxremote_optional-repackaged-4.1.1.jar"
jvisualvm-cp“$JAVA_HOME/lib/tools.jar:/jmxremote_optional-repacked-4.1.1.jar”
然后使用以下连接字符串进行连接:

service:jmx:jmxmp://<url:port>
服务:jmx:jmxmp://

(默认端口为9875)

对于开发环境,您可以将
java.rmi.server.hostname
设置为0.0.0.0

例如:


经过相当多的挖掘,我发现了这个配置

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

与上面的另一个不同之处在于,
java.rmi.server.hostname
被设置为
localhost
,而不是
0.0.0

为了增加一些额外的见解,我使用了一些Docker端口映射,之前的答案都没有直接适用于我。经过调查,我在这里找到了答案:提供所需的见解

我相信会发生这样的事情:

我按照其他答案中的建议设置了JMX:

-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.port=1098
-Dcom.sun.management.jmxremote.rmi.port=1098
-Djava.rmi.server.hostname=localhost
-Dcom.sun.management.jmxremote.local.only=false
程序流程:

  • 我运行Docker容器并将端口从主机公开/映射到容器。假设我在Docker中映射端口主机:1099->容器:1098
  • 我在docker中使用上述JMX设置运行JVM
  • Docker容器中的JMX代理现在侦听给定的端口1098
  • 我使用URL localhost:1099在主机(Docker外部)上启动JConsole。我使用1099,因为我使用了1099:1098的
    host:docker
    端口映射
  • JConsole很好地连接到Docker内部的JMX代理
  • JConsole询问JMX从何处读取监控数据
  • JMX代理使用配置的信息和地址进行响应:
    localhost:1098
  • JConsole现在尝试连接到给定的地址
    localhost:1098
  • 此操作失败,因为本地主机(Docker外部)上的端口1098未侦听。端口1099已映射到
    Docker:1098
    。JMX应该告诉JConsole从
    localhost:1099
    读取监控信息,而不是
    localhost:1098
    ,因为1099是Docker容器内从主机映射到1098的端口
作为修复,我将我的
host:docker
端口映射从
1099:1098
更改为
1098:1098
。现在,JMX仍然告诉JConsole连接到
localhost:1098
,以获取监控信息。但现在它可以工作了,因为外部端口与JMX inside Docker发布的相同

我希望同样的情况也适用于SSH隧道和类似场景。您必须将配置的JMX与ad匹配
 -Djava.rmi.server.hostname=0.0.0.0 \
                -Dcom.sun.management.jmxremote \
                -Dcom.sun.management.jmxremote.port=${JMX_PORT} \
                -Dcom.sun.management.jmxremote.rmi.port=${JMX_PORT} \
                -Dcom.sun.management.jmxremote.local.only=false \
                -Dcom.sun.management.jmxremote.authenticate=false \
                -Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.port=1098
-Dcom.sun.management.jmxremote.rmi.port=1098
-Djava.rmi.server.hostname=localhost
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.port=1098
-Dcom.sun.management.jmxremote.rmi.port=1098
-Djava.rmi.server.hostname=localhost
-Dcom.sun.management.jmxremote.local.only=false