Centos7 中 firewalld导致docker网络异常


现象

宿主机访问docker中的服务时,时而正常,时而超时

排查工具:

1
httping http://kess-uat_host/WebServiceProxy/ProxyService

Centos7 自带防火墙是firewalld。在某下情况下可能导致docker 的某些网络问题。

docker 有4种网络模式:

  1. bridge模式(默认):网桥模式,通过虚拟网桥使容器通信。容器有自己的独立ip和端口。
  2. host模式:主机模式,与主机共用一个网络,容器ip是主机的ip,端口占用主机的端口范围。
  3. container模式:与指定容器共享一个网络,类似host模式,但是是两个容器间共用一个ip。
  4. none模式:无网络模式,容器有自己的内部网络,但是没有分配ip,路由等信息,需要自己分配。

默认是bridge 网桥模式,docker会在宿住机配置一个虚拟网卡,并将容器连接到该网卡,而docker网络与宿住机外部网络的通信,是借助nat来实现的。所以当Iptable出现问题时,就会导致docker容器网络异常

查看firewalld 日志

1
tail -10 /var/log/firewalld

在日志中可以看到一些警告信息,是docker添加的nat规则,但是因为chain不存在,所以添加失败。一般情况下是没有什么问题,但是某些情况,比如容器内需要访问宿住机的服务,则可能出现问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -D PREROUTING' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -D OUTPUT' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -F DOCKER' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -X DOCKER' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -F DOCKER' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -X DOCKER' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -F DOCKER-ISOLATION' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -X DOCKER-ISOLATION' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -n -L DOCKER' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -n -L DOCKER' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -n -L DOCKER-ISOLATION' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -C DOCKER-ISOLATION -j RETURN' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -C POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -C DOCKER -i docker0 -j RETURN' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -D FORWARD -i docker0 -o docker0 -j DROP' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -C FORWARD -i docker0 -o docker0 -j ACCEPT' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -C FORWARD -i docker0 ! -o docker0 -j ACCEPT' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -C FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT' failed: iptables: Bad rule (does a matching rule exist in that chain?).
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -C PREROUTING -m addrtype --dst-type LOCAL -j DOCKER' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t nat -C OUTPUT -m addrtype --dst-type LOCAL -j DOCKER ! --dst 127.0.0.0/8' failed: iptables: No chain/target/match by that name.
WARNING: COMMAND_FAILED: '/usr/sbin/iptables -w2 -t filter -C FORWARD -o docker0 -j DOCKER' failed: iptables: No chain/target/match by that name.

解决方案

1. 修改docker网络模式为host

在运行容器时添加参数 –net=host,但是不能从根本上解决问题。

2. 将firewalld换成iptables(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#查看firewalld是否启用
systemctl status firewalld
#停止firewalld
systemctl stop firewalld
#禁用firewalld(否则重启系统后会再次启动)
systemctl disable firewalld
#查看是否安装iptables
yum list installed | grep iptables-services
#如果没安装则安装下
yum install iptables-services -y
#重启iptables
systemctl restart iptables
#设置开机自启
systemctl enable iptables
#重启docker
systemctl restart docker

3. 关闭防火墙

不推荐,特别是在生产环境

1
2
3
4
5
6
#查看firewalld是否启用
systemctl status firewalld
#停止firewalld
systemctl stop firewalld
#禁用firewalld(否则重启系统后会再次启动)
systemctl disable firewalld