Docker Swarm 负载均衡深度解析:VIP vs DNSRR 模式详解

Docker Swarm 负载均衡深度解析:VIP vs DNSRR 模式详解

一、Swarm 负载均衡核心概念

Docker Swarm 模式内置了完整的负载均衡体系,主要包含以下核心组件:

组件 功能说明
内置 DNS 自动为集群中的每个服务分配 DNS 记录,实现服务发现
内部负载均衡 基于服务 DNS 名称在集群内部分发请求(VIP/DNSRR)
Ingress 负载均衡 通过 Ingress Network 暴露外部访问入口,实现跨节点路由
Published Port 自动分配 30000-32767 范围的端口,或手动指定端口

两种负载均衡模式对比

DNSRR 模式
DNS 记录
IP 列表轮询
容器 IP 1
容器 IP 2
容器 IP 3
VIP 模式
DNS 记录
虚拟 VIP IP
IPVS 负载均衡
容器 1
容器 2
容器 3

关键区别

  • VIP:DNS 解析到虚拟 IP,通过 IPVS 做负载均衡(类似 LVS)
  • DNSRR:DNS 直接轮询返回多个容器 IP,客户端自行选择

二、网络架构:Ingress vs 自定义 Network

Swarm 中存在两种主要的网络类型,对应不同的负载均衡场景:

2.1 Ingress Network(外部访问入口)

Swarm 集群 - Ingress Network
外部请求
IPVS
IPVS
IPVS
访问 192.168.1.79:8080
客户端
Node 1

Ingress IP: 10.0.0.1
Node 2

Ingress IP: 10.0.0.1
Node 3

Ingress IP: 10.0.0.1
ServiceA

Task 1
ServiceA

Task 2
ServiceA

Task 3

Ingress 特点

  • 创建 Swarm 集群时自动生成
  • 所有 Node 节点共享相同的 Ingress IP(把集群视为一台物理机)
  • 端口暴露(--publish)时自动使用 Ingress 网卡
  • 通过 IPVS 模块实现跨节点负载均衡

2.2 自定义 Overlay Network(内部服务通信)

自定义 Network: my-network
DNSRR 模式流量路径
返回 IP 列表
轮流访问
轮流访问
轮流访问
Client Container
DNS 轮询
10.0.0.4

10.0.0.12

10.0.0.13
ServiceA/Task 1
ServiceA/Task 2
ServiceA/Task 3
VIP 模式流量路径
overlay
overlay
overlay
Client Container
DNS 解析
VIP: 10.0.0.2
IPVS 负载均衡
Network Sandbox
ServiceA/Task 1
ServiceA/Task 2
ServiceA/Task 3

