Docker 网络模式全解析:6 种驱动选型与生产环境避坑指南
先从一段真实经历说起
先说我踩过的一个坑。刚入行那会儿,我用 Docker 默认的 bridge 网络跑了一个微服务集群,容器之间通过 IP 互相调用。某天重启了一台宿主机,所有容器 IP 都变了,服务全崩。当时我才意识到——默认 bridge 网络不支持容器名 DNS 解析,容器之间只能靠 IP 通信。
后来翻官方文档才发现,Docker 的“默认网络”和“用户自定义网络”根本不是一回事。这期文档我就把 Docker 的 6 种网络模式一次性讲透,帮你少走弯路。
Docker 网络模式速览
Docker 的网络子系统是插件化的,通过不同的网络驱动(driver)来提供核心网络功能。Docker Engine 在 Linux 上提供了以下内置网络驱动:
模式 | 一句话概括 | 适用场景 |
bridge | 默认模式,容器通过虚拟网桥通信 | 单机多容器通信 |
host | 容器直接使用宿主机网络栈 | 追求极致网络性能 |
none | 完全无网络 | 离线计算、安全隔离 |
container | 共享另一个容器的网络命名空间 | 边车(sidecar)模式 |
overlay | 跨主机容器通信(VXLAN 隧道) | Swarm 集群、多机分布式 |
macvlan | 容器拥有独立 MAC 地址 | 从 VM 迁移、需要容器像物理主机 |
ipvlan | 容器共享宿主机 MAC,独享 IP | 同网段大量容器、MAC 数量受限 |
安装 Docker 后系统会自动创建三个默认网络:bridge、host、none。
一图看懂:所有模式对比表
🔄结构调整:对比表从原 Macvlan/IPvlan 章节之后移至此处,先给全局骨架,再逐个拆解血肉,阅读负担更小。
模式 | 隔离级别 | 独立 IP | 独立 MAC | 端口映射 | 跨主机 | 性能开销 | 平台限制 |
bridge(默认) | 中 | ✅ | ✅ | 需要 | ❌ | 中 | 无 |
bridge(自定义) | 高 | ✅ | ✅ | 需要 | ❌ | 中 | 无 |
host | 极低 | ❌(共享宿主机) | ❌ | 失效 ⚠️ | ❌ | 最低 | Linux 为主;Docker Desktop 4.34+ 需手动开启 |
none | 极高 | ❌ | ❌ | ❌ | ❌ | 零 | 无 |
container | 中(依赖目标) | ❌(共享目标) | ❌(共享目标) | 共享目标(不可单独设置) | ❌ | 低 | 无 |
overlay | 高 | ✅ | ✅ | 需配置 | ✅ | 高(VXLAN 封装开销) | 需 Swarm |
macvlan | 中 | ✅ | ✅(独立) | 不需要 | ❌ | 极低(接近原生性能) | ⚠️仅 Linux;云厂商常阻断 |
ipvlan | 中 | ✅ | ❌(共享宿主机 MAC) | 不需要 | ❌ | 极低(接近原生性能) | Linux |
模式一:Bridge——默认但别直接用默认
它是什么
Bridge 是 Docker 的默认网络驱动。在 Linux 上,Docker 启动时会创建一个名为docker0的虚拟网桥(默认子网 172.17.0.0/16),每个容器分配一对 veth pair——一端在容器的网络命名空间(eth0),一端连到网桥上。容器访问外网走 NAT(iptables MASQUERADE),外部访问容器需要做端口映射(-p)。
⚠️ 致命问题:默认 bridge ≠ 用户自定义 bridge
这是90% 新手踩的第一个坑。Docker 的默认 bridge 网络和用户自定义的 bridge 网络有本质区别:
特性 | 默认 bridge | 用户自定义 bridge |
容器名 DNS 解析 | ❌ 不支持(只能用 IP) | ✅ 自动支持 |
动态连接/断开 | ❌ 需要停止容器重建 | ✅ 支持 |
配置灵活性 | ❌ 所有容器共用配置 | ✅ 每个网络独立配置 |
隔离性 | ❌ 所有容器都在同一个网络 | ✅ 按需隔离 |
生产环境铁律:永远不要在 production 中使用默认 bridge 网络。原因很简单——默认 bridge 上的容器无法通过容器名互相访问,只能靠 IP。在动态环境中 IP 会变,而名字不会。
⚠️--link参数已废弃。老版本 Docker 可以用--link让容器通过名称互相访问,但官方文档已明确将其标记为legacy feature,最终可能会被移除,除非你绝对需要继续使用它,否则强烈建议使用用户定义的网络。别教读者用--link补救——新项目千万别碰。
正确用法
# ❌ 错误:使用默认 bridge(不指定 --network) docker run -d --name my-app nginx # ✅ 正确:创建用户自定义 bridge 网络 docker network create --driver bridge my-app-network # 启动容器并加入自定义网络 docker run -d --name web --network my-app-network nginx docker run -d --name db --network my-app-network postgres:16 # 在 web 容器中可以直接通过 "db" 访问数据库 docker exec web ping db # 能通!🔧生产环境常用--internal参数
如果你需要创建一个完全隔离的内部网络(容器之间可以互通,但不能访问外部网络),可以加上--internal参数:
# 创建内部网络,容器无法访问外网 docker network create --driver bridge --internal my-internal-network docker run -d --name internal-app --network my-internal-network nginx # 这个容器无法 ping 通 8.8.8.8,但可以和同网络的其它容器通信这个模式很适合用来部署内网微服务——数据库、缓存、消息队列这些不需要直接暴露给外网的组件,放在 internal 网络里更安全。
特点总结
维度 | 评价 |
隔离性 | 高(独立网络命名空间) |
性能 | 中(NAT + veth pair 有开销,比 host 低约 5–10%) |
易用性 | 高(默认即用,但自定义网络需要手动创建) |
安全性 | 中(端口可控,但需要合理规划网络隔离) |
适用场景
- 单机多容器应用(Web 服务 + 数据库 + 缓存)
- 开发/测试环境
- 需要端口映射对外暴露服务的场景
模式二:Host——性能王者,隔离弃子
它是什么
Host 模式下,容器直接使用宿主机的网络命名空间,没有网络隔离、没有虚拟网桥、没有 NAT。容器内的端口就是宿主机的端口——比如容器里监听 80,宿主机的 80 端口就直接被占用了。
性能优势从哪来
省掉了三层东西:NAT 转换、veth pair 遍历、userland-proxy。对于高频交易、实时数据采集这类对延迟极度敏感的场景,host 模式是首选。
⚠️ 两个致命限制
第一,端口冲突。同一台宿主机上只能有一个容器监听同一个端口。想跑两个 Nginx 容器都用 80 端口?没门。
第二,-p参数失效。官方文档明确写了——-p、--publish、-P、--publish-all这些选项在 host 网络模式下会被忽略,并产生警告:
$ docker run -d --network host -p 8080:80 nginx WARNING: Published ports are discarded when using host network mode平台支持
Host 网络驱动只在 Linux 上原生支持。Docker Desktop 从 4.34 版本开始支持(需要手动在 Settings → Resources → Network 中开启“Enable host networking”)。
特点总结
维度 | 评价 |
隔离性 | 极低(完全共享宿主机网络栈) |
性能 | 最高(无任何虚拟化开销) |
端口管理 | 麻烦(必须手动规划,避免冲突) |
安全性 | 较差(容器可访问宿主机所有网络接口) |
适用场景
- 对网络性能极度敏感的应用(高频交易、游戏服务器、基准测试)
- 需要处理大量端口的应用(避免每个端口创建 userland-proxy)
- 单容器部署(没有多容器端口冲突问题)
模式三:None——完全离线
它是什么
None 模式下容器只有lo回环网卡,没有外部网络连接,与宿主机和其他容器完全隔离。
$ docker run -it --network none alpine ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> ... # 只有 lo,没有 eth0适用场景
- 只需要运行计算任务、不需要任何网络通信的批处理容器
- 安全沙箱、离线审计
- 测试隔离环境
⚠️ 注意
None 网络不支持 Swarm 服务。
模式四:Container——共享命名空间的“边车”模式
它是什么
Container 模式让一个新容器与一个已存在的容器共享同一个网络命名空间。这意味着两个容器共用一套 IP 地址、路由规则和端口空间(Port Space)。
# 先启动一个容器 docker run -d --name app tomcat # 新容器共享 app 的网络命名空间 docker run -d --name nginx --network container:app nginx核心理解(关键避坑点):
既然共享了端口空间,那么这两个容器不能同时监听同一个端口。比如 App 容器监听了 8080,Nginx 容器就不能再监听 8080(会报端口冲突),但它们可以互相通过
localhost或127.0.0.1直接访问对方暴露的不同端口(例如 Nginx 监听 80,App 监听 8080,Nginx 就能通过localhost:8080反向代理到 App)。
这个设计在Kubernetes Pod 模型中被大量使用——Pod 内的多个容器(如主业务容器 + 日志采集 Sidecar)共享网络命名空间,通过localhost高效通信,但各自监听不同的端口号。
端口映射行为补充说明:
如果在创建“目标容器”(App)时使用了
-p 8080:8080,这个端口映射规则会被新容器继承。如果目标容器没有端口映射,新容器也不允许单独添加
-p参数(会被 Docker Daemon 拦截或报错)。
🔗 过渡句
搞定了单机内的网络“合租”模式,接下来的需求就升级了——如果容器需要跨宿主机进行通信,那就必须请出下一章的主角:Overlay 网络。
特点总结
| 维度 | 评价 |
|---|---|
| 隔离性 | 中(与目标容器共享 IP 及端口空间) |
| 端口冲突风险 | 较高(需人工规划两个容器的监听端口) |
| 灵活性 | 依赖目标容器的生命周期 |
| 典型场景 | 边车模式(如日志采集器与主应用共享网络) |
适用场景
Sidecar 代理(如 Envoy 伴随主容器)
调试代理(需要访问目标容器的网络栈)
多进程容器风格的部署
模式五:Overlay——跨主机通信的标配
它是什么
Overlay 网络将多个 Docker 守护进程连接在一起,让运行在不同宿主机上的容器能够直接通信。它基于VXLAN 隧道技术,在底层网络上构建一个覆盖网络。
⚠️概念澄清:Overlay 是Docker Swarm 模式的内置网络方案。其 VXLAN 封装理念也被 Kubernetes CNI 插件(如 Flannel)广泛采用,但K8s 环境中不会使用 Docker 的 Overlay 驱动,而是用独立的 CNI 实现。不要把 Docker Overlay 和 K8s CNI 混为一谈。
性能代价
Overlay 网络有不可忽视的性能开销。VXLAN 封装会增加约50 字节的包头开销,吞吐量通常只有原生网络栈的一半左右。
🔧 生产环境关键参数:MTU
这是 Overlay 网络在生产环境最大的坑。如果不设置 MTU,VXLAN 头部(约 50 字节)会导致底层网络频繁丢包或分片,跨主机大包传输会直接卡死。
铁律:如果底层物理网卡 MTU 为 1500,Overlay 网络的 MTU必须设置为 1450(1500 - 50)。
# ✅ 正确:通过 --opt 指定 MTU docker network create -d overlay \ --subnet=10.0.9.0/24 \ --opt com.docker.network.driver.mtu=1450 \ my-overlay-net⚠️注意:Dockernetwork create命令中不存在--mtu这个顶级参数。正确的写法是通过--opt com.docker.network.driver.mtu=1450传递。
不设置这个参数,跨主机通信会出现诡异的“小包能通、大包超时”问题——排查起来极其痛苦。
适用场景
- 多主机分布式应用
- Docker Swarm 集群服务
- 需要跨节点容器通信的场景
模式六:Macvlan vs IPvlan——直接接入物理网络的双生子
这两个模式放在一起说,因为它们解决的是同一类问题——让容器直接接入物理网络,获得与宿主机同网段的独立 IP。
Macvlan
Macvlan 为每个容器分配独立的 MAC 地址,让容器在网络上看起来像一台独立的物理主机。
docker network create -d macvlan \ --subnet=192.168.1.0/24 \ --gateway=192.168.1.1 \ -o parent=eth0 \ my-macvlan-net优点:性能极好(接近原生性能——绕过 docker0 和 NAT,开销极低),不需要端口映射和额外桥接;完美兼容需要 MAC 地址识别的遗留应用。
缺点(很致命):
- 只支持 Linux 主机,不支持 Docker Desktop for Mac 或 Windows
- 官方文档明确写了:“Most cloud providers block macvlan networking. You may need physical access to your networking equipment.”——因为需要物理网卡工作在混杂模式(promiscuous mode),云平台的虚拟交换机层面通常会阻止
- 需要 Linux kernel 3.9+(推荐 4.0+)
- 不支持 rootless 模式
- 宿主机与 macvlan 容器之间默认无法直接通信,这是 Linux 内核的限制
我在 AWS 上试过 macvlan,直接翻车。不是配置问题,是底层网络压根就不允许。如果你的容器跑在云上,macvlan 基本可以忽略。
IPvlan
IPvlan 和 macvlan 类似,但不为每个容器分配独立的 MAC 地址——所有容器共享宿主机的 MAC 地址,只在 IP 层做区分。
docker network create -d ipvlan \ --subnet=192.168.1.0/24 \ --gateway=192.168.1.1 \ -o ipvlan_mode=l2 \ -o parent=eth0 \ my-ipvlan-net一句话区别:macvlan 是“不同 MAC + 不同 IP”,ipvlan 是“相同 MAC + 不同 IP”。
IPvlan 的优势:
- 规避了云厂商对混杂模式的限制(因为不分配新 MAC)
- 适合同一网段有大量容器的场景(交换机 MAC 表不会爆)
- 支持 L2 和 L3 两种模式
适用场景对比
场景 | 推荐 |
从 VM 迁移,应用依赖 MAC 地址识别 | Macvlan |
云环境、VPS(大多数云厂商) | IPvlan(macvlan 大概率被阻断) |
同网段需要大量容器(> 几百个) | IPvlan(避免 MAC 地址耗尽) |
物理机房、可控网络设备 | 两者皆可 |
生产环境选型决策树
你的容器需要跨主机通信吗? ├─ 是 → 用 Overlay(Swarm 集群) └─ 否 → 继续往下 你需要容器直接拥有物理网络 IP(不需要端口映射)吗? ├─ 是 → 你在物理机房还是云上? │ ├─ 物理机房,可控网络 → Macvlan │ └─ 云上/VPS → IPvlan(macvlan 大概率被云厂商阻断) └─ 否 → 继续往下 你需要极致网络性能(毫秒级延迟敏感)吗? ├─ 是 → Host 模式(但注意端口冲突!) └─ 否 → 继续往下 你需要容器间通过名称互相访问吗? ├─ 是 → **用户自定义 bridge 网络**(千万别用默认的!) └─ 否 → 默认 bridge 也能用,但建议还是用自定义的 你的容器完全不需要网络? └─ None 模式验证方法
1. 查看当前所有网络
docker network ls预期输出(Linux 上):
NETWORK ID NAME DRIVER SCOPE def456... bridge bridge local ghi789... host host local jkl012... none null local说明:SCOPE列对于 Overlay 网络会显示swarm,对于 Bridge/Host/None 显示local。
2. 查看容器的网络详情
docker inspect <container_name> | jq '.[0].NetworkSettings'3. 测试容器间 DNS 解析(自定义 bridge)
# 在 web 容器中 ping db 容器(通过容器名) docker exec web ping db4. 验证 host 模式下端口映射被忽略
docker run --rm --network host -p 8080:80 nginx 2>&1 | grep -i warning # 应该看到: WARNING: Published ports are discarded when using host network mode常见问题(真实报错)
Q1:默认 bridge 网络下容器无法通过名称互相访问
报错原文:
ping: bad address 'my-db'
原因:默认 bridge 网络不支持自动 DNS 解析,容器之间只能通过 IP 地址访问。
解决方案:改用用户自定义 bridge 网络。
docker network create mynet docker run -d --name db --network mynet postgres docker run -d --name web --network mynet nginx # 现在 web 容器中可以直接 ping dbQ2:Host 模式下使用-p端口映射不生效
报错原文:
WARNING: Published ports are discarded when using host network mode
原因:host 模式下容器直接使用宿主机网络栈,没有独立的网络命名空间,端口映射没有意义。
解决方案:
- 移除
-p参数,直接让容器监听端口 - 或者改用 bridge 网络 + 端口映射
Q3:Macvlan 在云服务器上无法工作
官方文档原文:
“Most cloud providers block macvlan networking. You may need physical access to your networking equipment.”
社区反馈:
“多数公有云默认启用源/目的检查(Source/Destination Check),尤其在使用自定义网桥或 macvlan 模式时,会拦截非本机发起的流量。”
解决方案:
- 如果在云上,改用IPvlan(共享宿主机 MAC,不触发云平台限制)
- 如果在物理机房且能控制交换机,可以尝试 macvlan
Q4:Container 模式启动失败——目标容器不存在
报错原文:
No such container: <container_name>
原因:--network container:<name>指定的目标容器不存在或未运行。
解决方案:确保目标容器已经存在且处于运行状态。
Q5:Overlay 网络跨主机大包通信超时
现象:小包(如 ping)能通,但大包(如 curl 大文件、数据库批量查询)超时或卡死。
根本原因:VXLAN 封装增加了约 50 字节的包头开销,如果 Overlay 网络的 MTU 没有相应减小,数据包会在物理网络层面被分片或丢弃。
解决方案:创建 Overlay 网络时通过--opt com.docker.network.driver.mtu=1450设置 MTU。
最后说几句
三个核心 takeaways:
- 永远不要在生产环境用默认 bridge——没有 DNS 解析,容器间只能靠 IP,一重启就崩。创建用户自定义 bridge 网络是举手之劳,收益巨大。
--link已经废弃,别走回头路。 - 性能、隔离、便捷三者不可兼得——host 最快但最不安全,bridge 最通用但有 NAT 开销,overlay 能跨主机但必须设置 MTU=1450(否则大包传输会卡死)。选型前先想清楚你最在乎什么。
- macvlan 在云上大概率不可用——别在 AWS、GCP、阿里云上折腾 macvlan 了,直接上 ipvlan 省心。
如果觉得这篇对你有帮助,欢迎分享给团队里正在踩网络坑的同事。
你在生产环境里用过哪个网络模式?遇到过什么奇葩问题?欢迎留言交流。