记录一次本网站数据库连接失败Error establishing a database connection故障排查及解决 系Docker与Firewalld Iptables冲突导致

大清早起来一看手机,发现监控推送的告警,网站挂了!淡定煎蛋、冲咖啡,开始排错。

监控显示,发现故障发生在 2024 年 5 月 21 日 22 点 41 分 19 秒。

站点状态:

先说下网站的运行环境:

主机:AlmaLinux
应用中间件均为 Docker 部署:PHP、Redis、OpenResty、RDS-MySQL

版本我都全盘脱出了,希望大佬们不要针对来搞我。

排查思路

  1. 排查数据库状态是否正常
  2. 检查PHP状态是否正常
  3. 检查OpenRsty状态是否正常
  4. Redis

1、数据库

数据库使用的是阿里云的 RDS-MySQL8
云管控制台未发现告警,通过站点云主机远程登录数据库正常;
另一站点也是用的此数据库,可正常访问。

故排除数据库故障。

2、PHP

docker ps 查看容器运行状态正常;
查看日志无异常,只是故障时间点请求PHP时超时,无法连接;

估计容器网络有些问题,继续向下排查。

3、OpenResty

检查了OpenResty的容器日志,相关时间节点无报错;

网站WordPress error.log日志无报错;
网站WordPress access.log故障时间节点无法被访问

未发现问题。

4、Redis

Redis 只做缓存,故不考虑。

嗯???

麻了,排查了一遍,均为发现什么问题,那是怎么回事儿呢?

因为网站报错,Error establishing a database connection,此错误是 PHP 无法连接数据库,所以还是把问题定位到 PHP,(是不是PHP有什么bug,导致无法连接数据库了,重启大法?)于是尝试重启PHP容器看是否可以解决。

docker restart php8

居然报错了,无法重新启动,详细报错如下:

服务内部错误:
stderr: Container 1Panel-php8-dC9R Restarting Error response from daemon: Cannot restart container a154463a11dd19ce26527fe69abf78e3c2887463c415e94228f4412c395436c1:
driver failed programming external connectivity on endpoint 1Panel-php8-dC9R
(2a71d44d9496f8a05cfac440bba22a72cc378bca0d75c305927ef852ced8da70):
(COMMAND_FAILED: ‘/usr/sbin/iptables -w10 -t nat -A DOCKER -p tcp -d 127.0.0.1 –dport 9000 -j DNAT –to-destination 172.19.0.2:9000 ! -i br-002aa63fa594’ failed: iptables: No chain/target/match by that name. )

一眼看出,重点在这:

COMMAND_FAILED: '/usr/sbin/iptables -w10 -t nat -A DOCKER -p tcp -d 127.0.0.1 --dport 9000 -j DNAT --to-destination 172.19.0.2:9000 ! -i br-002aa63fa594' failed: iptables: No chain/target/match by that name.

这什么东西,查不到这个“链”了?怎么会突然消失呢?

于是开始了一番查阅,发现是Firewalld和Docker冲突;
众所周知,docker是默认会自动创建网桥,并使用网桥桥接上网,一般将此网桥自动名为docker0,它会通过iptables来管理它的容器之间的通信和容器与宿主机的通信,又众所周知,Firewalld配置的规则,最终也是使用iptables来管理,并且共同使用 nat 表和 filter 表,所以Firewalld的重载可能会清除覆盖掉docker创建的规则。

查看Firewalld日志:

May 22 09:10:58 wanwan firewalld[184557]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w10 -t nat -A DOCKER -p tcp -d 127.0.0.1 --dport 9000 -j DNAT --to-destination 172.19.0.2:9000 ! -i br-002aa63fa594' failed: iptables: No chain/target/match by that name.

确实,添加规则失败了,所以容器无法启动。

尝试把Firewalld关掉,再重启容器,重启成功,网站也可以正常访问了。

ps:但是,确实没人重载docker或者Firewalld配置,至于为啥会突然网络不通了,是不是策略被覆盖、失效,懂的大佬可以评论区指导下。

如何在开启Firewalld的情况下解决此问题呢

其实这个问题在docker的官方文档里也是有记录的:Packet filtering and firewalls | Docker Docs

在Docker 20.10.0后的版本也对此问题进行了解决,但是我的Docker为什么都26.1.1版本了,还是出现了这个问题呢?
可能的原因:(猜测)

  1. 我是在安装完Docker后才启用的Firewalld,可能在Docker启动过程中,没有检测到Firewalld,所以没进行处理;(猜对了
  2. Docker默认的网桥名为docker0,但是我并没有使用它,我使用了自己创建的br-002aa63fa594,并不会把后期自定义的网桥加入进去。

那就要说说Docker是如何在20.10.0后解决的此问题了:
Docker 在启动时会自动检测 firewalld 是否正在运行,如果检测到 firewalld 运行,它会创建一个名为 docker 的区域(zone),并在该区域中应用 Docker 需要的 iptables 规则。

可能在部署完容器后,也没有重启过docker,所以才一直没有将网卡自动加入到docker zone中吧。

可以看出确实有docker zone,但是services中是空的,表明br-002aa63fa594和docker0网桥并没有在其中。

不想直接重启docker服务?那咱就手动添加:

查询了一下现在活动中的zone,只有public,并没有docker

执行:

firewall-cmd --zone=docker --add-interface=br-002aa63fa594 --permanent
firewall-cmd --reload
firewall-cmd --get-active-zones
firewall-cmd --list-all-zones

网桥已经被加入到docker zone中,再起尝试重启php容器;
(重启成功,网站可以正常访问,Firewalld日志无报错。)

问题解决!

猜想验证

重启docker服务,看看docker0网桥会不会自动加入到docker zone中。

停止所有容器、重启docker:

docker stop $(docker ps -q)
systemctl restart docker

确实docker0被加进来了,“可能在部署完容器后,也没有重启过docker,所以才一直没有将网卡自动加入到docker zone中吧。”猜想正确 哈哈哈。

其实

其实,我觉得,如果使用的云主机,没有特殊需求,只控制虚机流量的出入控制,完全不用开启Firewalld,直接disable,毛事儿没有,也不用折腾,云平台的安全组和ACL基本可以满足绝大部分需求了。

赞(2) 打赏
未经允许不得转载:万万没想到 » 记录一次本网站数据库连接失败Error establishing a database connection故障排查及解决

评论 抢沙发

评论前必须登录!

立即登录   注册

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

登录

找回密码

注册