Appearance
容器网络
Docker 网络负责容器之间、容器到宿主机、宿主机到容器、容器到外部的通信。单机 Docker 里最常用的是 bridge 模式,生产上再根据服务需要选用 host、none 或自定义网络。
默认网络和 docker0
安装 Docker 后会有几个内置网络:
bash
docker network ls| 网络 | 驱动 | 说明 |
|---|---|---|
bridge | bridge | 默认桥接网络,不指定网络时容器连到这里 |
host | host | 直接使用宿主机网络栈 |
none | null | 没有网络接口 |
docker0 是宿主机上的一个 Linux bridge,容器通过 veth pair(虚拟网线)接到这个网桥上,再经宿主机转发和 NAT 访问外部网络。
自定义 bridge 网络
默认 bridge 网络上容器之间只能通过 IP 互通,不能用容器名解析。自定义 bridge 网络解决了这个问题:
bash
docker network create app-net
docker run -dit --name app1 --network app-net alpine sh
docker run -dit --name app2 --network app-net alpine sh
docker exec app1 ping -c 3 app2 # 自定义网络内可以用容器名解析实际项目里给每个单机项目建独立网络,不把所有容器堆到默认 bridge。这样排查端口、DNS、容器互通时边界更清楚。
端口映射
容器内服务默认只在容器网络里可见。宿主机或外部要访问容器服务,需要发布端口:
bash
docker run -d \
--name web \
-p 8080:80 \
nginx:1.26| 写法 | 含义 |
|---|---|
-p 8080:80 | 宿主机所有地址的 8080 → 容器 80 |
-p 127.0.0.1:8080:80 | 只允许宿主机本机访问 |
-p 192.168.10.10:8080:80 | 只绑定指定宿主机 IP |
端口映射的链路是:客户端 → 宿主机端口 → Docker NAT 规则 → 容器端口。直接 -p 8080:80 暴露在所有网卡上,公网机器上很容易把不该暴露的服务暴露出去。只给本机代理访问时,绑定 127.0.0.1 更安全。
Docker 和防火墙的关系
Docker 发布端口时会在宿主机 iptables 里写转发规则。表现是宿主机上并没有进程直接监听 8080,但外部访问 宿主机IP:8080 可以转到容器 80。
bash
iptables -t nat -S | grep DOCKER # Docker 写入的 NAT 规则
iptables -S DOCKER-USER 2>/dev/null # Docker 预留的用户自定义过滤入口DOCKER-USER 是 Docker 给用户预留的过滤链,流量进入 Docker 自己的转发规则前会先经过这里。需要限制外部来源访问容器端口时,规则写在这里比直接改 Docker 自动生成的链更稳——Docker 重启不会覆盖 DOCKER-USER。
示例:只允许管理网段访问已发布的容器端口:
bash
iptables -I DOCKER-USER -s 192.168.10.0/24 -j RETURN
iptables -A DOCKER-USER -j DROP在 ufw 的 Ubuntu 上,Docker 发布端口可能绕过普通 ufw 入站规则。公网机器上遇到"ufw 没放行但容器端口能访问"时,原因是 Docker 的 NAT 规则在 ufw 之前生效。排查方向优先看 Docker NAT 规则和 DOCKER-USER。
firewalld、ufw、iptables-nft 混用时,表面上命令都能执行,实际生效顺序可能和预期不同——这是网络排错里容易绕进去的地方。
容器访问宿主机
Linux 上容器访问宿主机服务,常见方式:
| 方式 | 说明 |
|---|---|
| 网桥网关 IP | 默认 bridge 通常是 172.17.0.1 |
host.docker.internal | 用 --add-host 显式添加 |
| host 网络 | 容器直接使用宿主机网络 |
bash
docker run --rm \
--add-host host.docker.internal=host-gateway \
curlimages/curl:8.8.0 \
curl -I http://host.docker.internal:8080host-gateway 会把宿主机网关地址写进容器 /etc/hosts,本地调试很方便。生产里要确认应用为什么需要反向访问宿主机,避免把服务依赖关系绕得太隐蔽。
host 和 none 模式
host 模式下容器直接使用宿主机网络,没有独立网络命名空间:
bash
docker run --rm --network host nginx:1.26它少了一层 NAT 和端口映射,网络性能更好,但容器进程直接占用宿主机端口,隔离更弱。适合对网络性能、多端口监听有特殊要求的服务。普通 Web/API 服务用 bridge 加端口映射更清楚。
none 模式下容器只有 loopback,没有外部网络:
bash
docker run --rm --network none alpine ip addr适合离线任务、只读文件处理、构建任务——不需要外部网络时,none 模式能减少不必要的网络暴露面。
自定义网段和网段冲突
默认 Docker 网段可能和公司内网、VPN、K8s Pod 网段冲突。创建网络时可以指定网段:
bash
docker network create \
--subnet 172.30.10.0/24 \
--gateway 172.30.10.1 \
app-net网段冲突的表现是容器能访问部分地址,部分地址路由异常。VPN、办公网、K8s Pod 网段、Docker 网段最好统一记录,不然排查网络问题会很绕。
常见排查
bash
docker network ls
docker network inspect app-net
docker port web
docker inspect web --format '{{json .NetworkSettings.Ports}}'
ss -lntp | grep 8080 # 宿主机上确认端口到底由谁监听
iptables -t nat -S | grep DOCKER # 端口映射对应的 NAT 规则| 现象 | 检查方向 |
|---|---|
| 容器访问不了外网 | DNS、默认路由、宿主机 ip_forward、防火墙 |
| 外部访问不了容器 | -p 映射、监听地址、防火墙、安全组 |
| 容器之间不通 | 是否在同一网络、容器名解析、应用监听地址 |
| 端口冲突 | 宿主机端口是否已被占用 |
| 访问到了旧容器 | 端口映射、反向代理 upstream、DNS 缓存 |
| 防火墙没放行但端口可访问 | Docker NAT 规则、DOCKER-USER、firewalld/ufw 生效顺序 |
容器网络故障里,核心是先确认三件事:容器内服务是否在监听、宿主机端口是否映射、流量有没有实际到容器。三件事分开看,比盯着应用日志猜要稳。