Docker 容器明明已经通过 -p 发布端口,外部访问却超时,或者重启防火墙后映射突然失效,问题通常不只在容器本身,还可能涉及宿主机监听地址、IP 转发、iptables NAT 链、FORWARD 策略及防火墙管理工具之间的冲突。本文提供一套由内到外的排查流程,帮助快速锁定故障点。🔍
一、先确认故障发生在哪一层
排查端口映射时,不要一开始就清空 iptables。建议先判断应用、容器网络、宿主机端口和外部链路中,究竟是哪一层出现异常。
- 进入容器,确认应用进程正在运行,并监听正确端口。
- 在宿主机访问容器 IP 与容器端口,验证容器内部服务是否可达。
- 在宿主机访问映射后的本地端口,检查 DNAT 是否生效。
- 从另一台机器访问宿主机 IP 与发布端口,验证外部流量是否被拦截。
例如容器发布参数为 -p 8080:80,应依次检查容器的 80 端口、宿主机的 8080 端口以及外部到 8080 的访问。Docker 会通过宿主机防火墙规则完成 NAT、端口转换和地址伪装,相关原理可参考 Docker 端口发布文档。
二、检查端口映射与监听地址
先执行 docker ps 或 docker inspect 容器名,确认实际映射是否符合预期。若结果显示 127.0.0.1:8080->80/tcp,意味着该端口仅绑定本机回环地址,远程设备无法直接访问;需要对外提供服务时,应绑定合适的宿主机地址。
还要确认容器中的应用不是只监听 127.0.0.1。如果应用仅监听容器内部回环地址,即使 Docker 已创建映射,进入容器网络命名空间的请求仍无法被服务接收。通常应让应用监听 0.0.0.0 或容器网卡地址。⚠️
三、核对 NAT 表中的 Docker 规则
执行 iptables -t nat -L -n -v --line-numbers,重点查看 PREROUTING、OUTPUT、POSTROUTING 和 DOCKER 链。正常情况下,Docker 会在 nat 表创建 DOCKER 链,并添加用于端口映射与 masquerading 的规则,具体链路说明可查阅 Docker 与 iptables 官方说明。
- 如果 DOCKER 链不存在,可能是 Docker 未接管 iptables、守护进程启动异常,或规则被其他服务清除。
- 如果存在 DNAT 规则但计数始终为零,流量可能没有到达对应网卡,或者目标 IP、协议及端口不匹配。
- 如果 DNAT 计数增长但容器无响应,应继续检查 FORWARD 链、容器路由和应用监听状态。
- 如果重启 Docker 后规则恢复,通常说明原有规则曾被防火墙重载、运维脚本或网络管理程序覆盖。
提示:诊断前可使用 iptables-save 保存当前规则。不要在远程服务器上贸然执行 iptables -F 或清空 nat 表,否则可能同时中断 SSH、容器网络和其他转发业务。
四、检查 FORWARD 策略与 IP 转发
NAT 规则负责修改目标地址,但数据包是否能继续进入容器网络,还取决于转发链。执行 iptables -L FORWARD -n -v --line-numbers,观察 FORWARD 默认策略、Docker 跳转链及命中计数。如果默认策略为 DROP,而 Docker 所需的放行规则缺失,端口映射就可能表现为连接超时。
同时执行 sysctl net.ipv4.ip_forward。返回值应结合实际网络模式判断;默认 bridge 网络依赖宿主机转发能力。若临时修改后恢复正常,还应检查 /etc/sysctl.conf 和 /etc/sysctl.d/ 下的持久化配置,防止服务器重启后再次失效。
自定义规则应放在哪里
需要限制容器入口流量时,优先使用 DOCKER-USER 链,而不是直接修改 Docker 自动维护的 DOCKER 链。Docker 会在 FORWARD 流程中优先处理相关自定义链;直接编辑自动生成的规则,可能在容器重建或 Docker 重启后丢失。🛡️
五、排查 firewalld、nftables 与规则后端冲突
现代 Linux 发行版可能同时存在 firewalld、nftables 以及 iptables 兼容层。执行 iptables --version,可以查看当前使用的是 legacy 还是 nf_tables 后端。如果 Docker 写入一套后端,而管理员查看或维护的是另一套后端,就会出现“规则看似不存在”或“修改后没有效果”的错觉。
若问题总在执行 firewall-cmd --reload 后出现,应检查 firewalld 是否重建规则集,以及 Docker 规则是否被完整保留。处理重点是统一防火墙管理方式,而不是反复手工补写 DNAT。对于 nftables 环境,也应确认实际活动规则集与 iptables 命令所展示的内容一致。
六、确认 Docker 守护进程没有禁用 iptables
检查 Docker 的 daemon 配置及启动参数,关注是否设置了 iptables=false 或 ip6tables=false。禁用后,Docker 不会自动创建桥接网络所需的多数防火墙规则,端口发布和容器外网访问可能因此失效。官方不建议普通场景关闭该功能,因为这通常需要管理员自行维护完整的 NAT 与转发规则。
修改守护进程配置后,应先验证配置格式,再在维护窗口重启 Docker。重启前需要评估运行中容器、连接状态以及业务恢复机制,避免将排障操作扩大为服务中断。
七、使用抓包和计数器定位断点
当规则表面正常时,可以使用 tcpdump 分别监听外部网卡、docker0 或自定义网桥。若外部网卡能看到 SYN 包,而容器网桥看不到,问题多半位于 PREROUTING、DNAT 或 FORWARD;若网桥可以看到请求,却没有响应,应检查容器应用、回程路由和连接跟踪状态。
iptables 的数据包计数同样重要。持续发起测试请求,再观察相关规则计数是否增长,比只阅读规则文本更容易确认数据包实际经过了哪条链。必要时可查看 conntrack 状态,但生产环境不应随意清空连接跟踪表。📡
八、推荐的恢复顺序
- 保存当前 iptables 与 nftables 规则,保留故障现场。
- 验证容器进程、监听地址和容器内部访问。
- 确认 Docker 端口发布参数及宿主机端口未冲突。
- 检查 NAT 表中的 DOCKER 链和对应 DNAT 规则。
- 检查 FORWARD 链、DOCKER-USER 链与 IP 转发。
- 确认 firewalld、nftables 和 iptables 后端没有冲突。
- 在评估影响后重启单个容器或 Docker 服务,并对比规则变化。
- 修复持久化配置,最后从本机和远程分别复测。
总结
Docker 端口映射失效,本质上需要沿着“应用监听、容器网络、端口发布、NAT 转换、FORWARD 放行、宿主机防火墙、外部链路”逐层检查。最常见的方向包括监听地址错误、DOCKER 链缺失、FORWARD 拒绝、IP 转发关闭、防火墙重载覆盖规则,以及 iptables 与 nftables 后端不一致。坚持先保存现场、再观察计数、最后修改配置,通常能更安全地找出真正原因,并避免同类故障反复出现。✅