沒能躲開的雲服務容器網絡問題

沒能躲開的雲服務容器網絡問題
遇到一個詭異的問題,在固定的 VPC 環境裏運行了一年的 ECS 機器,突然連不上 RDS 數據庫,而這個問題在早些時候,也曾在另外一臺機器上出現過。

爲了避免後續在業務日常運行和重大活動過程中出現類似問題,我們和阿里雲進行了反饋,並進行的排查。

寫在前面
由於同一業務分組的幾臺機器中,有兩臺(暫命名爲 host-pre、host-01)都出現了這個問題,所以我們將同一業務分組的幾臺機器同時作爲樣本進行問題排查。

在解決問題過程的時候,我們首先收集了基礎環境的相關線索:

  • 機器運行應用均爲無狀態容器,沒有持久化內容存在。
  • 被測試的機器均處於相同 VPC 環境內,爲避免容器網絡問題,2019 年初始化 VPC 時使用了比較不容易撞車的 192.168.73.x 網段。。
  • 機器、數據庫都沒有關閉 ICMP。
  • 機器的安全策略組允許訪問 RDS。
  • 機器在數據庫白名單之內。
  • 這幾臺機器都是於去年購買,在一個月前執行過系統版本和軟件升級。
  • 這幾臺機器在半年前執行過硬件配置升降級。
    問題狀況:連不通的數據庫
    分別使用服務器對數據庫進行 ping:


ssh host-pre ping rm-intra.mysql.rds.aliyuncs.com
PING rm-intra.mysql.rds.aliyuncs.com (192.168.0.166) 56(84) bytes of data.
From host-pre (192.168.0.1) icmp_seq=1 Destination Host Unreachable
From host-pre (192.168.0.1) icmp_seq=2 Destination Host Unreachable
From host-pre (192.168.0.1) icmp_seq=3 Destination Host Unreachable



ssh host-01 ping rm-intra.mysql.rds.aliyuncs.com
PING rm-intra.mysql.rds.aliyuncs.com (192.168.0.166) 56(84) bytes of data.
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=1 ttl=102 time=1.11 ms
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=2 ttl=102 time=1.09 ms
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=3 ttl=102 time=1.12 ms



ssh host-02 ping rm-intra.mysql.rds.aliyuncs.com
PING rm-intra.mysql.rds.aliyuncs.com (192.168.0.166) 56(84) bytes of data.
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=1 ttl=102 time=0.992 ms
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=2 ttl=102 time=0.994 ms
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=3 ttl=102 time=0.977 ms



ssh host-03 ping rm-intra.mysql.rds.aliyuncs.com
PING rm-intra.mysql.rds.aliyuncs.com (192.168.0.166) 56(84) bytes of data.
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=1 ttl=102 time=1.07 ms
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=2 ttl=102 time=1.07 ms
64 bytes from 192.168.0.166 (192.168.0.166): icmp_seq=3 ttl=102 time=1.04 ms




發現只有第一臺 host-pre 出現了 Destination Host Unreachable,其餘幾臺均正常。host-01 在早些時候也出現過相同的問題。

**登錄服務器:進一步探查問題**
既然 host-pre 出現問題,我們就先來排查下它的容器運行狀況是否出現問題。登錄機器 ,忽略掉最近更新變動的應用,可以看到機器上目前運行最久的應用的啓動時間是七個月前,分別使用 exec ,以及 curl 請求本地服務,都有正常的反饋,所以首先可以排除是容器應用自身的問題。

docker ps -a

...
c092f8c5f41e docker.dev.baai.ac.cn/nesletter-api:0.9.1 "docker-php-entrypoi…" 4 months ago Up 4 months (healthy) 9000/tcp newsletter-api
ed0c7fb1945f docker.dev.baai.ac.cn/hub-node-gate:14 "docker-entrypoint.s…" 4 months ago Up 4 months 3000/tcp xxxxx_1
7aba2cbc2e21 traefik:v2.2.0 "/entrypoint.sh trae…" 5 months ago Up 5 months (healthy) 0.0.0.0:80->80/tcp traefik
1a9e0a150133 xxx:4.7.6-xxx "entrypoint.sh docke…" 7 months ago Up 7 months 8080/tcp xxx_1




接着我們試着在 host-pre 上 ping 其他的服務器,發現也是正常的,所以 VPC 網絡內的連通性也是沒有問題的,那麼問題應該是出現在了 “ECS 或 VPC 到 RDS” 的網絡被“阻塞”了。

**排查路由表:定位問題**
隨後,阿里雲 ECS 的工程師建議我們進行路由表的排查,於是我們分別在幾臺機器上查看了路由規則狀況:

ssh host-pre route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.73.253 0.0.0.0 UG 100 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-df03b027a5e8
192.168.0.0 0.0.0.0 255.255.240.0 U 0 0 0 br-c3c094fc6759
192.168.73.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.73.253 0.0.0.0 255.255.255.255 UH 100 0 0 eth0







