Docker 网络模式详解:bridge、host、overlay 和 macvlan
Docker 提供了多种网络模式,让容器既能灵活通信,又能实现安全隔离。无论是单机多容器应用,还是跨主机的 Swarm 集群,亦或需要直接接入物理网络的 IoT 设备,Docker 的网络子系统都有对应的解决方案。本文将系统讲解 Docker 全部 5 种网络模式------bridge、host、none、overlay 和 macvlan------并提供完整的配置示例和实战演示,帮助你在生产环境中做出正确的网络架构决策。
服务器配置
学习和测试 Docker 网络不需要顶级硬件,但需要一台干净、稳定的 Linux 环境。推荐选用 雨云服务器 rainyun+com 的 2 核 4GB 机型 ,该配置足以同时运行多个容器、测试 Swarm 单节点集群,以及模拟 macvlan 和 overlay 网络场景。注册填码 2026off 领 5 折券,性价比极高。
推荐操作系统:Ubuntu 22.04 LTS 或 Debian 12。本文所有命令均在该环境下验证通过。
核心概念
Docker 网络模式本质上是通过 Linux 内核的网络命名空间(network namespace)、虚拟网卡(veth pair)、网桥(bridge)以及 iptables/nftables 规则来实现的。理解这一底层机制有助于排查网络故障。
| 网络模式 | 隔离性 | 跨主机 | 典型场景 |
|---|---|---|---|
| bridge | 中 | 否 | 单机多容器,默认推荐 |
| host | 无 | 否 | 高性能、低延迟应用 |
| none | 完全 | 否 | 安全沙盒、纯计算任务 |
| overlay | 中 | 是 | Swarm 集群、微服务 |
| macvlan | 中 | 否* | IoT、需要独立 IP 的场景 |
安装与配置
安装 Docker
bash
# 一键安装脚本(Ubuntu/Debian)
curl -fsSL https://get.docker.com | bash
# 将当前用户加入 docker 组,避免每次都用 sudo
sudo usermod -aG docker $USER
newgrp docker
# 验证安装
docker version
docker info
模式一:bridge(默认网络模式)
bridge 是 Docker 的默认网络模式。每个容器拥有独立的网络命名空间,通过虚拟网卡对连接到宿主机上的 docker0 网桥,再经 NAT 访问外网。
使用默认 bridge 网络
bash
# 运行两个容器,均连接默认 bridge
docker run -d --name app1 --network bridge nginx:alpine
docker run -d --name app2 --network bridge alpine sleep 3600
# 查看默认 bridge 网络信息
docker network inspect bridge
# 默认 bridge 网络中容器只能通过 IP 互访(不支持 DNS 解析容器名)
docker exec app2 ping $(docker inspect -f '{{.NetworkSettings.IPAddress}}' app1)
端口映射(-p 参数)
bash
# 将容器 80 端口映射到宿主机 8080
docker run -d --name web -p 8080:80 nginx:alpine
# 映射到指定 IP
docker run -d --name web2 -p 127.0.0.1:8081:80 nginx:alpine
# 查看端口映射
docker port web
用户自定义 bridge 网络(推荐生产使用)
自定义 bridge 网络相比默认 bridge 有两大优势:容器名 DNS 解析 和更好的隔离性。
bash
# 创建自定义 bridge 网络
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
myapp-network
# 运行容器并连接到自定义网络
docker run -d --name frontend --network myapp-network nginx:alpine
docker run -d --name backend --network myapp-network python:3.11-alpine python3 -m http.server 8000
# 自定义网络支持容器名 DNS 解析------直接 ping 容器名即可
docker exec frontend ping backend
docker exec frontend wget -qO- http://backend:8000
# 将已运行的容器动态连接/断开网络
docker network connect myapp-network some-existing-container
docker network disconnect myapp-network some-existing-container
查看网络详情
bash
docker network ls
docker network inspect myapp-network
# 查看容器的网络配置
docker inspect --format='{{json .NetworkSettings.Networks}}' frontend | python3 -m json.tool
模式二:host
host 模式下,容器直接共享宿主机的网络命名空间,没有网络隔离。容器中的服务监听的端口直接绑定在宿主机的网络接口上,无需端口映射,延迟极低。
bash
# 使用 host 网络运行容器
docker run -d --name nginx-host --network host nginx:alpine
# 此时 nginx 直接监听宿主机的 80 端口
curl http://localhost:80
# host 模式下 -p 参数无效(直接用宿主机端口)
# 验证:容器内看到的网络接口与宿主机完全一致
docker exec nginx-host ip addr show
适用场景:
- 需要最低网络延迟的应用(如高性能代理、游戏服务器)
- 需要监听宿主机特定物理网卡的服务
- 网络性能测试工具
限制:
- 端口冲突:若宿主机已占用某端口,容器无法再监听该端口
- 安全隔离性弱,不推荐在多租户环境使用
- macOS 和 Windows 上的 Docker Desktop 不支持 host 模式
模式三:none
none 模式为容器创建独立的网络命名空间,但不配置任何网络接口(除了 loopback)。容器完全与外部网络隔离。
bash
# 运行完全无网络的容器
docker run -d --name isolated --network none alpine sleep 3600
# 验证:容器内只有 lo 接口
docker exec isolated ip addr show
# 输出只有 127.0.0.1/8
# 无法访问外网
docker exec isolated ping 8.8.8.8
# ping: bad address '8.8.8.8'
适用场景:
- 安全沙盒:运行不可信代码
- 纯 CPU 密集型计算任务(如编译、数据处理)
- 需要通过 volume 进行数据交换而不需要网络的任务
模式四:overlay
overlay 网络专为 Docker Swarm 多主机集群设计,能让不同宿主机上的容器像在同一个局域网内通信,无需手动配置路由。
bash
# 首先初始化 Swarm(单节点也可测试)
docker swarm init --advertise-addr $(hostname -I | awk '{print $1}')
# 创建 overlay 网络
docker network create \
--driver overlay \
--subnet 10.0.9.0/24 \
myswarm-network
# 在 Swarm 中创建服务,使用 overlay 网络
docker service create \
--name web-service \
--network myswarm-network \
--replicas 3 \
-p 8080:80 \
nginx:alpine
# 查看服务状态
docker service ls
docker service ps web-service
# 创建 attachable overlay 网络(允许独立容器连接,便于调试)
docker network create \
--driver overlay \
--attachable \
--subnet 10.0.10.0/24 \
debug-overlay
# 在 attachable overlay 网络上运行独立容器
docker run -d --name debugger --network debug-overlay alpine sleep 3600
多主机集群加入:
bash
# 在管理节点获取 worker 加入令牌
docker swarm join-token worker
# 在 Worker 节点执行(替换实际 token 和 IP)
docker swarm join --token SWMTKN-1-xxxxx 192.168.1.100:2377
模式五:macvlan
macvlan 允许容器拥有独立的 MAC 地址和 IP 地址,直接接入物理网络,就像一台独立的物理机。这是 IoT、裸机服务以及需要固定 IP 的场景的最佳选择。
bash
# 查看宿主机物理网卡名称
ip link show
# 假设物理网卡为 eth0,子网为 192.168.1.0/24,网关为 192.168.1.1
# 创建 macvlan 网络
docker network create \
--driver macvlan \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
--opt parent=eth0 \
macvlan-net
# 运行容器,分配固定 IP
docker run -d \
--name iot-device \
--network macvlan-net \
--ip 192.168.1.150 \
alpine sleep 3600
# 验证容器获得了独立 IP(可从局域网其他设备直接访问)
docker exec iot-device ip addr show
docker exec iot-device ip route show
# 宿主机访问 macvlan 容器需要创建 macvlan 子接口
ip link add macvlan-shim link eth0 type macvlan mode bridge
ip addr add 192.168.1.151/32 dev macvlan-shim
ip link set macvlan-shim up
ip route add 192.168.1.150/32 dev macvlan-shim
注意: 宿主机物理网卡需要开启混杂模式(或交换机端口允许多 MAC 地址)才能正常工作:
bash
ip link set eth0 promisc on
Docker Compose 中的网络配置
基础网络配置
yaml
# docker-compose.yml
version: "3.9"
services:
frontend:
image: nginx:alpine
ports:
- "80:80"
networks:
- frontend-net
backend:
image: python:3.11-alpine
command: python3 -m http.server 8000
networks:
- frontend-net
- backend-net
database:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
networks:
- backend-net # 只在后端网络,前端无法直接访问
networks:
frontend-net:
driver: bridge
ipam:
config:
- subnet: 172.21.0.0/24
backend-net:
driver: bridge
ipam:
config:
- subnet: 172.22.0.0/24
使用外部已有网络
yaml
networks:
shared-network:
external: true # 使用已存在的网络,不由 Compose 创建/销毁
name: myapp-network
host 和 none 模式的 Compose 配置
yaml
services:
high-perf-proxy:
image: haproxy:latest
network_mode: host # 使用 host 网络
sandbox-job:
image: python:3.11
network_mode: none # 完全无网络
command: python3 /scripts/compute.py
实战演示
多容器应用的网络隔离最佳实践
以下是一个典型的三层应用(前端、后端 API、数据库)的网络隔离方案:
yaml
# docker-compose.prod.yml
version: "3.9"
services:
nginx:
image: nginx:alpine
ports:
- "443:443"
- "80:80"
networks:
- public-net
depends_on:
- api
api:
image: myapp-api:latest
networks:
- public-net # 接收来自 nginx 的流量
- private-net # 访问数据库
environment:
DB_HOST: postgres # 通过容器名 DNS 解析
REDIS_HOST: redis
postgres:
image: postgres:16-alpine
networks:
- private-net # 仅在私有网络,外部无法直接访问
volumes:
- pg-data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
networks:
- private-net
networks:
public-net:
driver: bridge
private-net:
driver: bridge
internal: true # 禁止访问外网,纯内部通信网络
volumes:
pg-data:
网络排查:常用命令速查
bash
# ===== 查看网络 =====
docker network ls # 列出所有网络
docker network inspect <network-name> # 查看网络详情(含所有容器 IP)
docker inspect <container> | grep -A 20 "Networks" # 查看容器网络配置
# ===== 连通性测试 =====
docker exec <container> ping <target-ip> # ping 测试
docker exec <container> ping <container-name> # DNS 解析 + ping
docker exec <container> wget -qO- http://<host>:<port> # HTTP 连通测试
docker exec <container> nc -zv <host> <port> # TCP 端口测试
# ===== 网络状态 =====
docker exec <container> ip addr show # 查看网卡和 IP
docker exec <container> ip route show # 查看路由表
docker exec <container> ss -tlnp # 查看监听端口(替代 netstat)
docker exec <container> cat /etc/resolv.conf # 查看 DNS 配置
# ===== 宿主机侧排查 =====
ip link show # 查看所有网络接口(含 docker0、veth 等)
bridge link show # 查看 bridge 上连接的 veth 接口
iptables -t nat -L -n -v # 查看 Docker 配置的 NAT 规则
iptables -L DOCKER -n -v # 查看 Docker 防火墙规则
# ===== 清理 =====
docker network prune # 删除所有未使用的网络
docker network rm <network-name> # 删除指定网络
常见问题与解决
Q:自定义 bridge 网络的容器为何无法解析容器名?
确认容器是否连接到了同一个 自定义网络(不是默认的 bridge)。默认 bridge 网络不支持容器名 DNS,只有用户自定义网络才支持。
Q:macvlan 容器无法与宿主机通信?
这是 macvlan 的内核限制。解决方法是在宿主机上创建 macvlan 子接口(见上文配置),通过该接口与容器通信。
Q:overlay 网络创建报错"This node is not a swarm manager"?
需要先执行 docker swarm init 初始化 Swarm,overlay 网络依赖 Swarm 的 key-value 存储。
Docker 网络模式各有适用场景:日常开发用自定义 bridge,高性能场景考虑 host,安全隔离用 none,集群部署选 overlay,物理网络集成用 macvlan。掌握这 5 种模式,能让你的容器化架构更加灵活和安全。如果你还没有合适的服务器环境来练习,推荐注册 雨云服务器 rainyun+com ,选择 2 核 4GB 机型 ,注册填码 2026off 领 5 折券,立即开始你的 Docker 网络实战之旅。