4. 网络隔离方案:bridge 网络 vs overlay 网络
在多租户 Docker Compose 栈中,网络隔离是防止租户间流量串扰、保障数据安全与性能稳定的第一道防线。Docker 原生提供 bridge(桥接)与 overlay(覆盖)两种核心网络驱动,它们在隔离粒度、跨主机通信能力、性能开销与运维复杂度上存在显著差异。本章将深入对比这两种方案,并给出针对多租户场景的选型建议。
4.1 bridge 网络:单机隔离的基石
bridge 网络是 Docker 默认的网络驱动,适用于单台 Docker 主机上的容器间通信。每个 bridge 网络在宿主机上创建一个虚拟网桥(Linux bridge),连接到该网络的容器通过网桥进行二层通信,与外部网络通过 NAT 转发。
4.1.1 单租户独立 bridge 网络配置
为每个租户创建独立的 bridge 网络,是 Compose 多租户隔离最直接的做法。以下是一个典型的两租户 Compose 配置示例:
version: '3.8'
networks:
tenant1_net:
driver: bridge
ipam:
config:
- subnet: 172.20.1.0/24
gateway: 172.20.1.1
tenant2_net:
driver: bridge
ipam:
config:
- subnet: 172.20.2.0/24
gateway: 172.20.2.1
services:
app1:
image: nginx:alpine
networks:
- tenant1_net
# 租户1的其他配置...
app2:
image: nginx:alpine
networks:
- tenant2_net
# 租户2的其他配置...
4.1.2 bridge 网络隔离优势与局限
| 维度 | 优势 | 局限 |
|---|---|---|
| 隔离性 | 子网与 iptables 完全独立,租户间零通信 | 仅限单机,无法跨宿主机 |
| 性能 | 无额外封装开销,接近原生网络性能 | 大规模容器时,iptables 规则膨胀影响转发效率 |
| 运维 | 配置简单,无需额外组件 | 每台宿主机需手动管理子网不重叠 |
| DNS | 内置 DNS 解析,容器名自动注册 | 跨网络容器无法通过 DNS 发现 |
4.2 overlay 网络:跨主机租户隔离
当多租户栈需要跨多台 Docker 宿主机部署时,overlay 网络成为必然选择。overlay 网络基于 VXLAN 隧道技术,在现有三层网络之上构建虚拟二层网络,使分布在不同主机的容器能够像在同一台机器上一样通信。
4.2.1 overlay 网络配置要点
使用 overlay 网络需要 Docker Swarm 模式或外部键值存储(如 Consul、etcd)。以下是一个基于 Swarm 的 overlay 网络配置:
# 初始化 Swarm 集群(在管理节点执行)
docker swarm init
# 创建租户专属 overlay 网络
docker network create \
--driver overlay \
--subnet 10.10.1.0/24 \
--attachable \
tenant1_overlay
docker network create \
--driver overlay \
--subnet 10.10.2.0/24 \
--attachable \
tenant2_overlay
在 Compose 文件中引用这些预创建的 overlay 网络:
version: '3.8'
networks:
tenant1_overlay:
external: true
name: tenant1_overlay
tenant2_overlay:
external: true
name: tenant2_overlay
services:
svc1:
image: your-app:latest
networks:
- tenant1_overlay
deploy:
replicas: 3
placement:
constraints: [node.role == worker]
svc2:
image: your-app:latest
networks:
- tenant2_overlay
deploy:
replicas: 3
4.2.2 overlay 网络隔离优势与局限
| 维度 | 优势 | 局限 |
|---|---|---|
| 隔离性 | VXLAN 封装天然隔离,租户间流量不可达 | 需依赖 Swarm 或外部 KV 存储 |
| 跨主机 | 原生支持跨宿主机通信,无需修改应用 | VXLAN 封装增加约 50 字节包头,MTU 需调整 |
| 性能 | 内核级封装,吞吐量较高 | 相比 bridge 有 5%-15% 的性能损耗 |
| 运维 | 子网自动管理,无需手动规划 | 排障复杂度增加,需熟悉 VXLAN 调试 |
4.3 bridge vs overlay 选型对比
| 对比维度 | bridge 网络 | overlay 网络 |
|---|---|---|
| 部署规模 | 单机,适合开发/测试/小规模生产 | 多机集群,适合大规模生产环境 |
| 隔离粒度 | 子网 + iptables,强隔离 | VXLAN VNI,强隔离 |
| 性能损耗 | 接近裸机,< 2% | 5%-15%,取决于封装与加密 |
| DNS 解析 | 内置,容器名自动解析 | 内置,支持跨主机服务发现 |
| 运维复杂度 | 低,Docker 原生即可 | 中,需 Swarm 或 KV 存储 |
| 子网管理 | 手动规划,避免冲突 | 自动分配,支持大规模 |
| 推荐场景 | 单机多租户、边缘节点 | 跨主机集群、微服务网格 |
4.4 每个租户独立 network 的设计模式
无论选择 bridge 还是 overlay,核心设计原则是:一个租户一个独立 network。这种模式带来以下好处:
- IP 地址空间隔离: 每个租户拥有独立的子网,不会发生 IP 冲突。
- 广播域隔离: 租户间的广播流量互不影响,避免广播风暴。
- 安全策略独立: 可为每个租户网络单独配置网络策略(如 iptables、网络策略)。
- 资源配额独立: 每个租户网络的 IP 池大小可单独规划,避免资源争抢。
4.5 DNS 解析与服务发现隔离
在多租户网络中,DNS 解析和服务发现必须严格隔离,防止租户 A 的服务名被租户 B 解析到。Docker 内置的 DNS 解析器(127.0.0.11)天然支持网络级别的隔离:
- 作用域隔离: 每个 Docker 网络拥有独立的 DNS 命名空间。容器只能解析到同一网络内的其他容器名。
- 自动注册: 容器启动时,其容器名和 service 名自动注册到所在网络的 DNS 记录中。
- 别名支持: 可通过
network_alias为容器在同一网络内设置额外别名。
4.5.1 DNS 隔离验证示例
以下 Compose 配置演示了 DNS 隔离效果:
version: '3.8'
networks:
net_a:
driver: bridge
net_b:
driver: bridge
services:
svc_a:
image: alpine
command: sleep 3600
networks:
- net_a
container_name: container_a
svc_b:
image: alpine
command: sleep 3600
networks:
- net_b
container_name: container_b
进入容器测试 DNS 解析:
# 在 container_a 中执行
docker exec container_a ping container_b
# 结果:ping: bad address 'container_b'
# 在 container_b 中执行
docker exec container_b ping container_a
# 结果:ping: bad address 'container_a'
# 正确做法:同一网络内解析
docker exec container_a ping svc_a
# 结果:成功解析到 container_a 的 IP
4.5.2 跨租户服务发现方案
当业务需要跨租户通信(如计费服务、日志收集)时,不应直接依赖 DNS 解析,而应采用以下模式:
| 方案 | 实现方式 | 隔离性 | 推荐度 |
|---|---|---|---|
| API 网关 | 所有跨租户请求通过统一网关路由 | 高,网关层控制访问权限 | ★★★★★ |
| 共享 overlay 网络 | 创建公共网络,仅允许特定服务加入 | 中,需配合网络策略 | ★★★★ |
| 外部服务注册中心 | 使用 Consul/etcd 进行服务发现 | 高,可配置 ACL | ★★★★ |
| 直接 DNS 跨网络 | 不推荐,破坏隔离原则 | 低 | ★ |
4.6 网络隔离最佳实践总结
- 单机多租户: 优先使用 bridge 网络,每个租户独立 network,手动规划子网。
- 集群多租户: 使用 overlay 网络,结合 Docker Swarm 或 Kubernetes 网络策略。
- DNS 隔离: 信任 Docker 内置 DNS 的网络作用域隔离,不要手动修改 /etc/hosts 或使用 --link。
- 跨租户通信: 统一通过 API 网关或消息队列,避免直接网络互通。
- 监控与排障: 使用
docker network inspect和docker exec定期验证隔离有效性。