
Docker 网络是新手最容易懵的部分报错又特别分散容器里 ping baidu.com 不通、应用连宿主机上的 MySQL 报 Connection refused、明明 -p 8080:80 了浏览器却打不开。这三个问题看起来不相干其实都落在 Docker 网络模型上。这篇把容器网络最高频的三个坑拆开连不上外网、容器访问宿主机服务、端口映射不生效每个都给出现象、根因和可复制的解法。先建立最小网络模型理解这三个坑只需要记住三点容器默认在bridge 网络里有自己的虚拟网卡和独立 IP如 172.17.0.x跟宿主机不是同一个网络栈容器访问外网靠NAT宿主机做地址转换访问宿主机本身不能写 localhost容器里的 localhost 是容器自己端口映射 -p 是靠宿主机上的iptables / 端口监听把流量转发进容器带着这三点看下面的坑就清楚了。坑一容器连不上外网现象docker run --rm alpine ping -c 2 baidu.com # ping: bad address baidu.com ← DNS 解析失败 docker run --rm alpine ping -c 2 8.8.8.8 # 通 / 不通 两种情况都有分两种情况排查情况 A域名解析失败但 IP 能 ping 通→ DNS 问题。容器默认用 Docker 内置 DNS127.0.0.11它会把请求转发到宿主机 /etc/resolv.conf 里的 DNS。如果宿主机 DNS 配置异常比如用了内网 DNS 但容器不在内网解析就失败。解法一给容器指定 DNSdocker run --rm --dns 223.5.5.5 --dns 114.114.114.114 alpine ping -c 2 baidu.com解法二daemon.json 全局配 DNS{ dns: [223.5.5.5, 114.114.114.114] }改完 systemctl restart docker。情况 BIP 也 ping 不通→ 路由 / 转发 / 防火墙问题。依次检查# 1. 宿主机 IP 转发是否开启Docker 依赖它做 NAT sysctl net.ipv4.ip_forward # 期望net.ipv4.ip_forward 1 # 如果是 0开启 sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward1 /etc/sysctl.conf # 2. iptables 的 FORWARD 链是否被设成 DROP某些安全加固脚本会改 iptables -L FORWARD | head # 如果 policy 是 DROP 且没有 Docker 的规则容器出网会被拦 # 3. 云主机安全组 / 防火墙是否放行 # 阿里云/腾讯云的安全组、firewalld、ufw 都可能拦一个高频场景服务器装了 firewalld 或者做了安全加固把 iptables 的 FORWARD 默认策略改成了 DROPDocker 启动时插入的规则被覆盖容器就出不了网。重启 Docker 通常能重新插入规则sudo systemctl restart docker如果还不行检查是否有人把 iptablesfalse 写进了 daemon.json这会让 Docker 不管理 iptablesNAT 失效cat /etc/docker/daemon.json | grep iptables # 如果有 iptables: false删掉或改 true再重启坑二容器访问不了宿主机上的服务现象宿主机上跑着 MySQL3306容器里的应用配置连 127.0.0.1:3306 或 localhost:3306报 Connection refused。根因容器里的 localhost 指的是容器自己不是宿主机。容器和宿主机是两个网络命名空间。三种解法解法一用宿主机内网 IP最通用# 宿主机上查内网 IP hostname -I # 192.168.1.100 # 容器里连这个 IP docker run -d -e DB_HOST192.168.1.100 myapp:1.0解法二用 host.docker.internalDocker Desktop 原生支持Linux 需手动加Windows / macOS 的 Docker Desktop 里容器可以直接用 host.docker.internal 指代宿主机docker run -d -e DB_HOSThost.docker.internal myapp:1.0Linux 上默认没有这个域名需要在 run 时手动加 --add-hostdocker run -d \ --add-hosthost.docker.internal:host-gateway \ -e DB_HOSThost.docker.internal \ myapp:1.0host-gateway 是个特殊值Docker 会把它解析成宿主机 IP。Compose 里services: app: image: myapp:1.0 extra_hosts: - host.docker.internal:host-gateway environment: - DB_HOSThost.docker.internal解法三host 网络模式容器直接用宿主机网络栈docker run -d --network host myapp:1.0此时容器里 localhost 就是宿主机-p 端口映射也不需要了容器端口直接占用宿主机端口。坑host 模式牺牲了网络隔离容器端口直接暴露在宿主机上多容器可能端口冲突。生产环境慎用开发图方便可以用。另一个隐蔽前提宿主机上的服务必须监听在 0.0.0.0 而不是 127.0.0.1。很多服务默认只 bind 127.0.0.1只接受本机回环连接这种情况下即使容器连宿主机内网 IP 也会被拒。检查ss -tlnp | grep 3306 # LISTEN 0.0.0.0:3306 ← 可以容器能连 # LISTEN 127.0.0.1:3306 ← 不行只接受宿主机本机连接如果是 127.0.0.1改服务配置让它监听 0.0.0.0注意同时做好防火墙/安全组避免暴露公网。坑三端口映射 -p 不生效现象docker run -d -p 8080:80 nginx 跑起来了但浏览器访问 http://宿主机IP:8080 打不开。按顺序排查1. 确认容器真的在监听。进容器看服务起没起docker exec -it 容器 sh # 容器内测试本机端口 wget -qO- http://127.0.0.1:80 || curl http://127.0.0.1:80容器内都不通是应用没起来或监听端口不对比如应用监听 3000 你却映射 80跟 -p 无关。2. 确认映射方向没写反。-p 8080:80 宿主机 8080 → 容器 80。访问要用宿主机端口8080不是 80。用 docker port 核对docker port 容器 # 80/tcp - 0.0.0.0:80803. 确认宿主机端口没被占 / 没被防火墙拦ss -tlnp | grep 8080 # 宿主机上 8080 是否在监听Docker 会监听 # 云主机检查安全组是否放行 8080 # 本机防火墙 sudo firewall-cmd --list-ports # firewalld sudo ufw status # ufw4. 确认 iptables 没被禁用。同坑一如果 daemon.json 里有 iptables: falseDocker 不写 NAT/转发规则-p 会失效容器能跑但端口不通。删掉该配置重启 Docker。5. 绑定地址问题。-p 8080:80 默认绑 0.0.0.0所有网卡。如果写成 -p 127.0.0.1:8080:80就只监听宿主机回环外部机器访问不了只能宿主机本机访问。想让外部访问要么去掉 IP 前缀要么绑具体内网 IP。6. IPv6 / 双栈干扰。少数环境宿主机优先解析 IPv6 而 Docker 只监听 IPv4导致 localhost:8080 连不上但 127.0.0.1:8080 能连。测试时直接用 127.0.0.1 排除 IPv6 干扰。容器之间互通别用默认 bridge顺带讲一个相关高频问题两个容器想互相访问用默认 bridge 网络时不能按容器名解析只能靠 IP而 IP 重启会变。正确做法是自建网络docker network create mynet docker run -d --name mysql --network mynet mysql:8.4 docker run -d --name app --network mynet -e DB_HOSTmysql myapp:1.0同一自定义网络内容器名就是主机名内置 DNS 解析app 里直接连 mysql:3306 即可重启 IP 变了也不影响。这是取代已废弃 --link 的现代做法。一张排查决策表现象优先怀疑第一条命令容器 ping 域名不通、ping IP 通DNSdocker run --rm --dns 223.5.5.5 alpine nslookup baidu.com容器 ping IP 也不通转发/防火墙/iptablessysctl net.ipv4.ip_forward容器连宿主机服务 refusedlocalhost 误区 / 服务只 bind 127.0.0.1ss -tlnp | grep 端口-p 映射外部访问不了安全组/防火墙/iptablesfalse/绑定地址docker port 容器 ss -tlnp容器间按名字连不上用了默认 bridgedocker network create 自建网络小结容器网络三个高频坑的根因都回到最小模型容器是独立网络命名空间出网靠 NAT访问宿主机不能写 localhost端口映射靠 iptables 转发。连不上外网先分 DNS 还是路由DNS 用 --dns 或 daemon.json路由查 ip_forward 和 iptables FORWARD访问宿主机别写 localhost用内网 IP / host.docker.internal(host-gateway) / host 模式并确认服务监听 0.0.0.0端口不生效核对映射方向、容器内是否真监听、安全组防火墙、iptables 是否被禁、绑定地址容器互联自建 network用容器名互访排查时按决策表从上往下走基本十分钟内能定位。