Docker 的几种网络模式详解

2025-09-02 Linux 运维

Docker 容器默认是"隔离"的,但容器之间、容器与宿主机之间、容器与外部网络之间怎么通信?答案就在 Docker 的网络模式中。

这篇文章把 Docker 的六种网络模式逐一拆解:原理、适用场景、实战命令和常见坑点。

一、先理解 Docker 的网络模型

Docker 使用 CNM(Container Network Model),核心组件有三个:

组件 作用 类比
Sandbox(沙盒) 容器的网络命名空间 一个独立的房间
Endpoint(端点) 连接 Sandbox 和 Network 的接口 房间的门
Network(网络) 一组可以互相通信的 Endpoint 集合 走廊/桥梁

Docker 内置了五种网络驱动:bridge、host、none、overlay、macvlan(以及更高效的 ipvlan)。

查看当前网络:

docker network ls

输出类似:

NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local
f6e5d4c3b2a1   host      host      local
e5d4c3b2a1f6   none      null      local

二、bridge 网络(默认模式)

工作原理

每个容器启动时默认连接到 bridge 网络。Docker 在宿主机上创建一个 docker0 虚拟网桥,容器通过 veth pair(虚拟网线)连接到这个网桥上。

    宿主机
 ┌─────────────────────────┐
 │       docker0 网桥       │ ← 172.17.0.1
 │    ┌─────┴─────┐        │
 │  veth1       veth2      │ ← veth pair(虚拟网线)
 │    │           │        │
 │ ┌──┴──┐    ┌──┴──┐     │
 │ │容器A │    │容器B │     │
 │ │172. │    │172. │     │
 │ │17.0.│    │17.0.│     │
 │ │ 2   │    │ 3   │     │
 │ └─────┘    └─────┘     │
 └─────────────────────────┘
       │ eth0
       ▼
    外部网络

容器的 eth0 通过 veth pair 连接到 docker0,然后通过 NAT(iptables MASQUERADE)访问外部网络。

实践

# 默认 bridge 启动容器
docker run -d --name web1 nginx

# 查看容器 IP
docker inspect web1 --format '{{.NetworkSettings.IPAddress}}'
# 172.17.0.2

# 容器间通信(通过 IP)
docker run -d --name web2 nginx
docker exec web1 ping 172.17.0.3

# 但无法通过容器名通信(默认 bridge 不支持 DNS)
docker exec web1 ping web2  # ❌ 失败

自定义 bridge(推荐)

默认 bridge 有局限:不支持容器名自动 DNS 解析、所有容器共享相同的网络配置。创建自定义 bridge 更灵活。

# 创建自定义 bridge
docker network create --driver bridge mynet

# 容器连接到自定义 bridge
docker run -d --name app1 --network mynet nginx
docker run -d --name app2 --network mynet nginx

# 自定义 bridge 支持容器名 DNS 解析 ✅
docker exec app1 ping app2

自定义 bridge 的特点:

  • 容器间可通过容器名直接通信(自动 DNS)
  • 独立的网络命名空间,与默认 bridge 隔离
  • 可动态连接/断开容器(docker network connect/disconnect)

端口映射

# -p 宿主机端口:容器端口
docker run -d --name web -p 8080:80 nginx

# 查看映射
docker port web
# 80/tcp -> 0.0.0.0:8080

内部流程:宿主机 iptables 的 DNAT 规则将访问 0.0.0.0:8080 的流量转发到容器 172.17.0.2:80。

三、host 网络模式

容器直接使用宿主机的网络命名空间,不隔离网络。

docker run -d --name web --network host nginx

特点:

对比 bridge host
端口映射 需 -p 不需要,直接监听宿主机端口
IP 地址 独立的 172.17.x.x 同宿主机 IP
网络性能 有轻微损耗(NAT) 零损耗,接近原生
端口冲突 每个容器独立端口空间 多个容器监听同一端口会冲突
# host 模式下,容器直接监听宿主机端口
docker run -d --name web --network host nginx
# 无需 -p,直接访问 http://宿主机IP:80

适用场景:

  • 对网络性能要求极高的场景(如日志采集器、监控代理)
  • 容器需要监听宿主机大量随机端口(如服务注册中心)
  • 想要容器网络完全透明无 NAT 损耗

不适用场景:

  • 需要端口隔离的多容器部署
  • Kubernetes Pod(K8s 强制要求独立的网络命名空间)

四、none 网络模式

容器没有网络接口,完全与网络隔离。

docker run -d --name isolated --network none alpine sleep 3600

docker exec isolated ip addr
# 1: lo: <LOOPBACK,UP,LOWER_UP> ... 只有 lo 回环接口

适用场景:

  • 极简安全容器,不需要任何网络访问
  • 离线计算任务
  • 仅执行本地文件操作的工具容器

五、overlay 网络(跨主机通信)

当容器分布在不同物理机(或不同宿主机)上时,bridge 无法直接通信。overlay 网络通过 VXLAN 隧道技术,把所有宿主机虚拟成一个大的二层网络。

  宿主机A                   宿主机B
 ┌──────────┐            ┌──────────┐
 │ 容器A    │            │ 容器B    │
 │ 10.0.0.2 │            │ 10.0.0.3 │
 └────┬─────┘            └────┬─────┘
      │                      │
 ┌────┴─────┐           ┌────┴─────┐
 │overlay   │  VXLAN    │overlay   │
 │网络      │◄─────────►│网络      │
 └──────────┘ 隧道封装  └──────────┘

使用前提

overlay 网络需要 Swarm 模式或 Docker 集群。最简单的场景是 Docker Swarm:

# 初始化 Swarm(在管理节点)
docker swarm init

