Docker 端口映射后外部无法访问的排查与处理
将容器内的服务暴露到宿主机外部时,最常见的做法是做端口映射。例如把容器内的 8080 端口映射到宿主机的 8080 端口:
docker run -d --name web-app -p 8080:80 myimage:latest
如果宿主机上能正常访问 localhost:8080,但外部机器却无法访问,通常可以从以下几个方面排查。
1. 检查 firewalld 是否放行端口
先确认 firewalld 是否在运行:
firewall-cmd --state
如果返回 not running,则不是 firewalld 拦截;如果返回 running,可以查看当前已开放的端口或服务:
firewall-cmd --list-ports
firewall-cmd --list-services
处理方式有两种:
- 直接关闭 firewalld(测试环境可用):
systemctl stop firewalld - 或者放行对应端口并 reload:
firewall-cmd --add-port=8080/tcp --permanentfirewall-cmd --reload
若不加 --permanent,规则重启后将失效,仅适合临时验证。
2. 确认 IP 转发已开启
Docker 依赖宿主机的 IP 转发能力,检查命令如下:
sysctl net.ipv4.ip_forward
若输出为 net.ipv4.ip_forward = 0,需要临时开启:
sysctl -w net.ipv4.ip_forward=1
永久生效可在 /etc/sysctl.conf 中添加:
net.ipv4.ip_forward=1
然后执行 sysctl -p 应用。
3. iptables 规则冲突或丢失
Docker 启动时会自动在 iptables 中插入 DNAT 与 FORWARD 规则。若宿主机的 iptables 服务被其他配置覆盖或链被清空,可能导致外部请求到不了 docker0 网桥。
可以先查看当前 nat 表相关规则:
iptables -t nat -L -n --line-numbers
如果怀疑 iptables 拦截,可临时停止测试:
systemctl stop iptables
若启动容器时遇到如下错误:
iptables: No chain/target/match by that name.
通常是因为 iptables 规则链异常,重启 Docker 服务即可重新创建所需链:
systemctl restart docker
4. CentOS 7 上的特殊处理
在部分 CentOS 7 环境中,Docker 生成的 DNAT 规则看似存在,但外部请求经过 eth0/eth1 转发后无法到达 docker0,或者出现数据包目的 MAC 无法识别的情况。此时可先重启 iptables 服务清空旧规则,再手工添加 SNAT 规则,使来自容器网段(默认 172.17.0.0/16)的流量能够正常伪装为宿主机地址:
systemctl restart iptables
iptables -t nat -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
之后重新启动容器或 Docker,让其重新生成必要的 DNAT 与 FORWARD 规则,外部访问即可恢复。