前言
Docker 网络是很多新手最想绕道走的模块。
什么 NAT、网桥、网络命名空间、DNS 解析……光看名词就头晕。
但其实 Docker 网络没那么复杂。今天这篇文章,用最通俗的语言 + 最直观的图,带你彻底搞懂 Docker 网络的三驾马车:bridge、host、none,以及多容器如何优雅地通信。

一、一张图看懂 Docker 默认网络
先看看 Docker 安装后会自动创建哪几个网络:
docker network ls
# 输出示例(重点关注前三个):
# NETWORK ID NAME DRIVER SCOPE
# abc123 bridge bridge local ← 默认,最常用
# def456 host host local ← 共享宿主机网络
# ghi789 none null local ← 完全无网络
# my-net123 my-net bridge local ← 你手动创建的网络bridge:默认网络驱动,容器有独立 IP,通过虚拟网桥通信
host:容器直接使用宿主机网络栈,无隔离
none:完全没有网络,只有回环接口 lo
二、bridge 模式详解(默认网络)
工作原理:虚拟网桥 + NAT
想象你住在一个小区(宿主机),每家每户(容器)都有独立的内部门牌号(容器IP),但要从外面访问你,必须通过小区的统一大门(宿主机 IP + 端口映射)。
宿主机 (物理网卡: 192.168.1.100)
│
├─ Docker 虚拟网桥 (docker0: 172.17.0.1) ← 小区总路由
│ ├─ 容器1 (vethXXXX): 172.17.0.2 ← 住户1
│ ├─ 容器2 (vethXXXX): 172.17.0.3 ← 住户2
│ └─ 容器3 (vethXXXX): 172.17.0.4 ← 住户3关键特性:
✅ 每个容器有独立 IP
✅ 容器间可以通过 IP 互相通信
❌ 默认 bridge 不支持容器名 DNS 解析
✅ 需要端口映射(-p)才能让外部访问
实际操作演示
# 启动两个容器(默认 bridge 网络)
docker run -d --name web1 nginx
docker run -d --name web2 nginx
# 查看容器 IP 地址
docker inspect -f '{{.NetworkSettings.IPAddress}}' web1
# 输出:172.17.0.2
docker inspect -f '{{.NetworkSettings.IPAddress}}' web2
# 输出:172.17.0.3
# ✅ 通过 IP 可以互相 ping 通
docker exec -it web1 ping 172.17.0.3 # ✅ 可以!
docker exec -it web2 ping 172.17.0.2 # ✅ 可以!
# ❌ 通过容器名无法解析(默认 bridge 的致命缺点!)
docker exec -it web1 ping web2
# 输出:ping: web2: Name or service not known ❌⚠️ 这是默认 bridge 最大的痛点! 容器 IP 是动态分配的,重建容器后 IP 会变,用 IP 通信根本不可靠。那怎么办?
答案:用自定义 bridge 网络!