# 创建 overlay 网络
docker network create -d overlay --attachable myoverlay

# 在任意集群节点启动容器并连接到 overlay
docker service create --name myservice \
  --network myoverlay \
  --replicas 2 \
  nginx

关键细节

  • VXLAN 封装会带来约 5-10% 的网络性能损耗
  • 需要宿主机之间 UDP 4789 端口互通(VXLAN 默认端口)
  • --attachable 参数让普通容器(非 service)也能连接到 overlay 网络

六、macvlan 网络(二层直通)

macvlan 给容器分配一个真实的 MAC 地址,让容器像一台独立物理机一样接入局域网。

    路由器
     │
     ├── 宿主机      MAC: AA:BB:CC:DD:EE:FF    IP: 192.168.1.100
     │
     ├── 容器A       MAC: 00:11:22:33:44:01    IP: 192.168.1.101
     │
     └── 容器B       MAC: 00:11:22:33:44:02    IP: 192.168.1.102
# 创建 macvlan 网络(绑定宿主机物理接口 eth0)
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 \
  mymacvlan

# 启动容器(指定 IP)
docker run -d --name web --network mymacvlan \
  --ip=192.168.1.101 nginx

特点:

优点 缺点
无 NAT,性能极高 宿主机无法直接与容器通信(需额外配置)
容器像普通设备一样接入局域网 需要交换机支持 MAC 地址学习的上限
可用于需要直接获取客户端真实 IP 的场景 IP 地址消耗大,每个容器占一个 IP

宿主机无法访问 macvlan 容器的解决方法(创建带 parent 接口的子接口 macvlan):

# 宿主机上创建 macvlan 子接口
ip link add mymacvlan-shim link eth0 type macvlan mode bridge
ip addr add 192.168.1.200/24 dev mymacvlan-shim
ip link set mymacvlan-shim up

七、ipvlan 网络(三层直通)

ipvlan 是 macvlan 的升级版,不分配 MAC 地址,所有容器共享宿主机 MAC 地址,通过 IP 区分。

# L2 模式(同网段通信)
docker network create -d ipvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 \
  -o ipvlan_mode=l2 \
  myipvlan

# L3 模式(跨网段路由)
docker network create -d ipvlan \
  --subnet=10.0.1.0/24 \
  --subnet=10.0.2.0/24 \
  -o parent=eth0 \
  -o ipvlan_mode=l3 \
  myipvlan-l3

macvlan vs ipvlan 对比:

对比项 macvlan ipvlan
MAC 地址 每个容器独立 MAC 所有容器共享宿主机 MAC
交换机压力 高(大量 MAC 学习) 低(只有宿主机一个 MAC)
性能 优 更优
支持模式 bridge、802.1q L2、L3
主流支持 广泛 较新,部分环境可能受限

八、网络模式对比总结

模式 驱动 隔离性 性能 DNS解析 跨主机 适用场景
默认 bridge bridge ✅ 一般(有 NAT) ❌ 不支持容器名 ❌ 单机单体容器
自定义 bridge bridge ✅ 一般(有 NAT) ✅ 支持容器名 ❌ 单机多容器(推荐)
host host ❌ 不隔网络 最高 同宿主机 ❌ 高性能/端口密集场景
none null ✅ 完全隔离 - - ❌ 离线/安全容器
overlay overlay ✅ 中等(VXLAN) ✅ ✅ Swarm/K8s 集群
macvlan macvlan ✅ 高(无 NAT) ❌ ✅ 容器直接连入物理网
ipvlan ipvlan ✅ 最高 ❌ ✅ MAC 地址受限场景

九、常见问题与排查

容器能 ping 通 IP 但 ping 不通容器名

# 原因:容器在默认 bridge,不在自定义 bridge
# 解决:创建自定义 bridge 并连接
docker network create mynet
docker network connect mynet containerA
docker network connect mynet containerB

host 模式下端口冲突

# 错误:端口已被占用
docker: Error response from daemon: driver failed programming external connectivity on endpoint ...

# 解决:换端口或停止占用该端口的进程

overlay 网络跨主机不通

# 1. 检查防火墙是否放行 VXLAN 端口(UDP 4789)
# 2. 确认 Swarm 节点之间的网络连通性
# 3. 检查 IP 转发是否开启
sysctl net.ipv4.ip_forward

端口映射后外部无法访问

# 1. 确认容器监听的是 0.0.0.0 而非 127.0.0.1
docker exec web netstat -tlnp

# 2. 确认宿主机防火墙放行了映射端口
sudo ufw status | grep 8080

# 3. 检查 iptables 规则是否被覆盖
sudo iptables -t nat -L DOCKER -n

十、选择网络模式的最佳实践

                 ┌── 单机部署 ──┐
                 │              │
          需要DNS解析?     不需要DNS解析?
                 │              │
            自定义 bridge   默认 bridge
                 │
        ┌────────┴────────┐
        │                 │
    多容器通信          单容器运行
        │                 │
  自定义 bridge       默认 bridge 够用

                 ┌── 多机部署 ──┐
                 │              │
             Docker Swarm     Kubernetes
                 │              │
            overlay 网络    CNI 插件(Flannel/Calico)

                 ┌── 特殊场景 ──┐
                 │              │
         零 NAT 损耗       MAC 地址受限
                 │              │
          macvlan/ipvlan     ipvlan L2

一句话总结:

  • 单机多容器 → 自定义 bridge(兼顾隔离和 DNS 解析)
  • 高性能/端口密集 → host(零损耗但有冲突风险)
  • 集群多主机 → overlay(跨主机透明通信)
  • 物理网络直通 → macvlan/ipvlan(容器就像真机器)
  • 完全隔离 → none(连网络都不要)