簡體   English   中英

如何從外部訪問docker中的JMX接口?

[英]How to access JMX interface in docker from outside?

我正在嘗試遠程監控在 docker 中運行的 JVM。 配置如下所示:

  • 機器 1:在 ubuntu 機器上的 docker 中運行 JVM(在我的情況下,運行 kafka); 本機IP為10.0.1.201; 在 docker 中運行的應用程序位於 172.17.0.85。

  • 機器 2:運行 JMX 監控

請注意,當我從機器 2 運行 JMX 監控時,它失敗並顯示以下錯誤版本(注意:運行 jconsole、jvisualvm、jmxtrans 和 node-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 和 node-jmx/npm:jmx)時,JMX 監控正常工作。

我認為這表明我的 JMX 端口處於活動狀態並且工作正常,但是當我遠程執行 JMX 監控(從機器 2)時,JMX 工具似乎無法識別內部 docker IP (172.17.0.85)

以下是 JMX 監控工作的機器 1 上的相關(我認為)網絡配置元素(注意 docker ip,172.17.42.1):

docker0   Link encap:Ethernet  HWaddr ...
      inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
      inet6 addr:... Scope:Link
      UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
      RX packets:6787941 errors:0 dropped:0 overruns:0 frame:0
      TX packets:4875190 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:0
      RX bytes:1907319636 (1.9 GB)  TX bytes:639691630 (639.6 MB)

wlan0     Link encap:Ethernet  HWaddr ... 
      inet addr:10.0.1.201  Bcast:10.0.1.255  Mask:255.255.255.0
      inet6 addr:... Scope:Link
      UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
      RX packets:4054252 errors:0 dropped:66 overruns:0 frame:0
      TX packets:2447230 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:1000
      RX bytes:2421399498 (2.4 GB)  TX bytes:1672522315 (1.6 GB)

這是我收到 JMX 錯誤的遠程機器(機器 2)上的相關網絡配置元素:

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

為了完整起見,以下解決方案有效。 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. 

完成此操作后,您應該能夠從本地或遠程機器執行 JMX 監控(jmxtrans、node-jmx、jconsole 等)。

感謝@Chris-Heald使這個修復變得非常快速和簡單!

對於開發環境,您可以將java.rmi.server.hostname設置為java.rmi.server.hostname IP 地址0.0.0.0

例子:

 -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

我發現嘗試通過 RMI 設置 JMX 很痛苦,尤其是因為您必須在啟動時指定-Djava.rmi.server.hostname=<IP> 我們在一切都是動態的 Kubernetes 中運行我們的 docker 鏡像。

我最終使用 JMXMP 而不是 RMI,因為它只需要打開一個 TCP 端口,不需要主機名。

我當前的項目使用Spring,可以通過添加以下內容進行配置:

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

(在 Spring 之外,您需要設置自己的 JMXConncetorServer 才能使其工作)

連同此依賴項(因為 JMXMP 是一個可選擴展,而不是 JDK 的一部分):

<dependency>
    <groupId>org.glassfish.main.external</groupId>
    <artifactId>jmxremote_optional-repackaged</artifactId>
    <version>4.1.1</version>
</dependency>

並且您需要在啟動 JVisualVM 時在您的類路徑中添加相同的 jar 以便通過 JMXMP 進行連接:

jvisualvm -cp "$JAVA_HOME/lib/tools.jar:<your_path>/jmxremote_optional-repackaged-4.1.1.jar"

然后使用以下連接字符串連接:

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

(默認端口為 9875)

挖了很多,我找到了這個配置

-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.0

為了增加一些額外的見解,我使用了一些 Docker 端口映射,並且之前的答案都沒有直接對我有用。 經過調查,我在這里找到了答案: How to connect with JMX from host to Docker container in Docker machine? 以提供所需的見解。

這就是我相信會發生的事情:

我按照其他答案中的建議設置了 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 中映射端口 host:1099->container:1098。
  • 我使用上述 JMX 設置在 docker 內運行 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 而不是localhost:1098 ,JMX 應該告訴 JConsole 從localhost:1099讀取監控信息,因為 1099 是從主機映射到 Docker 容器內的 1098 的端口。

作為修復,我將host:docker端口映射從1099:1098更改為1098:1098 現在,JMX 仍然告訴 JConsole 連接到localhost:1098以獲取監控信息。 但是現在它可以工作了,因為外部端口與 Docker 內部的 JMX 所宣傳的相同。

我希望這同樣適用於 SSH 隧道和類似的場景。 您必須匹配您配置 JMX 進行通告的內容以及 JConsole 將其視為運行它的主機上的地址空間的內容。

也許可以使用jmxremote.portjmxremove.rmi.porthostname屬性來使用不同的端口映射來完成這項工作。 但是我有機會使用相同的端口,所以使用它們簡化了它,這(對我來說)有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM