遇到一个诡异的问题,在固定的 VPC 环境里运行了一年的 ECS 机器,突然连不上 RDS 数据库,而这个问题在早些时候,也曾在另外一台机器上出现过。

为了避免后续在业务日常运行和重大活动过程中出现类似问题,我们和阿里云进行了反馈,并进行的排查。

写在前面

由于同一业务分组的几台机器中,有两台(暂命名为 host-prehost-01)都出现了这个问题,所以我们将同一业务分组的几台机器同时作为样本进行问题排查。

在解决问题过程的时候,我们首先收集了基础环境的相关线索:

  • 机器运行应用均为无状态容器,没有持久化内容存在。
  • 被测试的机器均处于相同 VPC 环境内,为避免容器网络问题,2019 年初始化 VPC 时使用了比较不容易撞车的 192.168.73.x 网段。。
  • 机器、数据库都没有关闭 ICMP。
  • 机器的安全策略组允许访问 RDS。
  • 机器在数据库白名单之内。
  • 这几台机器都是于去年购买,在一个月前执行过系统版本和软件升级。
  • 这几台机器在半年前执行过硬件配置升降级。

问题状况:连不通的数据库

分别使用服务器对数据库进行 ping

发现只有第一台 host-pre 出现了 Destination Host Unreachable,其余几台均正常。host-01 在早些时候也出现过相同的问题。

登录服务器:进一步探查问题

既然 host-pre 出现问题,我们就先来排查下它的容器运行状况是否出现问题。登录机器 ,忽略掉最近更新变动的应用,可以看到机器上目前运行最久的应用的启动时间是七个月前,分别使用 exec ,以及 curl 请求本地服务,都有正常的反馈,所以首先可以排除是容器应用自身的问题。

接着我们试着在 host-pre 上 ping 其他的服务器,发现也是正常的,所以 VPC 网络内的连通性也是没有问题的,那么问题应该是出现在了 “ECS 或 VPC 到 RDS” 的网络被“阻塞”了。

排查路由表:定位问题

随后,阿里云 ECS 的工程师建议我们进行路由表的排查,于是我们分别在几台机器上查看了路由规则状况:

可以看到机器基础 VPC 网络都在 192.168.73.1/24 段内,唯一有差别的是 docker 创建的桥接网卡。

host-02host-03 的网卡指定网段都在 172.27~30.1.1/8 内,而 host-01host-pre 的网卡则出现了两张在 192.168.x.x 的网卡:

看到路由表之后,阿里云工程师反馈网络冲突了,第一反应确实如此,因为在排查连通性的时候,我们确实看到了当前连接 RDS 的地址是 192.168.0.xxx 的远程地址。但是随后我们又想到了一个问题,为什么这个问题现在才出现,或者说,为什么之前的业务运行没有受到影响呢?

此时阿里云工程师提示我们“RDS 实例IP地址可能发生变化,连接串则始终不变,请使用以上连接串进行实例连接。”

到了这个时候,答案呼之欲出:容器创建应用内部桥接网卡的网段和阿里云 RDS 网络撞车了。 虽然概率很小,但是它确实出现了,因为 CI/CD 过程中容器会随机创建新的应用内部网卡,赶巧和 RDS 网络切换后的地址撞在了一起,就会出现这个问题。

和阿里云工程师沟通确认 “ 192.168.0.0/16 是 RDS 所在 VPC 的网段”后,就可以放心动手解决问题了。

解决问题:修改容器网卡地址分配规则

登录 host-pre ,先再次打印路由表,以及查看容器创建的网卡列表:

可以看到 br-c3c094fc6759 这个网卡在 docker 中命名为 c3c094fc6759,是由 project-grpup_project-name 这个项目创建,使用的网络段确实是和 RDS 发生了冲突。

通过查看 docker 官方文档,我们可以找到我们需要的 daemon 配置项 default-address-pools,来主动规避掉和阿里云 RDS 网络冲突的问题。

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

在修改配置后,执行 service docker restart,接着重新启动应用,触发重新创建内部网卡逻辑,然后再次查看容器网卡列表:

看到创建的新网卡为 5089b1504e22,我们使用 inspect 检查网卡分配网络:

可以看到分配网络与我们预期一致,规避了 192.168.0.0/16 ,至此问题解决。

最后

如同“墨菲定律”所言,凡是可能出错的事情就一定会出错。

为了避免出错,靠谱的方案是:彻底查出可能出现事故的问题所在和根本原因,对其进行标本兼治的方案,才能防患于未然。

–EOF