根本问题是firewalld与docker共用iptables且不协同:firewalld重启会清空DOCKER等链,导致端口映射失效,表现为本地可访问但外部连接超时;推荐方案是启用docker zone迁移docker0接口并开启masquerade,或配置docker禁用iptables交由firewalld统一管控。

根本问题是 firewalld 和 docker 都在操作 iptables 的 nat 和 filter 表,但彼此不协同。firewalld 重启时会清空非自身管理的链(比如 DOCKER、DOCKER-USER),而 docker 依赖这些链做端口映射和地址转发,结果就是 外部无法访问映射端口,但宿主机 curl localhost 却正常。
确认是否为典型冲突现象
执行以下检查快速定位:
- 在宿主机运行
curl http://localhost:映射端口—— 若成功,说明容器服务本身正常 - 从另一台机器或本机局域网 IP 访问
http://[宿主机IP]:映射端口—— 若超时或拒绝连接,基本可判定是网络转发层被阻断 - 检查关键 iptables 链是否存在:
iptables -t nat -L DOCKER,若提示No chain/target/match by that name,说明 docker 规则已被 firewalld 清除
推荐优先尝试的稳定方案:启用 docker zone 并迁移接口
适用于 Docker ≥ 20.10.0 + firewalld 默认配置的环境(CentOS 7/8、RHEL 8+、Fedora 等):
- 将 docker0 网桥接口从默认 public zone 移入专用 docker zone:
firewall-cmd --permanent --zone=docker --add-interface=docker0 - 确保该 zone 允许 masquerade(地址伪装,用于容器出向流量):
firewall-cmd --permanent --zone=docker --add-masquerade - 重载配置:
firewall-cmd --reload - 验证:
firewall-cmd --get-active-zones应显示 docker 区域及 docker0 接口
兼容性更强的方案:禁用 docker 的 iptables 管理
让 firewalld 完全接管 iptables,docker 只负责容器内网络,不干预宿主机防火墙规则:
- 编辑
/etc/docker/daemon.json(如不存在则新建),加入:{"iptables": false} - 重启 docker:
systemctl restart docker - 开启 firewalld 的地址伪装支持(必须):
firewall-cmd --add-masquerade --permanent && firewall-cmd --reload - 手动开放所需端口(例如 8080):
firewall-cmd --add-port=8080/tcp --permanent && firewall-cmd --reload
临时应急与验证技巧
当问题突发且需快速恢复时,可按顺序执行:
- 先重启 firewalld:
systemctl restart firewalld - 再重启 docker:
systemctl restart docker - 重新运行容器(旧容器的端口映射可能已失效,需重建)
- 验证 iptables nat 表中是否重建了 DOCKER 链:
iptables -t nat -nL | grep -A 5 "Chain DOCKER"
实际部署中,禁用 docker iptables 管理 + firewall-cmd 开放端口 是最可控、最易审计的方式;而启用 docker zone 更贴近 firewalld 原生设计,适合长期运维。两种都不需要停用任一服务,也不依赖重启服务器。


