自定义 Network 特点

  • 需要手动创建(docker network create --driver overlay
  • 为每个 Service 生成唯一的 VIP (VIP 模式)或多个容器 IP(DNSRR 模式)
  • 用于服务间内部通信,具备服务发现能力
  • 支持两种负载均衡模式:VIP 和 DNSRR

三、深入理解 VIP 与 DNSRR 模式

3.1 VIP 模式(默认)

Task 3 10.0.0.13 Task 2 10.0.0.12 Task 1 10.0.0.4 IPVS 模块 虚拟 VIP 10.0.0.2 Swarm DNS 客户端容器 Task 3 10.0.0.13 Task 2 10.0.0.12 Task 1 10.0.0.4 IPVS 模块 虚拟 VIP 10.0.0.2 Swarm DNS 客户端容器 nslookup my_web 返回 VIP 10.0.0.2 请求 my_web:80 数据包标记 fwmark 负载均衡算法选择后端 转发请求(第1次) 返回响应 请求 my_web:80 转发请求(第2次) 返回响应 请求 my_web:80 转发请求(第3次) 返回响应

VIP 模式工作原理

  1. 自定义 Network 为每个 Service 生成一个虚拟 IP(VIP)
  2. 该 Service 下的所有容器 Task 共享这个 VIP
  3. 容器将端口暴露给虚拟 Service(而非物理机)
  4. 虚拟 Service 通过 IPVS 将请求负载到实际容器
  5. 类比:虚拟 Service = 物理服务器,容器 Task = 服务器上的 Docker 容器

适用场景

  • 短连接请求(HTTP REST API)
  • 需要服务端负载均衡
  • 端口不直接暴露给物理机

3.2 DNSRR 模式(DNS Round Robin)

Task 3 10.0.0.13 Task 2 10.0.0.12 Task 1 10.0.0.4 Swarm DNS 客户端容器 Task 3 10.0.0.13 Task 2 10.0.0.12 Task 1 10.0.0.4 Swarm DNS 客户端容器 10.0.0.4, 10.0.0.12, 10.0.0.13 nslookup my_web2 返回 3 个 IP 地址 直接访问 10.0.0.4(第1次) 返回响应 直接访问 10.0.0.12(第2次) 返回响应 直接访问 10.0.0.13(第3次) 返回响应

DNSRR 模式工作原理

  1. 自定义 Network 为每个容器生成具体 IP
  2. 所有容器 IP 记录到 DNS 列表
  3. 客户端查询 DNS 时,轮询返回不同 IP
  4. 客户端直接访问具体容器 IP
  5. 负载均衡发生在客户端(DNS 层面)

适用场景

  • 长连接保持(WebSocket、数据库连接)
  • 需要会话亲和性(Sticky Session)
  • 客户端能处理多 IP 轮询
  • 不支持端口对外暴露(仅内部通信)

四、容器网卡与网络选择

4.1 网卡类型总结

在 Swarm 模式下,一个容器可能拥有多张网卡:
Swarm 容器网络栈
可选网卡
基础网卡
容器访问外网
宿主机访问容器
服务间通信
外部访问入口
默认网卡

eth0
docker_bridge

与宿主机通信
自定义 Network 网卡

用于服务发现
Ingress 网卡

端口暴露时自动添加
Internet
Host
Other_Services
External

网卡类型 说明 使用条件
默认网卡 容器基础网络 始终存在
docker_bridge 与宿主机通信 始终存在
自定义 Network 网卡 服务发现、内部负载均衡 加入自定义 Network
Ingress 网卡 外部访问、跨节点路由 端口暴露(--publish

注意 :当端口暴露时(PublishMode=ingress),容器会同时拥有自定义 Network IPIngress Network IP,两者同时生效。

4.2 负载均衡模式与网卡的关系

负载均衡模式选择


默认/VIP
DNSRR
端口是否暴露?
使用 Ingress Network

VIP 模式
使用自定义 Network
选择负载均衡模式
VIP 模式

虚拟 IP + IPVS
DNSRR 模式

DNS 轮询

关键结论

  • Ingress 负载均衡:固定使用 VIP 模式,基于 IPVS
  • 自定义 Network 负载均衡:可选择 VIP(默认)或 DNSRR
  • 端口暴露与否决定了是否使用 Ingress 网卡

五、实战实验:负载均衡测试

5.1 实验环境准备

bash 复制代码
# 创建自定义 Overlay 网络
$ docker network create --driver overlay my-network

5.2 实验一:VIP 模式测试(默认)

步骤4: 测试访问
curl 192.168.1.79:8080
请求被负载均衡到 3 个副本
步骤3: 获取 VIP
docker service inspect -f '{{json .Endpoint.VirtualIPs}}' my_web
VIP: 10.0.0.2/24
步骤2: 暴露端口
docker service update --publish-add 8080:80 my_web
步骤1: 创建服务
docker service create --replicas 3

--network my-network

--name my_web nginx

执行命令

bash 复制代码
# 1. 创建 3 副本服务
$ docker service create \
    --replicas 3 \
    --network my-network \
    --name my_web \
    nginx

# 2. 添加端口暴露(使用 Ingress Network)
$ docker service update --publish-add 8080:80 my_web

# 3. 查看 VIP 信息
$ docker service inspect -f '{{json .Endpoint.VirtualIPs}}' my_web
[{"NetworkID":"3d1ut7rm89tvqvhh98wl3bxtx","Addr":"10.0.0.2/24"}]

# 4. 外部访问测试(自动负载均衡)
$ curl 192.168.1.79:8080

验证负载均衡

在每个副本容器中查看访问日志,确认请求被分发到不同容器。

5.3 实验二:DNSRR 模式测试

步骤4: Ping 测试轮询
ping my_web2
每次 ping 解析到不同 IP
步骤3: DNS 解析测试
nslookup my_web2
返回 3 个 IP:

10.0.0.4, 10.0.0.12, 10.0.0.13
步骤2: 进入容器测试
docker exec -it sh
步骤1: 创建 DNSRR 服务
docker service create

--replicas 3

--name my_web2

--network my-network

--endpoint-mode dnsrr

nginx

执行命令

bash 复制代码
# 1. 创建 DNSRR 模式服务
$ docker service create \
    --replicas 3 \
    --name my_web2 \
    --network my-network \
    --endpoint-mode dnsrr \
    nginx

# 2. 进入工作节点容器
$ docker exec -it 06a5a7ae6e7e sh

# 3. 测试 DNS 解析
/ # nslookup my_web2
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      my_web2
Address 1: 10.0.0.13
Address 2: 10.0.0.4
Address 3: 10.0.0.12

# 4. 多次 ping 测试轮询效果
/ # ping my_web2
PING my_web2 (10.0.0.4): 56 data bytes
...
/ # ping my_web2
PING my_web2 (10.0.0.12): 56 data bytes
...
/ # ping my_web2
PING my_web2 (10.0.0.13): 56 data bytes

关键观察

  • 每次 ping my_web2 解析到不同的 IP 地址
  • 负载均衡发生在 DNS 解析层面
  • 客户端直接连接具体容器 IP

5.4 查看服务负载均衡模式

bash 复制代码
# 查看当前服务的 Endpoint 模式
$ docker service inspect my_web

{
  "EndpointSpec": {
    "Mode": "vip"
  },
  "Endpoint": {
    "Spec": {
      "Mode": "vip",
      "Ports": [
        {
          "Protocol": "tcp",
          "TargetPort": 80,
          "PublishedPort": 8080,
          "PublishMode": "ingress"
        }
      ]
    }
  }
}

六、端口暴露与网络选择深入分析

6.1 端口暴露的网络影响

端口暴露 --publish
内部通信
外部访问
Service

my_web
自定义 Network

my-network

VIP: 10.0.0.2
Ingress Network

自动创建

IP: 10.0.0.1
Published Port

8080:80
端口不暴露
仅使用
Service

my_web
自定义 Network

my-network
容器 IP: 10.0.0.x

关键结论

  • 不暴露端口:仅使用自定义 Network,无 Ingress 网卡
  • 暴露端口:同时使用自定义 Network(用于服务发现)和 Ingress Network(用于外部访问)
  • 两个网卡同时生效,容器拥有多个 IP

6.2 Ingress vs 自定义 Network 负载均衡对比

自定义 Network 负载均衡
VIP
DNSRR
服务间请求
DNS 查询
VIP or DNSRR?
VIP: 10.0.0.2

IPVS 分发
轮询返回

容器 IP 列表
目标容器
目标容器
特点: 服务发现

支持 VIP/DNSRR

内部通信
Ingress 负载均衡
外部请求
任意节点

8080端口
IPVS 负载均衡
目标容器 Task
特点: 跨节点路由

基于 IPVS

固定使用 VIP

特性 Ingress Network 自定义 Network
使用场景 外部访问集群服务 内部服务间通信
负载均衡模式 固定 VIP(IPVS) VIP 或 DNSRR
服务发现 不支持 支持(内置 DNS)
网络类型 特殊 Overlay(自动创建) 自定义 Overlay(手动创建)
端口要求 需要暴露端口 不需要暴露端口
IP 分配 所有节点共享相同 Ingress IP 每个 Service 唯一 VIP 或 多个容器 IP

七、双层负载均衡架构扩展

在生产环境中,可以在 Swarm 内置负载均衡之上,再叠加一层外部负载均衡器(如 HAProxy、Nginx):
第二层: Swarm 负载均衡
第一层: 外部负载均衡
轮询
轮询
轮询
Node 3
Swarm LB

8080端口
my_web

Task 3
Node 2
Swarm LB

8080端口
my_web

Task 2
Node 1
Swarm LB

8080端口
my_web

Task 1
HAProxy

192.168.99.99:80

双层架构优势

  1. 高可用:HAProxy 可配置多后端节点,单点故障自动剔除
  2. 灵活调度:支持权重、灰度发布、会话保持等高级功能
  3. SSL 终结:在 HAProxy 层处理 HTTPS,后端使用 HTTP
  4. 大规模扩展:突破 Swarm 内置负载均衡的性能瓶颈

配置示例

haproxy 复制代码
# HAProxy 配置示例
backend swarm_nodes
    balance roundrobin
    server node1 192.168.99.100:8080 check
    server node2 192.168.99.101:8080 check
    server node3 192.168.99.102:8080 check

八、模式选择与最佳实践

8.1 负载均衡模式选择决策树







开始选择负载均衡模式
需要外部访问?
使用 Ingress Network

固定 VIP 模式
使用自定义 Network
需要长连接/会话保持?
选择 DNSRR 模式
选择 VIP 模式

默认推荐
需要端口暴露?
⚠️ DNSRR 不支持端口暴露

考虑 VIP + 应用层会话保持
DNSRR 适合

服务间长连接
VIP 适合

短连接/HTTP API

8.2 最佳实践建议

场景 推荐模式 原因
HTTP REST API VIP 短连接,服务端负载均衡更可控
WebSocket DNSRR 长连接保持,避免 VIP 连接粘滞
数据库连接 DNSRR 会话亲和性,连接池复用
外部 Web 服务 VIP + Ingress 需要端口暴露,跨节点路由
内部微服务通信 VIP(默认)或 DNSRR 根据连接特性选择

8.3 注意事项

  1. DNSRR 不支持端口暴露

    bash 复制代码
    # 错误示例:DNSRR 无法暴露端口到宿主机
    docker service create --endpoint-mode dnsrr --publish 8080:80 nginx
    # 该配置不会生效,端口不会绑定到宿主机
  2. VIP 模式的长连接问题

    • VIP 使用 IPVS,长连接可能粘滞在同一后端
    • 建议应用层实现连接池刷新或会话超时
  3. 健康检查配置

    bash 复制代码
    # 配置健康检查,确保故障容器及时剔除
    docker service create \
        --health-cmd "curl -f http://localhost/health || exit 1" \
        --health-interval 5s \
        --health-retries 3 \
        nginx
  4. 会话保持实现

    • Swarm 原生不支持会话保持(Sticky Session)
    • 需要会话亲和性时,使用 DNSRR + 客户端 cookies
    • 或叠加外部负载均衡器(HAProxy)实现

九、总结

Docker Swarm 提供了开箱即用的负载均衡能力,通过内置 DNS 和 IPVS 实现了服务发现和流量分发。核心要点如下:

  1. 两种负载均衡模式

    • VIP:虚拟 IP + IPVS,适合短连接,默认推荐
    • DNSRR:DNS 轮询,适合长连接,不支持端口暴露
  2. 两种网络类型

    • Ingress Network:外部访问入口,固定使用 VIP
    • 自定义 Network:内部服务通信,支持 VIP/DNSRR
  3. 容器多网卡

    • 基础网卡(默认 + docker_bridge)始终存在
    • 自定义 Network 网卡用于服务发现
    • Ingress 网卡在端口暴露时自动添加
  4. 扩展能力

    • 可叠加 HAProxy/Nginx 实现双层负载均衡
    • 支持 SSL 终结、权重调度、灰度发布等高级功能
相关推荐
我爱学习好爱好爱2 小时前
Ansible include任务复用 tags ignore_errors
linux·运维·ansible
panzer_maus2 小时前
工厂模式、代理模式与单例模式的介绍
java·设计模式·代理模式
@土豆2 小时前
混合云组网-基于公有云产品实现(非开源方法)
运维·网络·开源
小林学编程2 小时前
模型上下文协议(MCP)的理解
java·后端·llm·prompt·resource·tool·mcp协议
软泡芙3 小时前
【Bug】ReactiveUI WPF绑定中依赖属性不更新的问题分析与解决方案
java·bug·wpf
小程故事多_803 小时前
Harness实战指南,在Java Spring Boot项目中规范落地OpenSpec+Claude Code
java·人工智能·spring boot·架构·aigc·ai编程
浪扼飞舟3 小时前
WPF输入验证(ValidationRule)
java·javascript·wpf
砍材农夫8 小时前
spring-ai 第四多模态API
java·人工智能·spring
她说..10 小时前
Java 对象相关高频面试题
java·开发语言·spring·java-ee