8

没能躲开的云服务容器网络问题

 3 years ago
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-prehost-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-02host-03 的网卡指定网段都在 172.27~30.1.1/8 内,而 host-01host-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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK