答案是分层验证:先curl localhost确认容器服务正常,再测局域网访问判断转发层,最后用iptables -t nat -l docker检查链是否存在;若链缺失则firewalld清空了docker规则,导致端口映射失效。

排查 Linux 防火墙(尤其是 firewalld)与 Docker 端口映射冲突,关键不是逐条查规则,而是快速定位“流量在哪一层断掉”。核心思路是分层验证:容器服务是否正常 → 宿主机能否访问 → 局域网能否访问 → iptables 转发链是否存在。
确认容器服务本身是否正常
先排除应用层问题,确保容器内服务已启动并监听正确端口:
- 在宿主机上执行 curl http://localhost:映射端口(如
curl http://localhost:8080) - 若返回预期响应(如 HTML 页面或 API JSON),说明容器运行正常、端口监听无误
- 若失败,检查容器日志:
docker logs 容器名,确认服务是否成功启动、是否绑定到0.0.0.0:80(而非仅127.0.0.1:80)
测试宿主机到容器的端口映射是否生效
验证 Docker 的 iptables nat 规则是否正确写入并生效:
- 运行 iptables -t nat -L DOCKER —— 若提示 No chain/target/match by that name,说明 Docker 自建的转发链已被清空,冲突已发生
- 同时检查 iptables -t nat -L PREROUTING,确认是否有类似
DNAT tcp -- anywhere anywhere tcp dpt:8080 to:172.17.0.2:80的规则 - 没有对应规则,基本可判定 firewalld 重启后抹除了 Docker 的 nat 链
验证防火墙是否放行映射端口
即使 Docker 规则存在,firewalld 仍可能拦截外部请求:
- 运行 firewall-cmd --list-ports 或 firewall-cmd --list-all,查看目标端口(如 8080/tcp)是否在允许列表中
- 注意:Docker 的
-p 8080:80不会自动触发 firewalld 开放端口,必须手动添加:firewall-cmd --permanent --add-port=8080/tcp && firewall-cmd --reload - 若使用了
--zone=public等非默认 zone,需确保该 zone 中包含对应端口和服务
观察 firewalld 重启对 Docker 规则的影响
这是冲突最典型的触发点:
- 执行 systemctl restart firewalld 后,立刻运行
iptables -t nat -L DOCKER - 若链消失,再启动一个新容器(
docker run -d -p 9000:80 nginx),观察 DOCKER 链是否重建 - 若未重建,说明 firewalld 的清空行为覆盖了 Docker 的自动管理机制,需启用兼容模式或切换方案
不复杂但容易忽略:很多问题其实就卡在“firewalld 重启了,但没人告诉 Docker 重装规则”。定位清楚哪一层失效,比盲目删规则更可靠。











