文章目錄
- 一、前言
- 二、遇到的問題
- 1、問題現象
- 2、問題分析
- 三、解決方案
- 四、總結
一、前言
今天在配置 docker 和 JMX 監控的時候,看到有一個細節和非容器環境中的 JMX 配置不太一樣,所以在這里寫一下,以備其他人查閱,
二、遇到的問題
1、問題現象
一般情況下,我們配置 JMX 只要寫上下面這些引數就可以了,
以下是無密碼監控時的 JMX 配置引數(有密碼監控的配置和常規監控無異)
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9998
-Djava.rmi.server.hostname=<serverip>
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
但是在 docker 容器中這樣配置的時候,會出現這個錯誤,

2、問題分析
這里就要說明一下邏輯了,為什么會這樣呢?
先看 docker 環境的網路結構,
容器使用默認的網路模型,就是 bridge 模式,在這種模式下是 docker run 時做的 DNAT 規則,實作資料轉發的能力,所以我們看到的網路資訊是以下這樣的:
docker 中的網卡資訊:
[root@f627e4cb0dbc /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.3 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:acff:fe12:3 prefixlen 64 scopeid 0x20<link>
ether 02:42:ac:12:00:03 txqueuelen 0 (Ethernet)
RX packets 366 bytes 350743 (342.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 358 bytes 32370 (31.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
docker 中的路由資訊:
[root@a2a7679f8642 /]# netstat -r
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default gateway 0.0.0.0 UG 0 0 0 eth0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
[root@a2a7679f8642 /]#
宿主機上的對應網卡資訊:
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether 02:42:44:5a:12:8f txqueuelen 0 (Ethernet)
RX packets 6691477 bytes 498130
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6751310 bytes 3508684363 (3.2 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
宿主機上的路由資訊:
[root@7dgroup ~]# netstat -r
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default gateway 0.0.0.0 UG 0 0 0 eth0
link-local 0.0.0.0 255.255.0.0 U 0 0 0 eth0
172.17.208.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.16.0 0.0.0.0 255.255.240.0 U 0 0 0 br-676bae33ff92
所以宿主機和容器是可以直接通信的,即便埠沒有映射出來,如下所示:
[root@7dgroup ~]# telnet 172.18.0.3 8080
Trying 172.18.0.3...
Connected to 172.18.0.3.
Escape character is '^]'.
另外,因為是橋接的,宿主機上還有類似 veth0b5a080 的虛擬網卡設備資訊,如:
eth0b5a080: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 42:c3:45:be:88:1a txqueuelen 0 (Ethernet)
RX packets 2715512 bytes 2462280742 (2.2 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2380143 bytes 2437360499 (2.2 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
這就是虛擬網卡對 veth pair,docker 容器里一個,宿主機一個, 在這種模式下,有幾個容器,主機上就會有幾個 veth 開頭的虛擬網卡設備,
但是如果不是宿主機訪問的話,肯定是不通的,如下圖所示:

當我們用監控機 訪問的時候,會是這樣的結果:
Zees-Air-2:~ Zee$ telnet <serverip> 8080
Trying <serverip>...
telnet: connect to address <serverip>: Connection refused
telnet: Unable to connect to remote host
Zees-Air-2:~ Zee$
因為 8080 是容器開的埠,并不是宿主機開的埠,其他機器是訪問不了的, 這就是為什么要把埠映射出來給遠程訪問的原因,映射之后的埠,就會有 NAT 規則來保證資料包可達,
查看下 NAT 規則,就知道,如下:
[root@7dgroup ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 171 packets, 9832 bytes)
pkts bytes target prot opt in out source destination
553K 33M DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 171 packets, 9832 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 2586 packets, 156K bytes)
pkts bytes target prot opt in out source destination
205K 12M DOCKER all -- * * 0.0.0.0/0 !60.205.104.0/22 ADDRTYPE match dst-type LOCAL
0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 2602 packets, 157K bytes)
pkts bytes target prot opt in out source destination
265K 16M MASQUERADE all -- * !docker0 172.18.0.0/16 0.0.0.0/0
0 0 MASQUERADE all -- * !br-676bae33ff92 192.168.16.0/20 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 192.168.0.4 192.168.0.4 tcp dpt:7001
0 0 MASQUERADE tcp -- * * 192.168.0.4 192.168.0.4 tcp dpt:4001
0 0 MASQUERADE tcp -- * * 192.168.0.5 192.168.0.5 tcp dpt:2375
0 0 MASQUERADE tcp -- * * 192.168.0.8 192.168.0.8 tcp dpt:8080
0 0 MASQUERADE tcp -- * * 172.18.0.4 172.18.0.4 tcp dpt:3306
0 0 MASQUERADE tcp -- * * 172.18.0.5 172.18.0.5 tcp dpt:6379
0 0 MASQUERADE tcp -- * * 172.18.0.2 172.18.0.2 tcp dpt:80
0 0 MASQUERADE tcp -- * * 172.18.0.6 172.18.0.6 tcp dpt:9997
0 0 MASQUERADE tcp -- * * 172.18.0.6 172.18.0.6 tcp dpt:9996
0 0 MASQUERADE tcp -- * * 172.18.0.6 172.18.0.6 tcp dpt:8080
0 0 MASQUERADE tcp -- * * 172.18.0.3 172.18.0.3 tcp dpt:9995
0 0 MASQUERADE tcp -- * * 172.18.0.3 172.18.0.3 tcp dpt:8080
Chain DOCKER (3 references)
pkts bytes target prot opt in out source destination
159K 9544K RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- br-676bae33ff92 * 0.0.0.0/0 0.0.0.0/0
1 40 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3307 to:172.18.0.4:3306
28 1486 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:6379 to:172.18.0.5:6379
228 137K DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:91 to:172.18.0.2:80
3 192 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9997 to:172.18.0.6:9997
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9996 to:172.18.0.6:9996
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9002 to:172.18.0.6:8080
12 768 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9995 to:172.18.0.3:9995
4 256 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:9004 to:172.18.0.3:8080
[root@7dgroup ~]#
我們看到了宿主機的 91 埠的資料會傳給 172.18.0.2 的 80 埠,宿主機的 3307 埠會傳給 172.18.0.4 的3306 埠,
啰啰嗦嗦說到這里,那和 JMX 有啥關系,苦就苦在,JMX 是這樣的:

在注冊時使用的是引數 jmxremote.port,然后回傳一個新的埠 jmxremote.rmi.port,
在呼叫服務時使用是引數 jmxremote.rmi.port, 前面提到了,因為 docker 在 bridge 模式下埠是要用 -p 顯式指定的,不然沒 NAT 規則,資料包不可達,所以在這種情況下,只能把 jmxremote.rmi.port 也暴露出去,所以必須顯式指定,因為不指定的話,這個埠會隨機開,隨機開的埠又沒 NAT 規則,所以是不通的了,
三、解決方案
所以,這種以上情況只能指定 jmxremote.rmi.port 為固定值,并暴露出去, 配置如下:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9995
-Djava.rmi.server.hostname=<serverip>
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.rmi.port=9995
像上面的設定就是兩個都是 9995,這樣是允許的,這種情況下注冊和呼叫的埠就合并了,
再啟動 docker 容器的時候,就需要這樣了,
docker run -d -p 9003:8080 -p 9995:9995 --name 7dgroup-tomcat5
-e CATALINA_OPTS="-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9995 \
-Djava.rmi.server.hostname=<serverip> \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.rmi.port=9995" c375edce8dfd
然后就可以連接上 JMX 的工具了,



在有防火墻和其他的設備的網路環境中,也有可能出同樣的問題,明白了JMX 的注冊呼叫邏輯之后,就可以解決各種類似的問題了,
網路鏈路是做性能分析的人必須想明白的技術點,所以前面說了那么多內容,
四、總結
這里對于 JMX 工具的選擇啰嗦兩句,有人喜歡花哨的,有人喜歡簡單的,有人喜歡黑視窗的,我覺得工具選擇的時候,要看適用情況,在性能分析的時候,一定要選擇合適的工具,而不是選擇體現技術高超的工具,
最后留個作業:
-
如果
docker run中如果指定-p 19995:9995,也就是換個埠暴露出去,其他配置都不變,JMX 工具還能連得上嗎? -
如果
jmxremote.rmi.port和jmxremote.port不合并,并且同時把兩個埠都暴露出去,其他配置都不變,JMX 工具還能連得上嗎?
有興趣的可以自己嘗試下哦,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286364.html
標籤:其他
上一篇:關于Linux下的一點補充
