跳到主要内容

网络模式与跨容器通信

1. 网络驱动概览

驱动用途
bridge默认,单机虚拟网桥
host共享宿主网络栈,无隔离
none完全无网络
overlay跨主机(Swarm / K8s 用)
macvlan容器有独立 MAC,像物理机
ipvlan类似 macvlan 但用 IP

99% 场景用 bridge(自定义 bridge)和 host

2. bridge(默认)

启动 docker daemon 时自动建 docker0 网桥(172.17.0.1)。容器加入网桥获得 172.17.0.x IP。

docker network ls
# bridge bridge local
# host host local
# none null local

docker network inspect bridge
# 看子网、网关、连接的容器

2.1 默认 bridge 的局限

  • 容器间只能通过 IP 通信,没自动 DNS
  • 不能动态加减容器(要用 --link,已 deprecated)

生产/开发都应该用自定义 bridge

docker network create mynet
docker run --network mynet --name web myapp
docker run --network mynet --name db postgres
# web 容器可以 ping db(通过容器名 DNS)

compose 自动给每个项目创建一个自定义 bridge,所以服务名直接当 DNS 用。

3. 端口映射

docker run -p 3000:3000 myapp # 宿主 3000 → 容器 3000
docker run -p 127.0.0.1:3000:3000 myapp # 只在本机访问
docker run -p 3000-3010:3000-3010 myapp # 端口范围
docker run -P myapp # 自动分配(看 EXPOSE)

底层是 iptables NAT 规则,看:

sudo iptables -t nat -L DOCKER -n

3.1 容器内监听 0.0.0.0

容器内服务必须监听 0.0.0.0(所有网卡),不能 127.0.0.1

// ✗ 容器外连不上
app.listen(3000, '127.0.0.1')

// ✓
app.listen(3000, '0.0.0.0')
// 或不指定(默认 0.0.0.0)
app.listen(3000)

4. host 模式

docker run --network host myapp

容器和宿主共享网络栈。优点:

  • 性能最高(无 NAT)
  • 不需要端口映射

缺点:

  • 没隔离,端口冲突
  • 不能多实例

适合:高性能要求、需要直接抓宿主网卡的场景(监控代理、网络工具)。

macOS / Windows 上 host 模式不真的"共享"宿主(Docker Desktop 用 VM),效果有限。

5. none 模式

docker run --network none myapp

容器无网络。适合纯计算任务、安全沙箱。

6. 跨主机:overlay

Docker Swarm / K8s 用。VXLAN 隧道把多台机器的容器连成一个虚拟网络。前端基本不直接配,K8s 用 CNI 插件(Calico、Flannel、Cilium)实现。

7. DNS 解析

容器内 /etc/resolv.conf 默认指向 docker daemon 内嵌 DNS(127.0.0.11)。docker DNS:

  1. 先查同网络的容器名
  2. 再转发到宿主配置的 DNS
# 容器内
nslookup db # 同网络容器名
nslookup google.com # 外网

# 自定义 DNS
docker run --dns 1.1.1.1 myapp

8. 容器互联实战

8.1 同 compose 项目

services:
web:
image: myweb
api:
image: myapi
# web 容器内 fetch('http://api:3000') 通

8.2 跨 compose 项目

A 项目用 B 项目的网络:

# A/compose.yaml
services:
myapp:
networks:
- shared
networks:
shared:
external: true
name: shared_net

# B/compose.yaml
networks:
default:
name: shared_net

或显式建外部网络:

docker network create shared_net

两个 compose 项目都用 shared_net

8.3 容器访问宿主机

宿主机服务(如本地 DB)容器内怎么访问?

  • macOS / Windows:host.docker.internal
  • Linux:默认无此别名,加 --add-host=host.docker.internal:host-gateway(20.10+)
services:
web:
extra_hosts:
- "host.docker.internal:host-gateway"

9. 网络故障排查

9.1 容器互通不了

# 1. 看是不是同网络
docker inspect web | jq '.[0].NetworkSettings.Networks'
docker inspect db | jq '.[0].NetworkSettings.Networks'

# 2. 容器内 ping
docker exec web ping db
docker exec web nslookup db

# 3. 看监听
docker exec db ss -tnlp

9.2 端口映射不生效

# 看映射
docker port web

# 看宿主机端口
ss -tnlp | grep :3000
# 应该是 docker-proxy 在监听

# 看 iptables 规则
sudo iptables -t nat -L DOCKER -n

冲突端口、防火墙、SELinux 都可能拦。

9.3 容器外网不通

docker exec web ping 1.1.1.1 # 通:网关 OK
docker exec web ping google.com # 不通:DNS 问题

cat /etc/resolv.conf # 容器内
docker exec web cat /etc/resolv.conf

10. 性能:NAT 还是 host?

bridge + 端口映射经过 NAT,单连接吞吐有损(约 3-5%),高并发短连接 NAT conntrack 表可能爆。

# 看 conntrack
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# 调大
sysctl -w net.netfilter.nf_conntrack_max=1000000

性能敏感场景:

  • host 模式
  • macvlan / ipvlan
  • K8s 的 hostNetwork

11. 常见反模式

  • 应用监听 127.0.0.1:容器外永远连不上
  • 容器间用 localhost 通信:每个容器有自己的 lo
  • 依赖默认 bridge 的 IP 通信:IP 重启会变
  • --link:已 deprecated,用 user-defined bridge
  • 端口大范围 -P 自动分配:每次重启端口变,外部接入麻烦
  • 跨主机用 bridge:bridge 是单机的,要 overlay 或 K8s 网络
  • 不知道 conntrack 表存在:高并发短连接挂掉莫名其妙

12. 延伸阅读