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 IP 和Ingress 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 终结、权重调度、灰度发布等高级功能
相关推荐
小羊没烦恼!4 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里4 天前
java中的继承和多态的区别
java
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕4 天前
JSONObject与JSONArray封装数据格式区别
java·json
虎头金猫4 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
胡写代码4 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖4 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时4 天前
01-06-A-JVM排查实战详解
java·jvm
分布式存储与RustFS4 天前
MinIO 官方 Docker 镜像被移除:依赖它的项目该怎么办
docker·云原生·devops·对象存储·minio·分布式存储
vipxieliang4 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot