添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

二、问题排查

碰到这个问题我第一反应就是问组里的人,是不是有人重启过CentOS 7 自己的firewallD了。

因为这台服务器是我配置的,防火墙虽然开着但我已经开启端口访问了,所以肯定不是因为防火墙阻断连接的缘故。但由于这篇文章是篇踩坑排查文档,所以还是把这种情况写出来了

情况一:开着防火墙但没有开放端口

CentOS 7自带并启用了防火墙FirewallD,我们可以通过下面的命令检查FirewallD的状态:

如果只是临时打开端口,去掉第一行命令中的“--permanent”参数,那么当再次重启FirewallD服务时,本策略将失效。

情况二:人为重启CentOS 7的FirewallD服务

FirewallD是CentOS系统在7版本引入的新组件,简单的说就是iptables的包装,用于简化防火墙相关的设置。

然而FirewallD和Docker相处的并不是特别好,当FirewallD启动(或重新启动)时,会从iptables中删除DOCKER链,造成Docker不能正常工作:

FirewallD

CentOS-7 introduced firewalld, which is a wrapper around iptables and can conflict with Docker.

When firewalld is started or restarted it will remove the DOCKER chain from iptables, preventing Docker from working properly.

When using Systemd, firewalld is started before Docker, but if you start or restart firewalld after Docker, you will have to restart the Docker daemon.

摘自Docker官方文档《 CentOS - Docker Documentation

在CentOS 7中,如果设置使用systemd开机自启动Docker服务是不会有问题的,因为Docker在systemd配置文件中明确注明了“After= firewalld.service”,以保证Docker daemon 在FirewallD启动后再启动。

(Docker:惹不起我还躲不起吗)

但每当用户手动重启过FirewallD服务之后,FirewallD服务会将Docker daemon写入iptables的DOCKER链删除,所以需要手动重新启动一次Docker daemon服务,让Docker daemon服务重建DOCKER链。

不过问了组里另外两个研发,都说没有动过。查看了shell的history也没找到对应的记录。

这就很奇怪了。不过经过一段时间的蹲点排查之后,我终于发现了一个新的原因:

情况三:没有启用IP_FORWARD

因为一直没法定位出问题的所在,所以我们研发组都是发现不能正常访问仓库时,手动登陆宿主机重启Docker daemon服务。

在有一次登录到宿主服务器上准备重启Docker daemon服务前,我突然想起之前在用Docker的时候还碰到过另一个问题:如果宿主机没有启用IP_FORWARD功能,那Docker容器在启动时会输出一条警告消息:

WARNING: IPv4 forwarding is disabled. Networking will not work.

并且将不能在启动的容器中访问外部网络,容器对外暴露的端口外部也不能正常访问:

会不会是因为宿主机的IP_FORWARD功能没有启用所以才引起的这个故障呢?

果然,输出表示当前系统的IP_FORWARD功能处于停用状态!

可是问题来了,当时启动容器的时候都是好的啊,什么都没有输出,怎么用着用着IP_FORWARD功能就被禁用了呢?

等等,Docker daemon服务在启动的时候会自动设置iptables设置,难不成它还会检查IP_FORWARD设置,并帮我临时启用吗?

带着这个假设,我手动重启了一下Docker daemon服务:

果然,Docker daemon服务在启动过程中会检查系统的IP_FORWARD配置项,如果当前系统的IP_FORWARD功能处于停用状态,会帮我们临时启用IP_FORWARD功能,然而临时启用的IP_FORWARD功能会因为其他各种各样的原因失效…

虽然具体造成本次故障的原因现在还没有确凿的证据定位出,但我现在严重怀疑是因为重启网络服务造成的。因为出问题的服务器宿主机上运行着我们研发组正在开发的Web项目,其中有一个功能是修改网卡IP地址,这个功能在修改完网卡IP后,会自动调用下面的命令重启网络服务:

Docker daemon服务在启动的时候会帮帮我们调整很多的配置项,比如这次出事儿的IP_FORWARD配置。

Docker daemon启用IP_FORWARD功能是因为Docker容器默认的网络模式(bridge/网桥模式)会给每个容器分配一个私有IP,如果容器需要和外部通信,就需要使用到NAT。NAT需要IP_FORWARD功能支持,否则无法使用。这也解释了为什么会出现在IP_FORWARD功能停用的情况下,使用bridge模式的容器内外均无法访问的情况。

只是在Linux下,出于安全考虑,默认是停用IP_FORWARD功能的,Docker daemon服务在启动时会检查IP_FORWARD功能是否已经启用,如果没有启用的话,Docker daemon会 悄无声息 临时启用 此功能,然而临时启用的IP_FORWARD功能并不能持久化,会因为其他命令的干扰导致失效。

不过这次的事情告诉了我一个小道理:当出现问题的时候,不要慌,要结合经验大胆的做出假设并验证,治标治本。

2018年11月5日 22:42:26