三、自定义 bridge 网络(强烈推荐!)
自定义网络解决了默认 bridge 的所有痛点,是多容器应用的标准选择。
使用自定义网络的正确姿势
# ️ 第1步:创建自定义网络
docker network create my-app-net
# ✅ 网络已创建,可以反复使用
# 第2步:启动容器时加入这个网络
docker run -d --name mysql --network my-app-net mysql:8.0
docker run -d --name redis --network my-app-net redis:7.0
docker run -d --name web --network my-app-net -p 8080:80 nginx
# ✅ 现在可以用容器名互相访问了!
docker exec -it web ping mysql # ✅ 通!
docker exec -it web ping redis # ✅ 通!
docker exec -it mysql ping web # ✅ 通!
# 验证 DNS 解析正常工作
docker exec -it web nslookup mysql
# 输出:Address: 172.18.0.2 ← DNS 自动解析成 IP从此以后,容器之间用名字通信,简单、稳定、优雅!
自定义网络的其他优势
# 优势1:自动 DNS 解析(最重要的!)
# 容器名 = 主机名,可直接用于连接字符串
# 比如在应用里:DB_HOST=mysql 就可以连上数据库
# 优势2:更好的隔离性
# 不同自定义网络之间默认无法互通,更安全
# 优势3:动态加入/退出网络
docker network disconnect my-app-net web # 把 web 从网络里踢出去
docker network connect my-app-net web # 重新加入
# 优势4:支持多个网络(容器可以同时加入多个网络)
docker network create front-net
docker network connect front-net web # web 同时在两个网络里
四、host 模式详解
工作原理:共享宿主机的网络栈
host 模式下,容器完全不隔离网络,直接和宿主机共用网络命名空间。
宿主机 (192.168.1.100)
└── 容器(共用宿主机网络栈,没有自己独立的 IP)
├── 直接绑定宿主机端口
└── 没有 NAT 转换,性能最好通俗理解: 容器就像一个"隐形人"直接坐在宿主机上操作网络,它开的端口就是宿主机开的端口。
使用示例
# 使用 host 模式(Linux 专属!)
docker run -d --network host nginx
# ✅ nginx 直接监听宿主机的 80 端口
# 不需要 -p 端口映射!
curl http://localhost:80 # ✅ 直接访问
# ❌ 注意:macOS 和 Windows 不支持 host 模式
# 在这两个平台上使用 --network host 会被忽略⚖️ host 模式:适合 vs 不适合
# ✅ 典型场景:Node Exporter(主机监控)
docker run -d \
--network host \
--name node-exporter \
prom/node-exporter:latest
# 直接采集宿主机的网络接口信息五、none 模式详解
工作原理:完全断网
none 模式下,容器完全没有网络,只有一个回环接口 lo(127.0.0.1)。
docker run -d --network none --name isolated-app my-app
# 进入容器查看网络接口
docker exec -it isolated-app ip addr
# 输出:
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
# inet 127.0.0.1/8 scope host lo ← 只有回环接口!
# (没有任何 eth0 或类似接口)适用场景:
数据处理任务(不需要网络,只需要算力)
对安全性要求极高的计算任务
测试网络隔离行为
离线批处理作业

六、三种模式全面对比
七、完整实战:多容器博客系统网络配置
让我们用实际例子把今天学的东西串联起来。这是一个典型的 Web 应用架构:
外部用户
│
▼
宿主机 (端口 80)
│
▼
[nginx 容器] (blog-proxy, bridge 网络)
│
├──▶ [blog-app 容器] (应用层, 同一 bridge 网络, 用容器名访问)
│
├──▶ [mysql 容器] (数据库, 同一 bridge 网络, 不对外暴露端口!)
│
└──▶ [redis 容器] (缓存, 同一 bridge 网络, 不对外暴露端口!)# ️ 第1步:创建专属网络(隔离外部访问)
docker network create --driver bridge blog-internal
# ️ 第2步:启动数据库(不暴露端口到外部!)
docker run -d \
--name blog-db \
--network blog-internal \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=blog_db \
-v blog-db-data:/var/lib/mysql \
mysql:8.0
# ️ 第3步:启动 Redis 缓存
docker run -d \
--name blog-cache \
--network blog-internal \
redis:7.0
# 第4步:启动应用(只有这一层对外暴露端口)
docker run -d \
--name blog-app \
--network blog-internal \
-p 80:8080 \
-e DB_HOST=blog-db \ # ← 用容器名!自动 DNS 解析!
-e REDIS_HOST=blog-cache \ # ← 用容器名!
blog-app:v1
# ✅ 外部访问:http://你的服务器IP
# ✅ 内部通信:blog-app 通过容器名访问 blog-db 和 blog-cache
# ✅ 安全性:数据库和 Redis 对外部完全不可见!安全亮点: 数据库和 Redis 不对外暴露任何端口,只有同一网络内的 blog-app 能访问它们,安全性大大提升!
八、跨网络容器如何通信?
有时候你需要让一个容器同时访问两个网络(比如一个容器既要对外服务,又要访问内网数据库):
# 创建两个网络
docker network create front-net # 前端网络
docker network create back-net # 后端网络
# 数据库只在后端网络
docker run -d --name mysql --network back-net mysql:8.0
# 应用同时加入两个网络
docker run -d --name app --network front-net -p 8080:80 app:v1
docker network connect back-net app # 再加入后端网络
# ✅ 现在 app 既能对外服务,又能访问 mysql
docker exec -it app ping mysql # ✅ 通!总结

今天的核心内容,用一张选择决策表收尾:
核心心法: 只要你的应用有多个容器需要互相通信,就用自定义 bridge 网络 + 容器名访问。这是 Docker 网络的最佳实践,没有之一。