没能躲开的云服务容器网络问题
source link: https://soulteary.com/2020/12/04/cloud-service-container-network-problems-that-could-not-be-avoided.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
遇到一个诡异的问题,在固定的 VPC 环境里运行了一年的 ECS 机器,突然连不上 RDS 数据库,而这个问题在早些时候,也曾在另外一台机器上出现过。
为了避免后续在业务日常运行和重大活动过程中出现类似问题,我们和阿里云进行了反馈,并进行的排查。
写在前面
由于同一业务分组的几台机器中,有两台(暂命名为 host-pre
、 host-01
)都出现了这个问题,所以我们将同一业务分组的几台机器同时作为样本进行问题排查。
在解决问题过程的时候,我们首先收集了基础环境的相关线索:
192.168.73.x
问题状况:连不通的数据库
分别使用服务器对数据库进行 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
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK