暗色模式

Docker 网络模式详解:Bridge、Host、Overlay 等六种模式与选型指南

技术教程
2026-08-01
5
0

容器能跑起来很简单,跑得「通」却需要一点网络知识。新手最常见的困惑就是:为什么两个容器互相 ping 不通?为什么 -p 8080:80 有时不生效?为什么有的容器一启动就「抢」了宿主机的端口?

答案都指向同一个东西——Docker 网络模式。本文从零讲清 Docker 的 6 种网络模式(Bridge、Host、None、Overlay、Macvlan、Ipvlan)的工作原理、优缺点,并给出不同场景下的选型建议。

网络基础:理解三个关键概念

在进入模式之前,先建立三个底层概念,理解它们之后,各种模式的区别就一目了然。

网络命名空间(Network Namespace)

Linux 的隔离机制之一。每个容器拥有独立的网络栈:自己的网卡、IP 地址、路由表和防火墙规则。Docker 的每种网络模式,本质上就是「容器网络命名空间和宿主机网络命名空间之间如何建立联系」。

veth 虚拟网卡对

一根「虚拟网线」,一头插在容器里,另一头插在宿主机的虚拟网桥上,数据包就在这根网线上双向流动。

NAT 地址转换

宿主机启动时开启 IP 转发,并通过 iptables 做源地址转换:容器访问外网时,数据包源地址被替换成宿主机 IP,回来后反向转换。NAT 让容器「借」宿主机上网,但多了一层转换开销。

六大网络模式详解

Docker 安装完成后默认自带三个网络:bridgehostnone,另外还有 overlaymacvlanipvlan 三种驱动可按需创建。用 docker network ls 即可查看:

$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
0c07a4c1d7a6   bridge    bridge    local
a1f2b3c4d5e6   host      host      local
9e8f7a6b5c4d   none      null      local

Bridge:默认模式,单机主力

工作原理:Docker 守护进程启动时创建虚拟网桥 docker0(默认网段 172.17.0.0/16),每个容器通过 veth 对连到网桥上,获得一个私有 IP;容器访问外网走 NAT,外部访问容器通过 -p 端口映射。

# 以默认 bridge 启动
docker run -d -p 8080:80 --name web nginx

# 查看容器 IP
docker inspect web | grep -i ipaddress

默认 bridge 的三个短板

  1. 没有容器名 DNS:同网段容器之间只能靠 IP 通信,而容器重启后 IP 会变,极其脆弱。
  2. 所有容器都挤在同一个网段:不同业务的容器互相可见,隔离性差。
  3. 不能热插拔:默认 bridge 上运行的容器无法动态 docker network connect 到其他网络。

自定义 Bridge 网络(强烈推荐):创建一个属于自己的网桥,以上三个问题全部解决:

# 创建自定义桥接网络
docker network create my-app-net

# 两个容器都连到该网络
docker run -d --network my-app-net --name api my-api:latest
docker run -d --network my-app-net --name db mysql:8.0

# 容器间直接用名字通信(自动 DNS 解析)
docker exec api ping db

自定义网络自带内置 DNS,api 容器直接 ping db 就能解析到 db 容器的 IP,与 IP 变化无关。同时不同自定义网络之间天然隔离,即使映射了相同端口也不冲突。绝大多数单机场景,这是最优解。

Host:共享宿主机网络栈

工作原理:容器不创建独立网络命名空间,直接复用宿主机的网络栈——容器里看到的网卡、IP 就是宿主机的。

# 启动方式:--network host
docker run -d --network host --name node-exporter prom/node-exporter

特点

  • 零 NAT 开销,性能最接近裸机,延迟最低(桥接模式大约有 5%–8% 的性能损耗)。
  • 不需要 -p 端口映射:容器进程监听什么端口,宿主机就有什么端口,-p 参数会被忽略。
  • 代价是隔离性归零:端口冲突(宿主机 80 被占,容器就起不来)、被入侵的容器可以直接操作宿主机网络栈、安全风险最高。
  • 平台限制:Docker Desktop(macOS/Windows)不支持 host 模式(除非开启实验性支持),因为容器实际跑在虚拟机里。

适合:监控采集器(Prometheus Node Exporter)、需要大量端口或抓包的场景、对性能极端敏感的应用。

None:完全断网

容器只有回环接口(lo),没有网卡、没有 IP、无法访问外网,也拒绝外部访问。适合对安全性要求极高、或者根本不需要网络的场景:

docker run --network none --name sandbox my-image:latest

典型用途:离线计算任务、安全沙箱、纯数据处理容器(只通过挂载卷交换数据)。

Container:与另一个容器共享网络

不常用但值得一提:新容器与指定容器共享同一个网络命名空间,两者通过 127.0.0.1 互访,像是「同一个容器里的两个进程」。

docker run --network container:db --name sidecar my-sidecar:latest

典型场景:边车(sidecar)模式,比如把日志采集、网络代理注入到业务容器旁边,不暴露多余端口。

Overlay:跨主机通信

工作原理:基于 VXLAN 隧道技术,在多个宿主机之间建立二层虚拟网络,容器就像连在同一个交换机上,可以跨主机按名字互相通信。需要先初始化 Swarm 集群:

# 集群中任一节点初始化 Swarm
docker swarm init

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

# 在不同宿主机上用服务方式部署,即可跨主机互通
docker service create --network my-overlay-net --name web --replicas 3 nginx

注意事项:需要开放 2377(Swarm 管理)、7946(节点间通信)、4789(VXLAN)三个端口;VXLAN 封装会增加约 50 字节包头,建议把 MTU 调低(如 1450)避免分片丢包;启用加密(--opt encrypted)会有额外性能开销。