ssh host-01 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.73.253 0.0.0.0 UG 100 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-0cb13ae8df3c
192.168.32.0 0.0.0.0 255.255.240.0 U 0 0 0 br-bb02c47906ee
192.168.73.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.73.253 0.0.0.0 255.255.255.255 UH 100 0 0 eth0







ssh host-02 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.73.253 0.0.0.0 UG 100 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-405544233f47
172.28.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-f11216ce202f
192.168.73.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.73.253 0.0.0.0 255.255.255.255 UH 100 0 0 eth0







ssh host-03 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.73.253 0.0.0.0 UG 100 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-df03b027a5e8
172.19.0.0 0.0.0.0 255.255.255.0 U 0 0 0 br-5089b1504e22
192.168.73.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.73.253 0.0.0.0 255.255.255.255 UH 100 0 0 eth0








可以看到機器基礎 VPC 網絡都在 192.168.73.1/24 段內,唯一有差別的是 docker 創建的橋接網卡。

host-02 和 host-03 的網卡指定網段都在 172.27~30.1.1/8 內,而 host-01 和 host-pre 的網卡則出現了兩張在 192.168.x.x 的網卡:

host-pre
192.168.0.0 0.0.0.0 255.255.240.0 U 0 0 0 br-c3c094fc6759

host-01
192.168.32.0 0.0.0.0 255.255.240.0 U 0 0 0 br-bb02c47906ee


看到路由表之後,阿里雲工程師反饋網絡衝突了,第一反應確實如此,因爲在排查連通性的時候,我們確實看到了當前連接 RDS 的地址是 192.168.0.xxx 的遠程地址。但是隨後我們又想到了一個問題,爲什麼這個問題現在纔出現,或者說,爲什麼之前的業務運行沒有受到影響呢?

此時阿里雲工程師提示我們“RDS 實例IP地址可能發生變化,連接串則始終不變,請使用以上連接串進行實例連接。”

到了這個時候,答案呼之欲出:容器創建應用內部橋接網卡的網段和阿里雲 RDS 網絡撞車了。 雖然概率很小,但是它確實出現了,因爲 CI/CD 過程中容器會隨機創建新的應用內部網卡,趕巧和 RDS 網絡切換後的地址撞在了一起,就會出現這個問題。

和阿里雲工程師溝通確認 “ 192.168.0.0/16 是 RDS 所在 VPC 的網段”後,就可以放心動手解決問題了。

**解決問題:修改容器網卡地址分配規則**
登錄 host-pre ,先再次打印路由表,以及查看容器創建的網卡列表:

host-pre:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.73.253 0.0.0.0 UG 100 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-df03b027a5e8
192.168.0.0 0.0.0.0 255.255.240.0 U 0 0 0 br-c3c094fc6759
192.168.73.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.73.253 0.0.0.0 255.255.255.255 UH 100 0 0 eth0







host-pre:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
0fba8dbbbff8 bridge bridge local
8b92ba96f640 host host local
c3c094fc6759 project-grpup_project-name bridge local
123b8780367b none null local
df03b027a5e8 traefik bridge local






可以看到 br-c3c094fc6759 這個網卡在 docker 中命名爲 c3c094fc6759,是由 project-grpup_project-name 這個項目創建,使用的網絡段確實是和 RDS 發生了衝突。

通過查看 docker 官方文檔,我們可以找到我們需要的 daemon 配置項 default-address-pools,來主動規避掉和阿里雲 RDS 網絡衝突的問題。

修改 /etc/docker/daemon.json ,聲明和 192.168.0.0/16 不衝突的地址:

{
...
"default-address-pools": [
{
"base": "172.18.0.0/16",
"size": 24
},
{
"base": "172.19.0.0/16",
"size": 24
},
{
"base": "172.20.0.0/16",
"size": 24
},
{
"base": "172.21.0.0/16",
"size": 24
},
{
"base": "172.22.0.0/16",
"size": 24
},
...
]
}

























在修改配置後,執行 service docker restart,接着重新啓動應用,觸發重新創建內部網卡邏輯,然後再次查看容器網卡列表:

docker network ls
NETWORK ID NAME DRIVER SCOPE
52a7bbc2b5fe bridge bridge local
8b92ba96f640 host host local
5089b1504e22 project-grpup_project-name bridge local
123b8780367b none null local
df03b027a5e8 traefik bridge local






看到創建的新網卡爲 5089b1504e22,我們使用 inspect 檢查網卡分配網絡:

docker inspect 5089b1504e22 --format='{{json .IPAM.Config}}'
[{"Subnet":"172.19.0.0/24","Gateway":"172.19.0.1"}]



可以看到分配網絡與我們預期一致,規避了 192.168.0.0/16 ,至此問題解決。

**最後**
如同“墨菲定律”所言,凡是可能出錯的事情就一定會出錯。

爲了避免出錯,靠譜的方案是:徹底查出可能出現事故的問題所在和根本原因,對其進行標本兼治的方案,才能防患於未然。

--EOF
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章