環境說明:
docker版本:20.10.3
nacos版本:1.3,而nacos鏡像是基於此版本自己製作的,並沒有拉取官方的鏡像。
如果我們的組件集成了nacos,那麼服務之間的調用都是採用服務名,來進行服務間的通信。所有的服務啓動的時候會向nacos註冊自己的地址。我們假設有下面的服務:
服務A---pmadmin
服務B---gateway
服務C---athena
問題描述
容器內的服務A在啓動的時候,需要去訪問服務gateway進行路由註冊,結果出現連接超時,報錯日誌:
從日誌中,看出,服務A-pmadmin 取訪問 gateway,實際是先去nacos拿到了gateway的地址:10.0.0.7:65,然後通過此地址訪問gateway,但是出現了連接超時,日誌如下:
問題排查
去nacos查詢gateway的地址,發現確實是10.0.0.7:65,地址是沒有問題,那是不是網絡的問題?
查看docker網絡
docker network ls
NETWORK ID NAME DRIVER SCOPE
52561b34842f bridge bridge local
0f0904683e30 docker_gwbridge bridge local
3273b79adf49 host host local
yuggnzybujkt iam_default overlay swarm
1yl193gp08xc ingress overlay swarm
45c9f5d126c9 none null local
iam_default這個網絡是我啓動iam 這個stack時,自動創建的網絡,我們看下這個網絡中有哪些容器
docker network inspect iam_default
[
{
"Name": "iam_default",
"Id": "yuggnzybujktpkkutkf0110pu",
"Created": "2021-03-10T16:52:56.364889741+08:00",
"Scope": "swarm",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "10.0.1.0/24",
"Gateway": "10.0.1.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
......
"c4d4ce1fc5330d791b8fbdf2869bfc40bd64535f5ae6d5ad51531227c5c87472": {
"Name": "iam_nacosserver.1.o8ccif1ktcaoh7pj21qnrsyql",
"EndpointID": "076e8d35347afe3fb5980629837d2008d1d9affe138e5dcb07c1646e4f4008c1",
"MacAddress": "02:42:0a:00:01:06",
"IPv4Address": "10.0.1.6/24",
"IPv6Address": ""
},
"fae43956f124d19248d7d00dfc1be4bb615ccde82b5875c15f8ffa4193ece218": {
"Name": "iam_gateway.1.z40ua51l1wlhrsxdol1v35o32",
"EndpointID": "8fc8443b9f7d19d5cb4854b6424c4178dcabf92fd7a4a955fc908dafe820f859",
"MacAddress": "02:42:0a:00:01:0c",
"IPv4Address": "10.0.1.12/24",
"IPv6Address": ""
},
"lb-iam_default": {
"Name": "iam_default-endpoint",
"EndpointID": "f5ecad6250919d7730a3d4bb588eb2d710d673964dd839052e2d89644cbf52a6",
"MacAddress": "02:42:0a:00:01:04",
"IPv4Address": "10.0.1.4/24",
"IPv6Address": ""
}
注意到iam_default這個網絡中的所有容器都在10.0.1.0/24這個網段中,並且裏面有個gateway的地址爲10.0.1.12,省略其他無關的容器詳情。
問題來了,那10.0.0.7這個地址也是gateway的地址啊,這個是從nacos的頁面確認的
我們知道,swarm集羣正常工作需要兩個overlay網絡,在現在這個環境裏,除了iam_default之外,還有一個ingress的網絡,這個網絡的主要目的是將外部流量導到我們的集羣服務,也就是iam-default網絡的服務。
那確認一下10.0.0.7這個地址是屬於 ingress網絡的。查看ingress網絡中的容器地址:發現所有的容器 在 10.0.0.0/24 這個網絡中
docker network inspect ingress
[
{
"Name": "ingress",
"Id": "1yl193gp08xc48ogm5l2qnf8q",
"Created": "2021-03-10T16:52:56.364392994+08:00",
"Scope": "swarm",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "10.0.0.0/24",
"Gateway": "10.0.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": true,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"344903fbfd671c51bbe4ca379a29ddcdd1b970555229caca57fdb89a8b7fe56c": {
"Name": "iam_pmadmin.1.oqtdd8wo0rhff813a2fjjmtoq",
"EndpointID": "f2fc565d0ceb7df1fe80a031523e324a2bef33f909d2faa5ad3f58af6f9f2f36",
"MacAddress": "02:42:0a:00:00:c9",
"IPv4Address": "10.0.0.201/24",
"IPv6Address": ""
},
"c4d4ce1fc5330d791b8fbdf2869bfc40bd64535f5ae6d5ad51531227c5c87472": {
"Name": "iam_nacosserver.1.o8ccif1ktcaoh7pj21qnrsyql",
"EndpointID": "7582d63054303734363d7b9d8dd7d69d5a733ca31cf39b00aaafcc1968a8c5d0",
"MacAddress": "02:42:0a:00:00:04",
"IPv4Address": "10.0.0.4/24",
"IPv6Address": ""
},
"fae43956f124d19248d7d00dfc1be4bb615ccde82b5875c15f8ffa4193ece218": {
"Name": "iam_gateway.1.z40ua51l1wlhrsxdol1v35o32",
"EndpointID": "0e08b11fe06750edb5252b757f464aa07dbb672976066bb69c69917b253468b3",
"MacAddress": "02:42:0a:00:00:07",
"IPv4Address": "10.0.0.7/24",
"IPv6Address": ""
},
"ingress-sbox": {
"Name": "ingress-endpoint",
"EndpointID": "e0845b4d04150dfda8bb30259a2d2c9516e55b0716bdbc7c03c467e4bceb0395",
"MacAddress": "02:42:0a:00:00:02",
"IPv4Address": "10.0.0.2/24",
"IPv6Address": ""
}
我們確實發現了10.0.0.7這個地址是gateway的。所以,10.0.1.12和10.0.0.7是swarm網絡中 不同網絡的地址,也就是說nacos客戶端採集的地址是ingress網絡中的地址,也就是10.0.0.7這個地址。
那爲什麼服務A去訪問服務B不通呢?難道是網絡不通。
由於服務A沒有啓動,無法進入容器內部,我們進入此集羣中另外一個容器c-athena 內部,看看這個容器的網絡是什麼樣的情況?
cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.0.1.8 athena
發現athena這個服務的地址10.0.1.8 此地址恰好在iam-default這個網絡中,也就是說容器裏的ip地址,採用的是集羣服務網絡,而不是ingress網絡,這也是說的通的,ingress網絡主要是用來流量導向的。
在此容器內部,我們看下和ingress網絡的聯通性
# ping 10.0.0.7
PING 10.0.0.7 (10.0.0.7) 56(84) bytes of data.
64 bytes from 10.0.0.7: icmp_seq=1 ttl=64 time=0.144 ms
64 bytes from 10.0.0.7: icmp_seq=2 ttl=64 time=0.075 ms
64 bytes from 10.0.0.7: icmp_seq=3 ttl=64 time=0.080 ms
64 bytes from 10.0.0.7: icmp_seq=4 ttl=64 time=0.077 ms
^C
--- 10.0.0.7 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.075/0.094/0.144/0.028 ms
說明iam_default網絡中的容器,訪問ingress網絡中的gateway容器地址可以聯通。
那我們再ping 一下gateway,看下到底返回哪個地址
# ping gateway
PING gateway (10.0.1.12) 56(84) bytes of data.
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=1 ttl=64 time=0.301 ms
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=2 ttl=64 time=0.074 ms
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=3 ttl=64 time=0.065 ms
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=4 ttl=64 time=0.075 ms
iam_default網絡中的所有地址是互通的,都是在10.0.1.0/24網絡中的。gateway的地址是10.0.1.12,這也說明了,容器內部的ipvs服務也是正常工作的。
以上實驗說明:
ingress網絡和iam-default網絡互通,
容器內部的地址採用的是iam-default這個集羣服務網絡中地址,在10.0.1.0/24網段中。
所以最開始的那個問題,連接超時實際是
10.0.1.0/24中的某個地址去訪問10.0.0.7:65這個服務沒有連接成功。
實驗
那麼直接通過iam_default網絡訪問gateway能否成功呢?
經過實驗發現,修改服務A配置,讓其直接訪問iam-default中gateway的地址10.0.1.12:65,
也就是說將 https://gateway/xxx改爲 https://10.0.1.12:65/xxx
這樣是可以正常通信的:
同樣,將gateway的地址的地址改爲 物理機ip也是正常啓動的。
問題來了:
- 容器訪問ingress(10.0.0.0/24)不行,訪問iam_default(10.0.1.0/24)是可以的,但是又是可以ping的,那麼爲什麼網絡互通的情況下,到了tcp協議這一層就不通了呢?
- nacos客戶端採集的地址是 ingress網絡中的,爲什麼不是iam-default網絡中的。
問題解決
查閱nacos的資料,發現可以讓客戶端自定義註冊的地址,因爲一般容器中會有多個網卡,nacos採集的地址不一定就是我們想要的那個,所以如何讓客戶端採集某個網卡的地址向服務器註冊呢?可以參見下面的解決方案,確實解決我遇到的問題。
如何讓nacos中服務註冊的ip是自定義的網段ip ( docker swarm )
好,採用上面方法解決了問題,那遺留的問題就是爲啥:同一網絡中的容器互相訪問的時候,通過ingress網絡無法通信(即使可以ping通ingress網絡中的地址),現在的猜想如下:
所謂的端口暴露,應該是物理機和集羣網絡(而不是ingress)之間的映射,容器訪問ingress網絡中的某個地址時,無法根據端口做轉發??
擴展知識
在服務c-athena容器內部,查看網卡信息
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
37646: eth0@if37647: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 02:42:0a:00:01:08 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.0.1.8/24 brd 10.0.1.255 scope global eth0
valid_lft forever preferred_lft forever
37658: eth2@if37659: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:13:00:08 brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet 172.19.0.8/16 brd 172.19.255.255 scope global eth2
valid_lft forever preferred_lft forever
37680: eth1@if37681: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 02:42:0a:00:00:05 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 10.0.0.5/24 brd 10.0.0.255 scope global eth1
valid_lft forever preferred_lft forev
eth0:10.0.1.8 ——iam_default網絡
eth1: 10.0.0.5 —— ingress網絡
eth2: 172.19.0.8 ——docker_gwbridge網絡
前面兩個都已經證實了,證實一下eth2網絡,在主機上執行一下命令,發現,docker_gwbridge網絡中的容器地址都在172.19.0.0/24網中,
docker network inspect docker_gwbridge |grep Gateway
"Gateway": "172.19.0.1"
所以,以上三個網卡分別對應三個網絡,根據不同ip走不同的網卡,流量默認走docker_gwbridge網絡
# ip route
default via 172.19.0.1 dev eth2
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.5
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.8
172.19.0.0/16 dev eth2 proto kernel scope link src 172.19.0.8
在主機上查看路由,也有三個網絡,默認走ens192網卡,看到最後一個docker_gwbridge,負責172.19.0.0網段。所以容器也可以通過docker_gwbridge和主機通信。
ip route
default via 10.92.4.1 dev ens192 proto static metric 100
10.92.4.0/24 dev ens192 proto kernel scope link src 10.92.4.126 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.19.0.0/16 dev docker_gwbridge proto kernel scope link src 172.19.0.1
更多的docker網絡知識:
https://blog.neuvector.com/article/docker-swarm-container-networking