适合:Docker Swarm 集群、跨主机的微服务架构。注意:如果用的是 Kubernetes,网络层通常交给 CNI 插件(Calico、Cilium 等),不会再直接用 Docker 的 overlay。

Macvlan 与 Ipvlan:让容器接入物理网络

Macvlan:给每个容器分配独立的 MAC 地址和物理局域网 IP,容器看起来就像一台插在交换机上的真实设备,无需 NAT、无端口映射,性能和延迟接近物理机:

# 假设宿主机网卡是 eth0,局域网 192.168.1.0/24
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 my-macvlan-net

docker run -d --network my-macvlan-net --ip 192.168.1.100 --name legacy my-app:latest

适用:老应用迁移(原来跑在物理机/VM 上,IP 固定)、IoT 设备、VLAN 网络集成。

但有两个坑

  1. 宿主机无法直接访问 macvlan 容器(内核限制),需要额外创建 macvlan shim 接口做桥接,麻烦。
  2. 部分云厂商 VPC 环境禁止 macvlan(网络策略限制),且交换机可能需要开启混杂模式。

Ipvlan:与 macvlan 类似,但所有容器共享宿主机的 MAC 地址,只分配独立 IP。MAC 地址消耗少、对传统交换机兼容性更好,适合需要大量容器接入同一子网的场景(比如一个网段跑上千个容器)。注意 ipvlan 有 L2 和 L3 两种模式,L3 模式下宿主机需开启 ip_forward。

模式对比总表

维度BridgeHostNoneOverlayMacvlan/Ipvlan
网络隔离好(可按网络隔离)完全隔离弱(二层直连)
性能中(NAT 损耗约 5%–8%)最好(近裸机)中(VXLAN 开销)很好
跨主机否(仅同局域网)
NAT是(可加密)
按名字解析自定义网络支持用宿主机 DNSSwarm 服务发现走物理网络 DNS
配置复杂度极低高(需手动配)
端口冲突风险

如何选择:一张决策路径图

选型不必纠结,按下面这棵决策树走就行:

需要跨主机通信吗?
├─ 是 → Overlay(Swarm 集群)
└─ 否
    ├─ 需要容器像物理设备一样接入局域网?
    │   ├─ 是 → Macvlan(需 MAC 数量多时用 Ipvlan)
    │   └─ 否
    │       └─ 需要极致性能且不在乎隔离?
    │           ├─ 是 → Host(注意端口冲突)
    │           └─ 否
    │               ├─ 需要完全断网隔离? → None
    │               └─ 默认场景 → 自定义 Bridge(90% 的答案)

按场景直接抄作业

场景推荐模式理由
单机多容器应用(Web + DB + Redis)自定义 Bridge名字互访、网络隔离、最省心
开发调试自定义 Bridge与生产一致,便于排查
监控采集(Node Exporter 等)Host需要抓宿主机指标,性能优先
对延迟极度敏感(游戏服务器、压测)Host 或 Macvlan无 NAT 开销
Swarm 集群 / 跨主机微服务Overlay唯一跨主机内置方案
旧应用迁移、固定 IP、IoTMacvlan模拟物理设备,IP 不变
大量容器接入同一子网Ipvlan共享 MAC,地址不浪费
安全沙箱、离线计算None完全隔离,拒绝一切网络

实战:docker compose 里的网络配置

Compose 文件里的网络配置是最高频的实战场景。默认情况下 Compose 会为每个项目自动创建专属网络,所有服务互相可见,且自带服务名 DNS:

services:
  web:
    image: nginx
    ports:
      - "8080:80"
  api:
    image: my-api:latest
  db:
    image: mysql:8.0

# 不写 networks 时,三个服务都在项目默认网络里,
# api 容器里直接 curl http://db:3306 即可访问数据库

需要更精细的隔离时,可以显式拆分网络——比如让 web 能访问外部互联网,而 db 完全内网化:

services:
  web:
    image: nginx
    ports:
      - "8080:80"
    networks:
      - frontend
  api:
    image: my-api:latest
    networks:
      - frontend
      - backend
  db:
    image: mysql:8.0
    networks:
      - backend

networks:
  frontend: {}
  backend:
    internal: true   # backend 网络禁止访问外网,db 只能被 api 访问

internal: true 是生产环境加固数据库、消息队列的常用手段——数据库容器彻底断外网,即使被攻破也无法外传数据。

常见坑与避坑建议

坑 1:默认 bridge 上靠 IP 通信,重启后 IP 变了。 解法:一律使用自定义 Bridge 网络 + 容器名通信,禁止裸 IP。

坑 2:host 模式端口冲突导致容器起不来。 解法:先 ss -lntp 确认端口占用;能用 bridge 映射就别用 host。

坑 3:macvlan 下宿主机访问不了容器。 解法:这是内核限制不是 bug,按官方文档添加 macvlan shim 接口,或改用 ipvlan。

坑 4:overlay 跨主机大流量丢包。 解法:检查 MTU,VXLAN 建议降到 1450 并统一各节点 MTU 配置。

坑 5:容器访问外网很慢或不通。 解法:检查宿主机的 net.ipv4.ip_forward 是否开启(sysctl net.ipv4.ip_forward),这是 NAT 出网的前提。

总结

  • 默认选择永远是自定义 Bridge:它覆盖了 90% 的单机场景,容器名 DNS + 网络隔离 + 灵活插拔。
  • 追求极致性能且能接受低隔离 → Host
  • 需要跨主机集群 → Overlay(Swarm)或交给 K8s 的 CNI。
  • 需要接入物理网络、固定 IP → Macvlan,大量容器则用 Ipvlan
  • 安全隔离、完全断网 → None

选型的核心不是「哪个最快」,而是「哪个匹配场景」。绝大多数时候,一个自定义 Bridge 网络就够了。

参考资料

发表评论

暂无评论,快来抢沙发吧!