环境: Rocky 8.6
(CentOS 7
)、firewalld
、Docker
PS: 如果防火墙关闭的话,或许一直都不会遇到该问题吧,又掉了一撮头发。
当且仅当需要占用服务器的端口时才会报错,如果不需要映射端口,也不会遇到相应的问题。
比如:docker run -d --name nginx-test1 nginx
这种的没有映射端口docker run -d --name nginx-test1 -p 80:80 nginx
映射端口了,就需要操作防火墙(若开启)。
1. 场景
因为服务器上的一个服务需要暴露端口,所以对防火墙进行过操作,并重启了防火墙;然后导致 Docker
上跑的服务都无法正常使用。
当执行 docker run xxx
和 docker start xxxx
的时候会报下面的错误:
docker: Error response from daemon: driver failed programming external connectivity
on endpoint xxxx(d3e43fa36d34987312e2c3ffd30d3ce3d1892d43ef951241fc2ae320ffeb1330):
(iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 9905 -j DNAT
--to-destination 172.18.0.2:9005 ! -i docker0: iptables: No chain/target/match by that name.
(exit status 1)).
2. 原因
Docker
与iptables
的关系请参考官方文档: https://docs.docker.com/network/iptables/
docker
服务启动的时候,docker
服务会自动向 iptables
注册名为 DOCKER-USER
和 DOCKER
两个链,以便让 docker
服务管理的 容器(containner)
所暴露的端口之间进行通信。
当防火墙 firewalld
重启的时候会导致该链丢失,当使用 docker run
的的时候就会出现上面的报错。
3. 解决方案
3.1 Docker 重启(推荐)
这种方式是最简单粗暴的, 因为 Docker
启动的时候会自动注册。是不是很 nice!!!
systemctl restart docker
# 或
service docker restart
【注】设置了 --restart=always
参数的容器当 Docker 将会自动启动,如果没有设置就需要手动重启了。
如果想对某个容器设置自动启动,可以通过下面的命令进行设置:
# 更新已有的容器:xxx 为容器的标识或容器的名称
docker container update --restart=always xxxx
# 启动时设置
docker run -d --name nginx-test1 -p 80:80 --restart=always nginx
3.2 恢复 iptables 规则(不推荐)
这种方式其实就是通过 iptables-save
命令备份防火墙的规则,然后通过 iptables-restore
进行恢复;但是在实践的过程中发现并不是很实用。
- 当
iptables
中没有Docker
两个链的时候,那么所有服务所暴露的端口,就不会生效,服务是中断的(这个时候还不如直接重启)。 - 即使备份了,如果
Docker
暴露服务的有变动,还需要手动去处理差异,也很麻烦。 - 如果完全没有备份,手动添加对应的链,如果
Docker
运行了很多服务,添加起来也是很费劲的(还是不折腾了) - 如果定期备份的话,倒是可以只用这种方式(但是既然服务都已经中断了,还不如直接重启)。
一个 iptables
规则的的复杂度,直接劝退:
# Generated by iptables-save v1.8.4 on Thu Jan 26 14:58:33 2023
*filter
:INPUT ACCEPT [105973064:35160153136]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [96468849:80475545565]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.18.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8805 -j ACCEPT
-A DOCKER -d 172.18.0.3/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8801 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Thu Jan 26 14:58:33 2023
# Generated by iptables-save v1.8.4 on Thu Jan 26 14:58:33 2023
*security
:INPUT ACCEPT [105973069:35160156762]
:FORWARD ACCEPT [11122602:8643145221]
:OUTPUT ACCEPT [96468861:80475547136]
COMMIT
# Completed on Thu Jan 26 14:58:33 2023
# Generated by iptables-save v1.8.4 on Thu Jan 26 14:58:33 2023
*raw
:PREROUTING ACCEPT [117095673:43803302209]
:OUTPUT ACCEPT [96468861:80475547136]
COMMIT
# Completed on Thu Jan 26 14:58:33 2023
# Generated by iptables-save v1.8.4 on Thu Jan 26 14:58:33 2023
*mangle
:PREROUTING ACCEPT [117095673:43803302209]
:INPUT ACCEPT [105973071:35160156988]
:FORWARD ACCEPT [11122602:8643145221]
:OUTPUT ACCEPT [96468861:80475547136]
:POSTROUTING ACCEPT [107591469:89118692771]
COMMIT
# Completed on Thu Jan 26 14:58:33 2023
# Generated by iptables-save v1.8.4 on Thu Jan 26 14:58:33 2023
*nat
:PREROUTING ACCEPT [288081:17293388]
:INPUT ACCEPT [287965:17286375]
:POSTROUTING ACCEPT [1756221:105814926]
:OUTPUT ACCEPT [1756221:105814926]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.18.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.18.0.2/32 -d 172.18.0.2/32 -p tcp -m tcp --dport 8805 -j MASQUERADE
-A POSTROUTING -s 172.18.0.3/32 -d 172.18.0.3/32 -p tcp -m tcp --dport 8801 -j MASQUERADE
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8805 -j DNAT --to-destination 172.18.0.2:8805
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8801 -j DNAT --to-destination 172.18.0.3:8801
COMMIT
# Completed on Thu Jan 26 14:58:33 2023