4. 网络隔离方案:bridge 网络 vs overlay 网络

在多租户 Docker Compose 栈中,网络隔离是防止租户间流量串扰、保障数据安全与性能稳定的第一道防线。Docker 原生提供 bridge(桥接)与 overlay(覆盖)两种核心网络驱动,它们在隔离粒度、跨主机通信能力、性能开销与运维复杂度上存在显著差异。本章将深入对比这两种方案,并给出针对多租户场景的选型建议。

4.1 bridge 网络:单机隔离的基石

bridge 网络是 Docker 默认的网络驱动,适用于单台 Docker 主机上的容器间通信。每个 bridge 网络在宿主机上创建一个虚拟网桥(Linux bridge),连接到该网络的容器通过网桥进行二层通信,与外部网络通过 NAT 转发。

核心特性: 每个 bridge 网络拥有独立的 IP 子网、独立的 iptables 规则,容器间默认完全隔离,只有连接到同一 bridge 网络的容器才能直接通信。

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 隧道技术,在现有三层网络之上构建虚拟二层网络,使分布在不同主机的容器能够像在同一台机器上一样通信。

适用场景: 多租户 SaaS 平台、微服务集群、需要跨主机数据同步或服务调用的分布式应用。

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 存储
子网管理 手动规划,避免冲突 自动分配,支持大规模
推荐场景 单机多租户、边缘节点 跨主机集群、微服务网格
避坑提示: 不要在同一 Compose 栈中混合使用 bridge 和 overlay 网络连接同一服务,这会导致网络拓扑混乱和 DNS 解析异常。每个服务应只连接一个租户网络,必要时通过反向代理或 API 网关进行跨租户通信。

4.4 每个租户独立 network 的设计模式

无论选择 bridge 还是 overlay,核心设计原则是:一个租户一个独立 network。这种模式带来以下好处:

  • IP 地址空间隔离: 每个租户拥有独立的子网,不会发生 IP 冲突。
  • 广播域隔离: 租户间的广播流量互不影响,避免广播风暴。
  • 安全策略独立: 可为每个租户网络单独配置网络策略(如 iptables、网络策略)。
  • 资源配额独立: 每个租户网络的 IP 池大小可单独规划,避免资源争抢。
多租户独立 Network 架构示意 宿主机 A 租户1 网络 bridge / overlay 172.20.1.0/24 容器 A1 容器 A2 租户2 网络 bridge / overlay 172.20.2.0/24 容器 B1 容器 B2 宿主机 B 租户1 网络 overlay 延伸 10.10.1.0/24 容器 A3 租户2 网络 overlay 延伸 10.10.2.0/24 容器 B3 VXLAN 隧道 VXLAN 隧道 设计要点: 1. 每个租户拥有独立的 network 对象,子网不重叠。 2. 单机场景使用 bridge,跨主机场景使用 overlay。 3. 同一租户的容器只能连接到该租户的网络,禁止跨租户网络连接。 4. overlay 网络通过 VXLAN 隧道实现跨主机二层连通,租户间 VNI 不同。

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
关键结论: Docker 的 DNS 解析严格绑定到网络作用域。不同网络间的容器名互不可见,这为多租户服务发现提供了天然隔离屏障。

4.5.2 跨租户服务发现方案

当业务需要跨租户通信(如计费服务、日志收集)时,不应直接依赖 DNS 解析,而应采用以下模式:

方案 实现方式 隔离性 推荐度
API 网关 所有跨租户请求通过统一网关路由 高,网关层控制访问权限 ★★★★★
共享 overlay 网络 创建公共网络,仅允许特定服务加入 中,需配合网络策略 ★★★★
外部服务注册中心 使用 Consul/etcd 进行服务发现 高,可配置 ACL ★★★★
直接 DNS 跨网络 不推荐,破坏隔离原则 低 ★
DNS 与服务发现隔离机制 租户A 网络 (net_a) svc_a 172.20.1.2 svc_a2 172.20.1.3 DNS 解析器 (127.0.0.11) 租户B 网络 (net_b) svc_b 172.20.2.2 svc_b2 172.20.2.3 DNS 解析器 (127.0.0.11) DNS 隔离边界 不可解析对方服务名 API 网关(公共网络) API 网关(公共网络)

4.6 网络隔离最佳实践总结

生产建议:
  • 单机多租户: 优先使用 bridge 网络,每个租户独立 network,手动规划子网。
  • 集群多租户: 使用 overlay 网络,结合 Docker Swarm 或 Kubernetes 网络策略。
  • DNS 隔离: 信任 Docker 内置 DNS 的网络作用域隔离,不要手动修改 /etc/hosts 或使用 --link。
  • 跨租户通信: 统一通过 API 网关或消息队列,避免直接网络互通。
  • 监控与排障: 使用 docker network inspect 和 docker exec 定期验证隔离有效性。