46-Linux学习之旅之LVS负载均衡与keepalived高可用

Linux学习之旅之LVS负载均衡与keepalived高可用

一、LVS基础介绍

1.1、集群介绍

集群类型 介绍 优点 缺点
LB 负载均衡(高扩展) 负载均衡集群,核心是请求分发。将用户流量按算法分发到多台后端服务器,横向扩容承载更多并发请求,代表:LVS、Nginx、HAProxy。目标:分担压力、提升并发能力。 1. 支持横向扩容,弹性增加节点提升承载;2. 单节点压力被分散,不容易被打垮;3. 部分 LB 自带后端节点健康检查,自动剔除故障节点。 1. 只是流量分发,不能保证业务有状态数据一致性;2. 七层 LB 会消耗 CPU 做解析、SSL 解密;3. 无自动故障切换能力,调度器本身存在单点,需要搭配 HA。
HA 高可用集群 高可用集群,核心是故障转移。消除单点故障,当主节点宕机,集群自动把服务、VIP 漂移到备节点,快速接管业务。代表:Keepalived、Pacemaker+Corosync。目标:减少服务中断时间。 1. 故障自动切换,RTO 低,业务连续性高;2. 可管理 VIP、存储、数据库、自定义服务等资源;3. 可配合 LB,解决负载调度器单点问题。 1. 不负责流量分担,无法提升并发;2. 存在 "脑裂" 风险,需要仲裁机制;3. 复杂 HA 集群配置、排障难度大,有资源依赖约束。
HPC 高性能集群 高性能计算集群,核心是算力聚合。把一个巨型计算任务拆分成多个子任务,分发到多个计算节点并行运算。代表:MPI、Slurm。目标:缩短超大计算任务耗时。 1. 聚合多台机器算力,处理超大计算任务;2. 适合仿真、气象、渲染、基因测序等计算密集场景;3. 算力可按需横向叠加。 1. 业务任务需要支持并行改造,普通 Web 业务不适用;2. 节点间通信量大,对高速网络(IB/RoCE)要求高;3. 任务拆分、调度复杂,IO 容易成为瓶颈。
1.1.1、LVS原理
bash 复制代码
	LVS 是根据监听到的前端请求报文中的目标 IP 和目标协议及端口号,将该请求转发到后台某台 RS 服务器上,由 RS 服务器完成对前端请求的响应,具体的监听规则及调度策略由使用者自行配置。
	LVS 是内核中的功能,工作在 PRE_ROUTING链 和 INPUT链 中间的位置上,截取发往 INPUT 链的请求与配置好的 LVS 监听及调度规则进行	对比,如果命中,则会触发 LVS 调度,从而转发该请求
bash 复制代码
客户端请求报文 → 网卡接收
        ↓
【PREROUTING】链(路由前)
        ↓
路由判断:目的IP是VIP(本机)
        ↓
==== IPVS(LVS)钩子在这里拦截 ====
截取报文:匹配【目标IP、协议、端口】和ipvs规则表
命中 → 按调度算法选出RS,根据模式(NAT/DR/TUN)修改报文,转发
未命中 → 继续往下走【INPUT链】交给本机上层应用
        ↓
【INPUT】链
        ↓
本机应用程序
1.1.2、LVS常用术语
分类 缩写 全称 释义
物理术语(主机) DS Director Server 调度服务器,LVS 调度器,运行 ipvs 模块
RS Real Server 后端真实业务服务器,处理业务请求
逻辑术语(IP) VIP Virtual Server IP 虚拟服务 IP,客户端访问的入口 IP
DIP Director Server IP 调度器 DS 本身的真实网卡 IP,DS 和 RS 通信使用
RIP Real Server IP 后端 RS 服务器本身的真实 IP
CIP Client IP 客户端的源 IP
访问关系:CIP <--> VIP === DIP <--> RIP 解读

​ CIP <--> VIP:客户端只知道 VIP,客户端和 VIP 交互 VIP === DIP:

​ VIP 配置在 DS(调度器)上,属于 DS 这台机器;

​ DIP <--> RIP:调度器 DS 通过自己的 DIP 和后端 RS 的 RIP 通信

1.1.3、LVS访问流程图

VS-NAT(网络地址转换模式)

bash 复制代码
CIP(客户端)
   ↓ 源:CIP 目的:VIP
DS调度器(VIP+DIP)【DNAT改目的IP为RIP】
   ↓ 源:CIP 目的:RIP
RS(RIP)
   ↑ 回包:源:RIP 目的:CIP
DS调度器【SNAT改源IP为VIP】
   ↑ 源:VIP 目的:CIP
CIP(客户端)

VS-DR(直接路由)

bash 复制代码
CIP(客户端)
   ↓ 源:CIP 目的:VIP
DS调度器(VIP+DIP)【只修改二层MAC,IP头不变】
   ↓ 报文IP还是CIP→VIP,MAC变成RS的MAC
RS(RIP,lo绑定VIP,arp抑制)
   ↘ 响应包:源:VIP 目的:CIP,**直接回客户端,不走DS**
CIP(客户端)

VS-TUN(IP 隧道模式)

bash 复制代码
CIP(客户端)
   ↓ 内层:CIP→VIP
DS调度器(VIP+DIP)【IPIP封装,外层头DIP→RIP】
   ↓ 隧道包发给RS
RS(RIP,解隧道)
   ↘ 响应包:源:VIP 目的:CIP,**直接回客户端,不走DS**
CIP(客户端)

1.2、LVS组成部分

1.2.1、LVS组成
组件 空间位置 作用说明
IPVS(IP Virtual Server) 内核空间(内核模块) LVS 核心!真正实现四层报文调度、转发,维护内核里的虚拟服务和 RS 列表、调度算法;基于 netfilter 钩子,在 PREROUTING 后、INPUT 前拦截报文做负载分发腾讯云
ipvsadm 用户空间(命令行工具) 原生管理工具;用来增删查改 IPVS 集群规则(VIP、RS、权重、调度算法、模式 NAT/DR/TUN),通过 netlink 和内核 ipvs 通信腾讯云
Keepalived(扩展配套组件,生产必用) 用户空间(独立程序) 不是 LVS 原生必须组件,但是生产标配1. VRRP:实现 VIP 漂移、DS 调度器主备 HA2. HealthCheck:自动检测后端 RS 健康状态,自动上下线 RS3. 内置 ipvs 封装,在配置文件里管理 LVS 规则,替代 ipvsadm 手动命令
1.2.2、ipvsadm软件安装与简单查看
bash 复制代码
# 软件安装
[root@xyx:~]# apt install ipvsadm

# 帮助使用
[root@xyx:~]# ipvsadm --help | head
ipvsadm v1.31 2019/12/24 (compiled with popt and IPVS v1.2.1)
Usage:
  ipvsadm -A|E virtual-service [-s scheduler] [-p [timeout]] [-M netmask] [--pe persistence_engine] [-b sched-flags]
  ipvsadm -D virtual-service
  ipvsadm -C
  ipvsadm -R
  ipvsadm -S [-n]
  ipvsadm -a|e virtual-service -r server-address [options]
  ipvsadm -d virtual-service -r server-address
  ipvsadm -L|l [virtual-service] [options]
选项 全称 作用说明
-A --add-service 添加虚拟服务(VIP 集群)
-E --edit-service 修改已存在的虚拟服务
-D --delete-service 删除一条虚拟服务(连带下面所有 RS)
-a --add-server 给虚拟服务添加后端 Real Server RS
-e --edit-server 修改 RS 参数(权重、模式等)
-d --delete-server 删除某一台后端 RS
-C --clear 清空 IPVS 全部所有规则
-L / -l --list 查看 LVS 集群规则列表
-n --numeric 数字格式输出,不反解域名(生产必加,速度快)
-c --connection 查看当前活跃连接状态,配合 - L 使用:ipvsadm -Lnc
--stats 查看流量统计(包数、字节)
--rate 查看速率统计
-Z --zero 清空连接统计计数器
-S --save 导出保存 ipvs 规则(配合 > 重定向)
-R --restore 导入恢复 ipvs 规则(和 - S 成对使用)
-t --tcp-service 指定 TCP 虚拟服务 VIP:PORT
-u --udp-service 指定 UDP 虚拟服务 VIP:PORT
-f --fwmark-service 防火墙标记模式
-s --scheduler 指定调度算法:rr/wrr/lc/wlc/sh/dh 等
-r --real-server 指定后端 RS 的 IP:PORT
-g --gatewaying DR 直接路由模式(生产最常用)
-i --ipip TUN 隧道模式
-m --masquerading NAT 地址转换模式
-w --weight 设置 RS 权重,数字越大权重越高
-p --persistent 持久会话(会话保持),后面跟超时时间,默认 300s
-h --help 帮助

1.3、调度算法和ipvsadm

1.3.1、调度算法
1.3.1.1、ipvsadm内置策略
模块名 简称 全称 类型 原理 & 作用 适用场景
CONFIG_IP_VS_RR rr Round Robin 轮询 静态 按顺序轮流分发连接,所有 RS 均分流量,不关心负载 所有服务器性能一致、短连接均衡业务
CONFIG_IP_VS_WRR wrr Weighted Round Robin 加权轮询 静态 按权重比例分配,权重越高分到连接越多;不看实时连接数 后端服务器硬件性能不一样、短连接场景
CONFIG_IP_VS_LC lc Least Connections 最少连接 动态 挑选当前活跃连接数最少的 RS 分发新连接 长连接、请求耗时差异大的业务
CONFIG_IP_VS_WLC wlc Weighted Least Connections 加权最少连接 动态 (生产最常用)计算 连接数/权重,比值最小的 RS 优先分配,兼顾负载和机器性能 绝大多数线上业务,LVS 默认推荐算法
CONFIG_IP_VS_FO fo Fail Over 故障转移(加权故障转移) 动态 优先选权重最高、没有标记过载的 RS;如果该 RS 过载,自动切换下一个高权重 RS;可手动标记 RS 过载 灰度发布、故障隔离、主备集群、版本切换
CONFIG_IP_VS_OVF ovf Overflow 溢出调度 动态 优先给权重最高的 RS 分配,直到它活跃连接数等于权重值,满了再溢出到下一台高权重 RS 限制单机最大连接数,防止单台被打垮
CONFIG_IP_VS_LBLC lblc Locality-Based Least Connection 基于本地的最少连接 动态 同一个目标 IP 固定调度到同一 RS;如果该 RS 过载,再选负载最轻的 RS 正向代理、缓存服务器,按客户端访问目标 IP 做缓存亲和
CONFIG_IP_VS_LBLCR lblcr LBLC with Replication 带复制的 LBLC 动态 在 LBLC 基础上增加副本机制;目标 IP 绑定一组 RS,防止单点过载,减少缓存失效 大型缓存集群
CONFIG_IP_VS_DH dh Destination Hashing 目标地址哈希 静态 对目标 IP 做哈希,相同目标 IP 永远分到同一个 RS 缓存、代理服务器
CONFIG_IP_VS_SH sh Source Hashing 源地址哈希 静态 对客户端源 IP 哈希,同一个 CIP 固定调度同一 RS,原生会话保持 需要会话绑定、无持久化的四层业务
CONFIG_IP_VS_MH mh Maglev 马格列夫一致性哈希 静态 谷歌 Maglev 一致性哈希,五元组哈希;后端节点上下线时,只有少量连接漂移 K8s IPVS 模式、需要稳定哈希、节点频繁扩缩容场景
CONFIG_IP_VS_SED sed Shortest Expected Delay 最短预期延迟 动态 公式:(active+1)*256/weight,选值最小的;比 WLC 更激进,优先空闲高性能机器 延迟敏感业务,希望优先把连接给到空闲高配机器
CONFIG_IP_VS_NQ nq Never Queue 永不排队 动态 只要有空闲 RS,优先分给空闲机器;全部繁忙时,退化成 SED 算法 低延迟、不想让请求排队等待
CONFIG_IP_VS_TWOS twos Two-Stage 两阶段加权调度 静态 两步加权随机:第一轮筛掉过载节点,第二轮在剩下节点中加权随机选择;负载分布更平滑,长尾更少 高并发大集群,追求流量均匀打散
1.3.1.2、调度分类
类别 算法列表 简要说明
✅ 静态方法(不看后端负载) RR、WRR、DH、SH RR 轮询;WRR 加权轮询;DH 目标 IP 哈希;SH 源 IP 哈希只按顺序 / 权重 / 哈希值分发,不管 RS 现在连接多不多
✅ 动态方法(参考后端实时连接负载) LC、WLC、LBLC、LBLCR、SED、NQ LC 最小连接;WLC 加权最小连接(生产首选);LBLC 本地最少连接;LBLCR 带复制 LBLC;SED 最短预期延迟;NQ 永不排队分配前会对比各个 RS 当前活跃连接数,优先分给负载轻的机器
✅ 4.15 高版本内核新增 FO、OVF、MH、TNDR(你的 6.8 内核额外还有 TWOS) FO:FailOver 故障转移OVF:Overflow 溢出调度MH:Maglev 一致性哈希(K8s 常用)TNDR:Two-Node DR(双节点调度)TWOS:两阶段加权随机(6.x 版本加入)
1.3.2、集群管理
bash 复制代码
# 1. 添加集群
# 命令格式:ipvsadm -A -t|u|f service_address:port [-s scheduler] [-p [timeout]]
	-A 添加虚拟服务(VIP 集群)
	-t 指定 TCP 虚拟服务 VIP:PORT
	-u 指定 UDP 虚拟服务 VIP:PORT
	-f 防火墙标记模式
	=s 指定调度算法:rr/wrr/lc/wlc/sh/dh 等
	-p 持久会话(会话保持),后面跟超时时间,默认 300s
[root@xyx:~]# ipvsadm -A -t 10.0.0.14:22
[root@xyx:~]# ipvsadm -A -t 10.0.0.13:80 -s rr
[root@xyx:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.13:80 rr
TCP  10.0.0.14:22 wlc

# 2. 修改集群
# 命令格式:ipvsadm -E -t service_address:port [-s scheduler]
	-E 修改已存在的虚拟服务
[root@xyx:~]# ipvsadm -E -t 10.0.0.13:80 -s lc
[root@xyx:~]# ipvsadm -E -t 10.0.0.14:22 -p 60
[root@xyx:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.13:80 lc
TCP  10.0.0.14:22 wlc persistent 60

# 3. 删除集群
# 命令格式:ipvsadm -D -t service_address:port
	-D 删除一条虚拟服务(连带下面所有 RS)
	-C 清空 IPVS 全部所有规则
[root@xyx:~]# ipvsadm -D -t 10.0.0.13:80
[root@xyx:~]# ipvsadm -D -t 10.0.0.14:22
[root@xyx:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
1.3.3、主机管理
bash 复制代码
# 1. 查看主机
 # -L 查看集群内所有主机
 # -n 不解析协议
[root@xyx:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

# 2. 添加主机
# 命令格式:ipvsadm -a -t service_address:port -r server-address:port -g|m|i [options]
	-a 给lvs集群增加一个真实主机RS
	-r 指定真实主机的地址信息,格式是 IP:[Port],Port可以省略
	-g|m|i 设定后端主机的转发模式
		-g 采用默认的direct routing模式
		-m 采用masquerading的nat模式
		-i 采用ipip的tunneling模式
	-w 指定真实主机的权重信息
[root@xyx:~]# ipvsadm -A -t 10.0.0.13:80
[root@xyx:~]# ipvsadm -a -t 10.0.0.13:80 -r 10.0.0.23
[root@xyx:~]# ipvsadm -a -t 10.0.0.13:80 -r 10.0.23		# 地址补充后相同失败
Destination already exists
[root@xyx:~]# ipvsadm -a -t 10.0.0.13:80 -r 10.0		# -r 会自动补齐后续地址,完整地址最好
[root@xyx:~]# ipvsadm -a -t 10.0.0.13:80 -r 10.0.0.24:886 -m
[root@xyx:~]# ipvsadm -a -t 10.0.0.13:80 -r 10.0.0.25:886 -m -w 3
[root@xyx:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.13:80 wlc
  -> 10.0.0.0:80                  Route   1      0          0
  -> 10.0.0.23:80                 Route   1      0          0
  -> 10.0.0.24:886                Masq    1      0          0
  -> 10.0.0.25:886                Masq    3      0          0

# 3. 编辑主机
# 命令格式:ipvsadm -e -t service_address:port -r server-address:port [options]
	-e 修改真实主机的属性信息
	-m 设定真实主机的转发模型信息为nat模型
	注意:
		修改真实主机信息的时候,必须指定已存在的lvs集群地址,协议也必须正确
		-m 和 -i 不能同时使用
[root@xyx:~]# ipvsadm -e -t 10.0.0.13:80 -r 10.0.0.23:80 -w 5	
[root@xyx:~]# ipvsadm -e -t 10.0.0.13:80 -r 10.0.0.24:886 -i
No such destination
[root@xyx:~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.13:80 wlc
  -> 10.0.0.0:80                  Route   1      0          0
  -> 10.0.0.23:80                 Route   5      0          0
  -> 10.0.0.24:886                Masq    1      0          0
  -> 10.0.0.25:886                Masq    3      0          0

# 4. 删除主机
[root@xyx:~]# ipvsadm -d -t 10.0.0.13:80 -r 10.0.0.0:80
[root@xyx:~]# ipvsadm -d -t 10.0.0.13:80 -r 10.0.0.23		# 和集群端口相同会自动补充80
[root@xyx:~]# ipvsadm -d -t 10.0.0.13:80 -r 10.0.0.24:886
[root@xyx:~]# ipvsadm -d -t 10.0.0.13:80 -r 10.0.0.25:886
[root@xyx:~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.13:80 wlc
1.3.4、规则买命令
bash 复制代码
# 1. 查看规则
# 命令格式:ipvsadm-save [-n]
	格式详解:
		-n 以精确的数字格式打印出lvs规则,如果不加-n的话,他会基于域名解析,将相应的ip转换成主机
	名展示
		使用 ipvsadm -Sn 可以实现同样的效果
[root@xyx:~]# ipvsadm -A -t 10.0.0.14:80
[root@xyx:~]# ipvsadm -a -t 10.0.0.14:80 -r 10.0.0.24:80
[root@xyx:~]# ipvsadm -a -t 10.0.0.14:80 -r 10.0.0.25:80
[root@xyx:~]# ipvsadm -a -t 10.0.0.14:80 -r 10.0.0.26:80
[root@xyx:~]# echo "10.0.0.24 lvs-server lvs-server.example.com" >> /etc/hosts
[root@xyx:~]# ipvsadm-save
-A -t 10.0.0.13:http -s wlc
-A -t 10.0.0.14:http -s wlc
-a -t 10.0.0.14:http -r lvs-server:http -g -w 1
-a -t 10.0.0.14:http -r 10.0.0.25:http -g -w 1
-a -t 10.0.0.14:http -r 10.0.0.26:http -g -w 1
[root@xyx:~]# ipvsadm-save -n
-A -t 10.0.0.13:80 -s wlc
-A -t 10.0.0.14:80 -s wlc
-a -t 10.0.0.14:80 -r 10.0.0.24:80 -g -w 1
-a -t 10.0.0.14:80 -r 10.0.0.25:80 -g -w 1
-a -t 10.0.0.14:80 -r 10.0.0.26:80 -g -w 1

# 2. 保存规则
# 通过 ipvsadm-save + > 的方式实现 规则的保存
[root@xyx:~]# ipvsadm-save + > n-ipvsadm
[root@xyx:~]# ipvsadm-save -n + > non-ipvsadm
[root@xyx:~]# ll
-rw-r--r--  1 root root  198 Oct 26 08:57 n-ipvsadm
-rw-r--r--  1 root root  181 Oct 26 08:58 non-ipvsadm
[root@xyx:~]# cat n-ipvsadm
-A -t 10.0.0.13:http -s wlc
-A -t 10.0.0.14:http -s wlc
-a -t 10.0.0.14:http -r lvs-server:http -g -w 1
-a -t 10.0.0.14:http -r 10.0.0.25:http -g -w 1
-a -t 10.0.0.14:http -r 10.0.0.26:http -g -w 1

# 3. 清空规则
# 命令格式:ipvsadm -C
	格式详解:
		-C 清空lvs服务集群规则
[root@xyx:~]# ipvsadm -C
[root@xyx:~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
[root@xyx:~]# ipvsadm-save

# 4. 导入规则
# 命令格式:ipvsadm-restore < 规则文件
[root@xyx:~]# sed -i '/lvs/d' /etc/hosts		# 验证带n和不带n的区别,没有hosts解析识别不出来
[root@xyx:~]# ipvsadm-restore < n-ipvsadm
illegal real server address[:port] specified
[root@xyx:~]# ipvsadm -Ln		# 发现没有主机只有集群
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.13:80 wlc
TCP  10.0.0.14:80 wlc
[root@xyx:~]# ipvsadm-restore < non-ipvsadm		# 有主机了
[root@xyx:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.13:80 wlc
TCP  10.0.0.14:80 wlc
  -> 10.0.0.24:80                 Route   1      0          0
  -> 10.0.0.25:80                 Route   1      0          0
  -> 10.0.0.26:80                 Route   1      0          0

二、keepalived基础

2.1、keepalived介绍

​ Keepalived 是 Linux 下开源、轻量的高可用(HA)软件 ,原生基于 VRRP(虚拟路由冗余协议),早期为 LVS(IPVS 四层负载均衡)配套开发;两大核心能力可以分开独立使用,也可以组合使用Keepalived

​ 虚拟路由冗余协议(Virtual Router Redundancy Protocol,简称VRRP)是由IETF提出的解决局域网中配置静态网关出现单点故障现象的路由协议,其本质上是一种路由容错协议。VRRP 的核心目标就是将多台网关设备组成一个 "虚拟路由器" ,对外提供一个固定的虚拟 IP 和虚拟MAC 地址,从而实现网关的故障自动切换,保障网络的连续性。

2.1.1、工作流程
bash 复制代码
	keepalived部署在多台主机上(一般是两台),keepalived服务启动后,会加载专用的配置文件,调用内核的LVS服务以创建虚拟服务器,并根据配置启用对外的统一访问接口,并且基于相关插件脚本对服务进行监控。
	为了保证服务对外的统一接口的高可用,VRRP协议将物理Router进行统一管理,并创建一个虚拟路由地址,作为外网的统一出口,物理Router内部通过VRRP机制进行内部通信,保证虚拟路由地址永远可用。
2.1.2、核心概念
名称 解释 核心特点
虚拟路由器(Virtual Router) 由多台物理路由器组成的逻辑路由器,是 VRRP 的核心逻辑对象。对外提供统一的虚拟 IP(VIP)和虚拟 MAC 地址。终端把网关设置为这个 VIP,不需要感知后端多台真实设备。 虚拟 MAC 格式:00-00-5E-00-01-VRID;同一个 VRRP 组(相同 VRID)对应一个虚拟路由器
主路由器(Master) 虚拟路由器组内,承担流量转发工作的物理设备,通过优先级选举产生。优先级越大越优先。它会周期性发送 VRRP 通告报文,通知备路由器自己正常运行。 同一时刻,一个 VRRP 组只有一台 Master;只有 Master 发送 VRRP 通告报文
备路由器(Backup) 虚拟路由器组内处于待命状态的物理设备。正常情况下不转发流量,只监听 Master 发送的 VRRP 通告。如果长时间收不到通告,备路由器之间重新选举,优先级最高的升级为新 Master 接管业务。 平时只监听、不发通告;Master 故障后才会上位接管 VIP
2.1.3、基础概念
概念 英文全称 说明 关键参数 / 格式
VRRP Virtual Router Redundancy Protocol 虚拟路由冗余协议,IETF 标准(RFC 5798),三层协议,协议号 112 组播地址 224.0.0.18
VRID Virtual Router ID 虚拟路由器编号,同一组内设备必须相同 取值范围 0~255
虚拟路由器 Virtual Router 多台物理设备虚拟成的一台逻辑网关,对外共享一个 IP 和 MAC 由组内真实设备共同模拟
VIP Virtual IP Address 虚拟 IP,内网终端的网关地址,同一时刻只在一台 Master 上 可绑定在 Master 网卡上
虚拟 MAC Virtual MAC Address 虚拟路由器对外的 MAC 地址,固定格式 00:00:5e:00:01:VRID(如 VRID=5 → 00:00:5e:00:01:05)
Master 主路由器 真正转发流量的设备,周期性发 VRRP 通告 同一 VRRP 组内只有一台
Backup 备路由器 待命设备,只监听通告,不转发流量 收不到通告超时后竞选上位

2.2、keepalived部署与配置

2.2.1、keepalived部署
2.2.2.1、环境准备
序号 主机 ip 主机名 安装软件 系统版本 虚拟网络模型
1 10.0.0.13 Ubuntu24-13 keepalived Ubuntu24.04 NAT
2 10.0.0.16 Ubuntu24-16 keepalived Ubuntu24.04 NAT
2.2.2.2、apt安装
bash 复制代码
# 1. 查看当前源软件本版  #本次使用阿里源
[root@Ubuntu24-13:~]# apt list keepalived
Listing... Done
keepalived/noble 1:2.2.8-1build2 amd64

# 2. apt安装keepalived
[root@Ubuntu24-13:~]# apt install keepalived -y
[root@Ubuntu24-13:~]# systemctl status keepalived.service
○ keepalived.service - Keepalive Daemon (LVS and VRRP)
     Loaded: loaded (/usr/lib/systemd/system/keepalived.service; enabled; preset: enabled)
     Active: inactive (dead)
  Condition: start condition unmet at Tue 2026-10-27 02:51:50 UTC; 34s ago
             └─ ConditionFileNotEmpty=/etc/keepalived/keepalived.conf was not met
       Docs: man:keepalived(8)			# 服务配置文件默认没有需要手动创建/etc/keepalived/keepalived.conf
             man:keepalived.conf(5)
             man:genhash(1)
             https://keepalived.org
Oct 27 02:51:50 Ubuntu24-13 systemd[1]: keepalived.service - Keepalive Daemon (LVS and VRRP) was skipped >
[root@Ubuntu24-13:~]# cd /etc/keepalived/
[root@Ubuntu24-13:/etc/keepalived]# mv keepalived.conf.sample keepalived.conf
# 修改监听网卡
[root@Ubuntu24-13:/etc/keepalived]# sed -i 's/interface eth33/interface ens33/' keepalived.conf
[root@Ubuntu24-13:/etc/keepalived]# systemctl restart keepalived.service
[root@Ubuntu24-13:/etc/keepalived]# systemctl status keepalived.service | awk '/Active:/{print $2}'
active

# 3. apt卸载keepalived
[root@Ubuntu24-13:/etc/keepalived]# cd
[root@Ubuntu24-13:~]# apt purge keepalived
2.2.2.3、脚本编译安装keepalived
bash 复制代码
# 官方离线包:https://www.keepalived.org/software/keepalived-2.4.3.tar.gz
# 1. 脚本准备
[root@Ubuntu24-13:~]# cat keepalived_install.sh
#!/bin/bash
# *************************************
# * 功能: Shell脚本模板
# * 作者: 北京马哥教育王老师
# *************************************

# 定义日志文件路径
LOG_FILE="/var/log/keepalived_install.log"

# 定义环境变量
KEEPALIVED_VERSION="2.4.3"
KEEPALIVED_INSTALL_PATH="/data/server/keepalived"
KEEPALIVED_TAR_NAME="keepalived-${KEEPALIVED_VERSION}"
read -p "当前节点的角色(MASTER|BACKUP): " KEEPALIVED_ROLE

# 定义日志记录函数
function log() {
    local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    local message="$1"
    echo "[${timestamp}] ${message}" | tee -a ${LOG_FILE}
}

# 定义函数:基本环境定制
function setup_environment() {
    log "开始基本环境定制"
    echo "正在更新软件包列表..."
    apt update 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "软件包列表更新成功"
    else
        log "软件包列表更新失败"
        exit 1
    fi
    echo "正在安装必要的软件包..."
    apt -y install make gcc ipvsadm build-essential pkg-config automake autoconf libipset-dev libnl-3-dev libnl-genl-3-dev libssl-dev libxtables-dev libip4tc-dev libip6tc-dev libmagic-dev libsnmp-dev libglib2.0-dev libpcre2-dev libnftnl-dev libmnl-dev libsystemd-dev libpopt-dev daemon 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "必要软件包安装成功"
    else
        log "必要软件包安装失败"
        exit 1
    fi
}

# 定义函数:下载软件
function download_software() {
    log "开始下载软件"
    echo "正在创建目录并下载 Keepalived ${KEEPALIVED_VERSION}..."
    mkdir -p /data/{server,softs} 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "目录创建成功"
    else
        log "目录创建失败"
        exit 1
    fi
    cd /data/softs
        if [ ! -f ${KEEPALIVED_TAR_NAME}.tar.gz ]; then
        keepalived_url="https://www.keepalived.org/software/${KEEPALIVED_TAR_NAME}.tar.gz"
    wget "${keepalived_url}" 2>&1 | tee -a ${LOG_FILE}
        if [ $? -eq 0 ]; then
            log "Keepalived ${KEEPALIVED_VERSION} 下载成功"
        else
            log "Keepalived ${KEEPALIVED_VERSION} 下载失败"
            exit 1
        fi
        fi
    echo "正在解压 Keepalived ${KEEPALIVED_VERSION}..."
        untar_dir="/data/softs/${KEEPALIVED_TAR_NAME}"
        [ -d ${untar_dir} ] && rm -rf ${untar_dir}
    tar xvf "${KEEPALIVED_TAR_NAME}.tar.gz" 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "Keepalived ${KEEPALIVED_VERSION} 解压成功"
    else
        log "Keepalived ${KEEPALIVED_VERSION} 解压失败"
        exit 1
    fi
}

# 定义函数:编译安装
function compile_and_install() {
    log "开始编译安装"
    echo "正在进入解压目录并进行配置..."
    cd "${KEEPALIVED_TAR_NAME}"
    ./configure --prefix="${KEEPALIVED_INSTALL_PATH}" 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "配置成功,安装路径为 ${KEEPALIVED_INSTALL_PATH}"
    else
        log "配置失败,安装路径为 ${KEEPALIVED_INSTALL_PATH}"
        exit 1
    fi
    echo "正在编译 Keepalived ${KEEPALIVED_VERSION}..."
    make 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "编译成功"
    else
        log "编译失败"
        exit 1
    fi
    echo "正在安装 Keepalived ${KEEPALIVED_VERSION} 到 ${KEEPALIVED_INSTALL_PATH}..."
    make install 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "安装成功,安装路径为 ${KEEPALIVED_INSTALL_PATH}"
    else
        log "安装失败,安装路径为 ${KEEPALIVED_INSTALL_PATH}"
        exit 1
    fi
}

# 定义函数:定制服务文件
function customize_service_file() {
    log "开始定制服务文件"
    echo "正在复制服务文件..."
        cd /data/softs/${KEEPALIVED_TAR_NAME}/keepalived
    cp keepalived.service /lib/systemd/system/ 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "服务文件复制成功"
    else
        log "服务文件复制失败"
        exit 1
    fi
}

# 定义函数:定制配置文件
function customize_config_file() {
    log "开始定制配置文件"
    echo "正在定制配置文件..."
    cd "${KEEPALIVED_INSTALL_PATH}/etc/keepalived/"
    [ ! -d /etc/keepalived ] && mkdir /etc/keepalived || rm -rf /etc/keepalived/*
    mv keepalived.conf.sample /etc/keepalived/keepalived.conf 2>&1 | tee -a ${LOG_FILE}
    sed -i "/LVS_DEVEL/s#LVS_DEVEL#kp${KEEPALIVED_ROLE}#" /etc/keepalived/keepalived.conf
    net_name=$(ip a | awk -F " |:" '/MULTICAST/{print $3}'|head -n1)
    sed -i "s/eth0/${net_name}/g" /etc/keepalived/keepalived.conf
    sed -i '/virtual_server/,$d' /etc/keepalived/keepalived.conf
    if [ "${KEEPALIVED_ROLE}" == "BACKUP" ]; then
        sed -i 's/MASTER/BACKUP/' /etc/keepalived/keepalived.conf
        sed -i 's/ty 100/ty 90/' /etc/keepalived/keepalived.conf
    fi
    if [ $? -eq 0 ]; then
        log "配置文件定制成功,安装路径为 ${KEEPALIVED_INSTALL_PATH}"
    else
        log "配置文件定制失败,安装路径为 ${KEEPALIVED_INSTALL_PATH}"
        exit 1
    fi
}

# 定义函数:启动服务
function start_service() {
    log "开始启动服务"
    echo "正在重新加载 systemd 管理器配置..."
    systemctl daemon-reload 2>&1 | tee -a ${LOG_FILE}
    if [ $? -eq 0 ]; then
        log "systemd 管理器配置重新加载成功"
                systemctl start keepalived
    else
        log "systemd 管理器配置重新加载失败"
        exit 1
    fi
}

# 主函数,按顺序调用各个子函数
function main() {
    # 检查环境变量是否为空
    if [ -z "${KEEPALIVED_VERSION}" ]; then
        log "错误:KEEPALIVED_VERSION 环境变量为空"
        exit 1
    fi
    if [ -z "${KEEPALIVED_INSTALL_PATH}" ]; then
        log "错误:KEEPALIVED_INSTALL_PATH 环境变量为空"
        exit 1
    fi

    setup_environment
    download_software
    compile_and_install
    customize_service_file
    customize_config_file
    start_service
    log "Keepalived ${KEEPALIVED_VERSION} 安装及配置完成,安装路径为 ${KEEPALIVED_INSTALL_PATH}!"
    echo "Keepalived ${KEEPALIVED_VERSION} 安装及配置完成,安装路径为 ${KEEPALIVED_INSTALL_PATH}!"
}

# 调用主函数
main

# 2. 脚本安装
	# 主机13安装
[root@Ubuntu24-13:~]# /bin/bash keepalived_install.sh
当前节点的角色(MASTER|BACKUP): MASTER
[root@Ubuntu24-13:~]# systemctl status keepalived.service | awk '/Active:/{print $2}'
active
[root@Ubuntu24-13:~]# ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7c:2f:bd brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 10.0.0.13/24 brd 10.0.0.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 192.168.200.16/32 scope global ens33			# VIP
       valid_lft forever preferred_lft forever
    inet 192.168.200.17/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet 192.168.200.18/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7c:2fbd/64 scope link
       valid_lft forever preferred_lft forever

	# 主机16安装
[root@Ubuntu24-16:~]# /bin/bash keepalived_install.sh
当前节点的角色(MASTER|BACKUP): BACKUP
[root@Ubuntu24-16:~]# systemctl status keepalived.service | awk '/Active:/{print $2}'
active
[root@Ubuntu24-16:~]# ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:f0:6f:97 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 10.0.0.16/24 brd 10.0.0.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fef0:6f97/64 scope link
       valid_lft forever preferred_lft forever
2.2.2.4、配置文件修改
bash 复制代码
# 认识配置文件
! Configuration File for keepalived
# 全局定义块,配置全局参数
global_defs {
   router_id kpBACKUP       # 路由器标识,集群内每台主机ID要不一样,用于区分节点
}

# 定义VRRP实例 VI_1,一组VRRP高可用配置
vrrp_instance VI_1 {
    state BACKUP             # 本节点初始角色:BACKUP备节点;Master为主节点,角色最终由优先级选举决定
    interface ens33          # VRRP报文收发使用的物理网卡,必须为本机真实网卡
    virtual_router_id 51     # VRRP组ID(VRID),同一高可用集群所有节点VRID必须保持一致,取值0‑255
    priority 90              # 节点优先级,数值越大优先级越高;master一般设置100,backup设置90
    advert_int 1             # VRRRP通告报文发送间隔,单位秒,Master每隔1秒发送组播通告报文

    authentication {         # VRRRP组认证配置,同组所有节点密码必须一致
        auth_type PASS        # 认证类型:PASS简单明文密码认证
        auth_pass 1111       # VRRP认证密码,最多8位字符
    }

    virtual_ipaddress {      # 虚拟IP(VIP)配置,故障时会在主备节点之间漂移
        10.0.0.100           # 对外提供服务的虚拟IP地址
    }

    # Allow packets addressed to the VIPs above to be received
    accept                   # 开启accept模式,允许本机接收目的地址为VIP的数据包
}

# 1. 修改VIP地址
	# 13主机修改
[root@Ubuntu24-13:~]# vim /etc/keepalived/keepalived.conf
[root@Ubuntu24-13:~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpMASTER
}

vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100
    }

    # Allow packets addressed to the VIPs above to be received
    accept
}
[root@Ubuntu24-13:~]# systemctl restart keepalived.service
[root@Ubuntu24-13:~]# hostname -I
10.0.0.13 10.0.0.100		# .100就是vip

	# 16主机修改
[root@Ubuntu24-16:~]# vim /etc/keepalived/keepalived.conf
[root@Ubuntu24-16:~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpBACKUP
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100
    }

    # Allow packets addressed to the VIPs above to be received
    accept
}
[root@Ubuntu24-16:~]# systemctl restart keepalived.service
[root@Ubuntu24-16:~]# hostname -I
10.0.0.16
 
# 2. 选择VIP masts主机
	# 组播地址224.0.0.18 有masts地址、VRRP组ID、优先级priority
[root@Ubuntu24-16:~]# tcpdump -nn -i ens33 host 224.0.0.18
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
06:40:13.564823 IP 10.0.0.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
06:40:14.565670 IP 10.0.0.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
06:40:15.566553 IP 10.0.0.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
	# 选举测试,关闭13 主机的keep
	# 从13切换到16
	[root@Ubuntu24-13:~]# systemctl stop keepalived.service
	
	06:43:29.862417 IP 10.0.0.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 0, authtype simple, intvl 1s, length 20
	06:43:30.512246 IP 10.0.0.16 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 90, authtype simple, intvl 1s, length 20
	[root@Ubuntu24-16:~]# hostname -I
	10.0.0.16 10.0.0.100
	
	[root@Ubuntu24-13:~]# systemctl start keepalived.service
	# masts恢复到13主机
	06:45:06.598595 IP 10.0.0.16 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 90, authtype simple, intvl 1s, length 20
	06:45:07.125637 IP 10.0.0.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
	[root@Ubuntu24-13:~]# hostname -I
	10.0.0.13 10.0.0.100

# 3. 内外分流,选举和业务流
	# 13主机和16主机添加一个新的网卡,模式:仅主机
[root@Ubuntu24-13:~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 100
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group defau
    link/ether 00:0c:29:7c:2f:bd brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 10.0.0.13/24 brd 10.0.0.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7c:2fbd/64 scope link
       valid_lft forever preferred_lft forever
3: ens37: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:7c:2f:c7 brd ff:ff:ff:ff:ff:ff
    altname enp2s5
# 修改网卡
[root@Ubuntu24-13:~]# cd /etc/netplan/
[root@Ubuntu24-13:/etc/netplan]# ls
50-cloud-init.yaml
[root@Ubuntu24-13:/etc/netplan]# vim 50-cloud-init.yaml
[root@Ubuntu24-13:/etc/netplan]# cat 50-cloud-init.yaml
network:
  version: 2
  ethernets:
    ens33:
      addresses:
      - "10.0.0.13/24"
      nameservers:
        addresses:
        - 223.5.5.5
        - 223.6.6.6
        search: []
      routes:
      - to: "default"
        via: "10.0.0.2"
    ens37:
      addresses:
      - "192.168.8.13/24" # 根据自己VMware仅主机网卡范围填写
[root@Ubuntu24-13:/etc/netplan]# netplan apply
[root@Ubuntu24-13:/etc/netplan]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7c:2f:bd brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 10.0.0.13/24 brd 10.0.0.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.100/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7c:2fbd/64 scope link
       valid_lft forever preferred_lft forever
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7c:2f:c7 brd ff:ff:ff:ff:ff:ff
    altname enp2s5
    inet 192.168.8.13/24 brd 192.168.8.255 scope global ens37
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7c:2fc7/64 scope link
       valid_lft forever preferred_lft forever
# 修改keepalived配置文件
[root@Ubuntu24-13:/etc/netplan]# vim /etc/keepalived/keepalived.conf
[root@Ubuntu24-13:/etc/netplan]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpMASTER
}

vrrp_instance VI_1 {
    state MASTER
    interface ens37			# 选举网卡
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33		# 业务流量网卡
    }

    # Allow packets addressed to the VIPs above to be received
    accept
}
[root@Ubuntu24-13:/etc/netplan]# systemctl restart keepalived.service
[root@Ubuntu24-13:/etc/netplan]# hostname -I
10.0.0.13 10.0.0.100 192.168.8.13

# 16主机同上操作
[root@Ubuntu24-16:~]# cat /etc/netplan/50-cloud-init.yaml
network:
  version: 2
  ethernets:
    ens33:
      addresses:
      - "10.0.0.16/24"
      nameservers:
        addresses:
        - 223.5.5.5
        - 223.6.6.6
        search: []
      routes:
      - to: "default"
        via: "10.0.0.2"
    ens37:
      addresses:
      - "192.168.8.16/24"
[root@Ubuntu24-16:~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpBACKUP
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens37
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
}
[root@Ubuntu24-13:/etc/netplan]# netplan apply
[root@Ubuntu24-13:/etc/netplan]# systemctl restart keepalived.service
[root@Ubuntu24-16:~]# hostname -I
10.0.0.16 192.168.8.16
# 网卡ens37选举
[root@Ubuntu24-16:~]# tcpdump -nn -i ens37 host 224.0.0.18
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), snapshot length 262144 bytes
07:28:13.929677 IP 192.168.8.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
07:28:14.932061 IP 192.168.8.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
07:28:15.934210 IP 192.168.8.13 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
2.2.2、keepalived抢占模式
模式 配置关键字 原理 优点 缺点 适用场景
抢占模式(默认) 不写 nopreempt 高优先级节点恢复上线后,发现当前 Master 优先级比自己低,立刻发送 VRRP 通告,抢占 VIP,接管业务 故障恢复后,自动回到预设的主节点,符合预期架构 主节点恢复瞬间发生 VIP 漂移,业务短暂中断(闪断) 测试环境、业务对短暂闪断不敏感的场景
非抢占模式 nopreempt 高优先级节点启动 / 恢复后,不主动抢 VIP;VIP 会留在当前 Master,只有当前 Master 故障,它才接管 不会发生二次切换,业务稳定,无额外抖动 故障恢复后,业务不会自动切回原主节点,需要人工干预切换 生产环境,不允许业务二次闪断(最常用)
延时抢占模式 preempt_delay 300 (单位:秒,搭配 nopreempt 不能一起用) 高优先级节点恢复后,先等待设定的延时时间;等待期间持续监听 VRRP 报文,如果到期后对方优先级仍然更低,才发起抢占 给服务器、Nginx、数据库预留启动就绪时间,避免刚启动还没就绪就抢 VIP 依旧会抢占,只是延后抢占,延时期间业务正常 主节点服务启动慢(Nginx、中间件、数据库),防止服务没起来就接管 VIP
2.2.3、消息转递
bash 复制代码
# 1. 组播传递
[root@Ubuntu24-13:~]# vim /etc/keepalived/keepalived.conf
[root@Ubuntu24-13:~]# head -n 10 /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpMASTER
   vrrp_mcast_group4 226.0.0.18	# 默认224.0.0.18
}

vrrp_instance VI_1 {
    state MASTER
    interface ens37
# 16主机同上
[root@Ubuntu24-16:~]# tcpdump -nn -i ens37 host 226.0.0.18
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), snapshot length 262144 bytes
08:30:34.284549 IP 192.168.8.13 > 226.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20
08:30:35.285166 IP 192.168.8.13 > 226.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20

# 2. 单薄转递
[root@Ubuntu24-13:~]# systemctl restart keepalived.service
[root@Ubuntu24-13:~]# vim /etc/keepalived/keepalived.conf
[root@Ubuntu24-13:~]# grep -C 3 '192.168.8.16' /etc/keepalived/keepalived.conf
    priority 100
    unicast_src_ip 192.168.8.13		# 本地单播IP地址,本地网卡IP地址
    unicast_peer {
        192.168.8.16				# 对端单播IP地址,对端网卡地址
    }
    advert_int 1
    authentication {
[root@Ubuntu24-13:~]# systemctl restart keepalived.service

[root@Ubuntu24-16:~]# vim /etc/keepalived/keepalived.conf
[root@Ubuntu24-16:~]# grep -C 3 '192.168.8.13' /etc/keepalived/keepalived.conf
    advert_int 1
    unicast_src_ip 192.168.8.16
    unicast_peer {
        192.168.8.13
    }
    authentication {
        auth_type PASS
[root@Ubuntu24-16:~]# systemctl restart keepalived.service

[root@Ubuntu24-16:~]# tcpdump -nn -i ens37 host 192.168.8.13
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), snapshot length 262144 bytes
08:36:15.339758 IP 192.168.8.13 > 192.168.8.16: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20

# 当同时配置单播传递和组播传递时,单播优先级高
2.2.4、子配置文件
BASH 复制代码
# 13主机修改子配置
[root@Ubuntu24-13:~]# cd /etc/keepalived/
[root@Ubuntu24-13:/etc/keepalived]# mkdir conf.d
[root@Ubuntu24-13:/etc/keepalived]# cat -n keepalived.conf
     1  ! Configuration File for keepalived
     2
     3  global_defs {
     4     router_id kpMASTER
     5     vrrp_mcast_group4 226.0.0.18
     6  }
     7
     8  vrrp_instance VI_1 {
     9      state MASTER
    10      interface ens37
    11      virtual_router_id 51
    12      priority 100
    13      unicast_src_ip 192.168.8.13
    14      unicast_peer {
    15          192.168.8.16
    16      }
    17      advert_int 1
    18      authentication {
    19          auth_type PASS
    20          auth_pass 1111
    21      }
    22      virtual_ipaddress {
    23          10.0.0.100 dev ens33
    24      }
    25
    26      # Allow packets addressed to the VIPs above to be received
    27      accept
    28  }
[root@Ubuntu24-13:/etc/keepalived]# sed -n '8,28p' keepalived.conf > conf.d/client1.conf
[root@Ubuntu24-13:/etc/keepalived]# sed -i '8,28d' keepalived.conf
[root@Ubuntu24-13:/etc/keepalived]# cat keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpMASTER
   vrrp_mcast_group4 226.0.0.18
}


[root@Ubuntu24-13:/etc/keepalived]# cat conf.d/client1.conf
vrrp_instance VI_1 {
    state MASTER
    interface ens37
    virtual_router_id 51
    priority 100
    unicast_src_ip 192.168.8.13
    unicast_peer {
        192.168.8.16
    }
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
}
[root@Ubuntu24-13:/etc/keepalived]# sed -i '$a\include /etc/keepalived/conf.d/*.conf' keepalived.conf
[root@Ubuntu24-13:/etc/keepalived]# cat keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpMASTER
   vrrp_mcast_group4 226.0.0.18
}


include /etc/keepalived/conf.d/*.conf
[root@Ubuntu24-13:/etc/keepalived]# systemctl restart keepalived.service

# 16主机修改子配置
[root@Ubuntu24-16:~]# cd /etc/keepalived/
[root@Ubuntu24-16:/etc/keepalived]# mkdir conf.d
[root@Ubuntu24-16:/etc/keepalived]# sed -n '8,28p' keepalived.conf > conf.d/client1.conf
[root@Ubuntu24-16:/etc/keepalived]# sed -i '8,28d' keepalived.conf
[root@Ubuntu24-16:/etc/keepalived]# sed -i '$a\include /etc/keepalived/conf.d/*.conf' keepalived.conf
[root@Ubuntu24-16:/etc/keepalived]# cat keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id kpBACKUP
   vrrp_mcast_group4 226.0.0.18
}


include /etc/keepalived/conf.d/*.conf
[root@Ubuntu24-16:/etc/keepalived]# cat conf.d/client1.conf
vrrp_instance VI_1 {
    state BACKUP
    interface ens37
    virtual_router_id 51
    priority 90
    advert_int 1
    unicast_src_ip 192.168.8.16
    unicast_peer {
        192.168.8.13
    }
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
}
[root@Ubuntu24-16:/etc/keepalived]# systemctl restart keepalived.service
2.2.5、邮件推送
bash 复制代码
# 1. 准备脚本
[root@Ubuntu24-16:~]# cat send_message_by_email.sh
#!/bin/bash
# *************************************
# * 功能: Shell脚本模板
# * 作者: 北京马哥教育王老师
# *************************************

# 配置邮件相关信息
contact='000000y@qq.com'		# 告警接受邮箱地址
email_send='000000@qq.com'			# 告警发送邮箱地址
# qq登录点击头像找到账号与安全-安全设置,开启POP3/.... 服务(已开启),生成授权码并替换email_passwd内容
email_passwd='afegwrehajhadjecjhi'		
email_smtp_server='smtp.qq.com'

# 加载操作系统信息
. /etc/os-release

# 定义颜色输出函数
msg_error() {
    echo -e "\033[1;31m$1\033[0m"
}

msg_info() {
    echo -e "\033[1;32m$1\033[0m"
}

msg_warn() {
    echo -e "\033[1;33m$1\033[0m"
}

# 带颜色的状态输出函数
color() {
    RES_COL=60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    SETCOLOR_SUCCESS="echo -en \\033[1;32m"
    SETCOLOR_FAILURE="echo -en \\033[1;31m"
    SETCOLOR_WARNING="echo -en \\033[1;33m"
    SETCOLOR_NORMAL="echo -en \E[0m"

    echo -n "$1"
    $MOVE_TO_COL
    echo -n "["
    case $2 in
        success|0)
            $SETCOLOR_SUCCESS
            echo -n "  OK  "
            ;;
        failure|1)
            $SETCOLOR_FAILURE
            echo -n "FAILED"
            ;;
        *)
            $SETCOLOR_WARNING
            echo -n "WARNING"
            ;;
    esac
    $SETCOLOR_NORMAL
    echo -n "]"
    echo
}

# 安装 sendemail 工具
install_sendemail() {
    local package_installed=false
    case $ID in
        rhel|centos|rocky)
            if ! rpm -q sendemail &> /dev/null; then
                msg_info "正在安装 sendemail..."
                if yum install -y sendemail; then
                    package_installed=true
                else
                    msg_error "安装 sendemail 失败!"
                    exit 1
                fi
            else
                package_installed=true
            fi;;
        ubuntu)
            if ! dpkg -l | grep -q sendemail; then
                msg_info "正在更新软件源并安装 sendemail..."
                if apt update && apt install -y libio-socket-ssl-perl libnet-ssleay-perl sendemail; then
                    package_installed=true
                else
                    msg_error "安装 sendemail 失败!"
                    exit 1
                fi
            else
                package_installed=true
            fi;;
        *)
            msg_error "不支持此操作系统,退出!"
            exit 1;;
    esac
}

# 发送邮件函数
send_email() {
    local email_receive="$1"
    local email_subject="$2"
    local email_message="$3"

    # 验证邮件接收地址是否为空
    if [ -z "$email_receive" ]; then
        msg_error "邮件接收地址不能为空!"
        return 1
    fi

    sendemail -f "$email_send" -t "$email_receive" -u "$email_subject" -m "$email_message" -s "$email_smtp_server" -o message-charset=utf-8 -o tls=yes -xu "$email_send" -xp "$email_passwd"
    local send_status=$?
    if [ $send_status -eq 0 ]; then
        color "邮件发送成功!" 0
    else
        color "邮件发送失败!" 1
    fi
    return $send_status
}

# 通知函数
notify() {
    local state="$1"
    # 验证输入的状态是否合法
    if [[ $state =~ ^(master|backup|fault)$ ]]; then
        local mailsubject="$(hostname) to be $state, vip floating"
        local mailbody="$(date +'%F %T'): vrrp transition, $(hostname) changed to be $state"
        send_email "$contact" "$mailsubject" "$mailbody"
    else
        msg_error "Usage: $(basename $0) {master|backup|fault}"
        exit 1
    fi
}

# 主程序入口
main() {
    # 验证输入参数是否存在
    if [ $# -eq 0 ]; then
        msg_error "请提供脚本运行状态参数 {master|backup|fault}"
        exit 1
    fi

    install_sendemail
    notify "$1"
}

# 执行主函数,接收三个选项
main "$@"

# 两台主机测试
[root@Ubuntu24-16:~]# /bin/bash send_message_by_email.sh master
Oct 28 06:40:52 ubuntu24-16 sendemail[2360]: Email was sent successfully!
邮件发送成功!                                              [  OK  ]
[root@Ubuntu24-13:~]# /bin/bash send_message_by_email.sh master
Oct 28 06:55:18 ubuntu24-13 sendemail[2511]: Email was sent successfully!
邮件发送成功!                                              [  OK  ]

# 2. 将脚本拷贝并赋权到keepalived软件配置目录下
[root@Ubuntu24-13:~]# install send_message_by_email.sh /etc/keepalived/
[root@Ubuntu24-13:~]# ls /etc/keepalived/
conf.d  keepalived.conf  send_message_by_email.sh
[root@Ubuntu24-16:~]# install send_message_by_email.sh /etc/keepalived/
[root@Ubuntu24-16:~]# ls /etc/keepalived/
conf.d  keepalived.conf  send_message_by_email.sh

# 配置告警语句
[root@Ubuntu24-13:~]# sed -i '/accept/a\    notify_master "/etc/keepalived/send_message_by_email.sh fault"' /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-13:~]# sed -i '/accept/a\    notify_master "/etc/keepalived/send_message_by_email.sh backup"' /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-13:~]# sed -i '/accept/a\    notify_master "/etc/keepalived/send_message_by_email.sh master"' /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-13:~]# systemctl restart keepalived.service


[root@Ubuntu24-16:~]# sed -i '/accept/a\    notify_master "/etc/keepalived/send_message_by_email.sh fault"' /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-16:~]# sed -i '/accept/a\    notify_master "/etc/keepalived/send_message_by_email.sh backup"' /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-16:~]# sed -i '/accept/a\    notify_master "/etc/keepalived/send_message_by_email.sh master"' /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-16:~]# systemctl restart keepalived.service

# 邮箱会有以下告警

2.3、keepalived进阶

2.3.1、环境准备
bash 复制代码
# 另外准备两台系统Ubuntu24.04
# 1. 安装环境
[root@Ubuntu24-19:~]# cat onekey_install_ruoyi_ubuntu24.sh
#!/bin/bash
# *************************************
# * 功能: Shell一键部署单机版Ruoyi-vue
# * 作者: 北京马哥教育王老师
# *************************************
# set -euo pipefail

# ====================== 全局自定义变量 ======================
MYSQL_ROOT_PWD="Root@2026"
RUOYI_DB="ry_vue"
RUOYI_USER="ruoyi"
RUOYI_PWD="Ruoyi@123"
REDIS_PWD="Redis@2026"
APP_PORT=8080
WEB_DOMAIN="ruoyi.magedu.com"
BASE_DIR="/data/ruoyi"
SOURCE_DIR="/root/RuoYi-Vue"
RUOYI_SERVICE="/etc/systemd/system/ruoyi-admin.service"
# ===========================================================

# 日志打印函数
log_info() {
    echo -e "\033[32m===== $1 =====\033[0m"
}

# 1. 系统更新 & 基础工具安装
func_sys_init() {
    log_info "系统更新并安装基础工具 git curl"
    apt update -y
    apt install -y git curl
}

# 2. 安装 JDK17 并配置全局 JAVA_HOME
func_install_jdk() {
    log_info "安装 JDK17"
    apt install openjdk-17-jdk -y
    echo "export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> /etc/profile
    echo "export PATH=\$JAVA_HOME/bin:\$PATH" >> /etc/profile
    source /etc/profile
}

# 3. Maven 安装 + 阿里镜像加速
func_install_maven() {
    log_info "安装 Maven 并配置阿里云镜像"
    apt install maven -y
    mkdir -p /root/.m2
    cat > /root/.m2/settings.xml <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<settings>
  <mirrors>
    <mirror>
      <id>aliyun</id>
      <mirrorOf>central</mirrorOf>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
  </mirrors>
</settings>
EOF
}

# 4. Node20 + npm 淘宝源
func_install_node() {
    log_info "安装 Node20 前端打包环境"
    curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
    apt install nodejs -y
    npm config set registry https://registry.npmmirror.com
}

# 5. Nginx 安装,清理默认站点
func_install_nginx() {
    log_info "安装 Nginx"
    apt install nginx -y
    systemctl enable --now nginx
    rm -f /etc/nginx/sites-enabled/default
    mkdir -p /etc/nginx/conf.d
}

# 6. Redis 单机本地仅127.0.0.1访问
func_install_redis() {
    log_info "安装并配置本地 Redis"
    apt install redis-server -y
    sed -i 's/^bind .*/bind 127.0.0.1/' /etc/redis/redis.conf
    sed -i '/^requirepass /d' /etc/redis/redis.conf
    sed -i '/# requirepass/a\requirepass "'${REDIS_PWD}'"' /etc/redis/redis.conf
    sed -i 's/^protected-mode .*/protected-mode yes/' /etc/redis/redis.conf
    systemctl restart redis-server
}

# 7. MySQL8 单机安装 + root初始化
func_install_mysql() {
    log_info "安装 MySQL8 单机服务"
    apt install mysql-server -y
    systemctl enable --now mysql
    mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PWD}';FLUSH PRIVILEGES;"
}

# 8. 创建若依数据库、业务账号
func_init_mysql_db() {
    log_info "初始化若依数据库与业务账号"
    mysql -uroot -p${MYSQL_ROOT_PWD} -e "
CREATE DATABASE IF NOT EXISTS ${RUOYI_DB} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '${RUOYI_USER}'@'localhost' IDENTIFIED BY '${RUOYI_PWD}';
GRANT ALL ON ${RUOYI_DB}.* TO '${RUOYI_USER}'@'localhost';
FLUSH PRIVILEGES;" 2>/dev/null
}

# 9. 拉取源码 & 导入初始化SQL
func_get_source_and_import_sql() {
    log_info "拉取 RuoYi-Vue 源码"
    cd /root
    [ ! -d "RuoYi-Vue" ] && git clone https://gitee.com/y_project/RuoYi-Vue.git
    cd ${SOURCE_DIR}

    log_info "导入系统初始化SQL"
    mysql -uroot -p${MYSQL_ROOT_PWD} ${RUOYI_DB} < sql/ry_*.sql
}

# 10. 仅修改配置连接参数(sed替换,不覆盖完整yml)
func_modify_config() {
    log_info "修改数据库、Redis连接配置(仅替换参数,保留原有全部配置)"
    cd ${SOURCE_DIR}

    # ========== application-druid.yml 修改本地MySQL ==========
    DRUID_YML="ruoyi-admin/src/main/resources/application-druid.yml"
    sed -i "s|url: jdbc:mysql://.*:3306/.*?|url: jdbc:mysql://127.0.0.1:3306/${RUOYI_DB}?|" ${DRUID_YML}
        sed -i 's|useSSL=true|useSSL=false\&allowPublicKeyRetrieval=true|' ${DRUID_YML}
    sed -i "/master:/,/password:/s|        username: .*|        username: ${RUOYI_USER}|" ${DRUID_YML}
    sed -i "/master:/,/slave:/s|        password: .*|        password: ${RUOYI_PWD}|" ${DRUID_YML}

    # ========== application.yml 修改Redis、上传路径、服务端口 ==========
    APP_YML="ruoyi-admin/src/main/resources/application.yml"
    sed -i "s|profile: .*|profile: ${BASE_DIR}/uploadPath|g" ${APP_YML}
    sed -i "s/host: .*/host: 127.0.0.1/g" ${APP_YML}
    sed -i '/redis:/,/timeout:/s/\s*password:.*/      password: '"${REDIS_PWD}"'/' ${APP_YML}
}

# 11. Maven打包后端,部署Jar包
func_build_backend() {
    log_info "Maven打包后端项目"
    cd ${SOURCE_DIR}
    mvn clean package -Dmaven.test.skip=true

    log_info "迁移Jar至部署目录"
    mkdir -p ${BASE_DIR}/server ${BASE_DIR}/uploadPath
    cp ruoyi-admin/target/ruoyi-admin.jar ${BASE_DIR}/server/
}

# 12. 前端打包,部署静态资源
func_build_frontend() {
    log_info "前端打包生产静态资源"
        cd ${SOURCE_DIR}
        git checkout -b ruoyi-3.9.2 tags/v3.9.2
    cd ${SOURCE_DIR}/ruoyi-ui
    npm install
    npm run build:prod

    log_info "部署前端dist目录"
    mkdir -p ${BASE_DIR}/web
    cp -r dist ${BASE_DIR}/web/
}

# 13. 创建后端 systemd 托管服务
func_create_systemd() {
    log_info "创建 ruoyi-admin systemd 服务"
    cat > "${RUOYI_SERVICE}" <<EOF
[Unit]
Description=RuoYi-Vue Backend Admin Service
After=network.target mysql.service redis-server.service

[Service]
User=root
WorkingDirectory=${BASE_DIR}/server
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar ruoyi-admin.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable --now ruoyi-admin
}

# 14. Nginx站点反向代理配置
func_config_nginx() {
    log_info "生成 Nginx 若依站点配置"
    cat > /etc/nginx/conf.d/ruoyi.conf <<EOF
server {
    listen 80;
    server_name ${WEB_DOMAIN};
    root ${BASE_DIR}/web/dist;
    index index.html;

    location / {
        try_files \$uri \$uri/ /index.html;
    }
    location ^~ /prod-api/ {
        proxy_pass http://127.0.0.1:${APP_PORT}/;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
    location /profile/ {
        proxy_pass http://127.0.0.1:${APP_PORT}/profile/;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
    }
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1d;
        add_header Cache-Control "public";
    }
}
EOF
    nginx -t
    systemctl reload nginx
}

# 15. 部署完成提示
func_finish_tips() {
    log_info "==================== RuoYi-Vue 单机部署全部完成 ===================="
    echo "后端服务端口:${APP_PORT}"
    echo "前端访问地址:http://${WEB_DOMAIN}"
    echo "后端实时日志:journalctl -u ruoyi-admin -f"
    echo "重启后端服务:systemctl restart ruoyi-admin"
    echo "MySQL数据库:${RUOYI_DB} 账号:${RUOYI_USER} 密码:${RUOYI_PWD}"
    echo "Redis本地连接密码:${REDIS_PWD}"
        echo "清理环境的话,可以执行如下命令"
        echo "apt purge nginx* redis-* mysql-* -y"
        echo "rm -rf /data/ruoyi ${RUOYI_SERVICE} ${SOURCE_DIR}"
}

# ===================== 主执行流程 =====================
main() {
    func_sys_init
    func_install_jdk
    func_install_maven
    func_install_node
    func_install_nginx
    func_install_redis
    func_install_mysql
    func_init_mysql_db
    func_get_source_and_import_sql
    func_modify_config
    func_build_backend
    func_build_frontend
    func_create_systemd
    func_config_nginx
    func_finish_tips
}

# 启动入口
main


# 安装ruoyi
[root@Ubuntu24-22:~]# cat onekey_install_ruoyi_ubuntu24.sh
#!/bin/bash
# *************************************
# * 功能: Shell一键部署单机版Ruoyi-vue
# * 作者: 北京马哥教育王老师
# *************************************
# set -euo pipefail

# ====================== 全局自定义变量 ======================
MYSQL_ROOT_PWD="Root@2026"
RUOYI_DB="ry_vue"
RUOYI_USER="ruoyi"
RUOYI_PWD="Ruoyi@123"
REDIS_PWD="Redis@2026"
APP_PORT=8080
WEB_DOMAIN="ruoyi.magedu.com"
BASE_DIR="/data/ruoyi"
SOURCE_DIR="/root/RuoYi-Vue"
RUOYI_SERVICE="/etc/systemd/system/ruoyi-admin.service"
# ===========================================================

# 日志打印函数
log_info() {
    echo -e "\033[32m===== $1 =====\033[0m"
}

# 1. 系统更新 & 基础工具安装
func_sys_init() {
    log_info "系统更新并安装基础工具 git curl"
    apt update -y
    apt install -y git curl
}

# 2. 安装 JDK17 并配置全局 JAVA_HOME
func_install_jdk() {
    log_info "安装 JDK17"
    apt install openjdk-17-jdk -y
    echo "export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> /etc/profile
    echo "export PATH=\$JAVA_HOME/bin:\$PATH" >> /etc/profile
    source /etc/profile
}

# 3. Maven 安装 + 阿里镜像加速
func_install_maven() {
    log_info "安装 Maven 并配置阿里云镜像"
    apt install maven -y
    mkdir -p /root/.m2
    cat > /root/.m2/settings.xml <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<settings>
  <mirrors>
    <mirror>
      <id>aliyun</id>
      <mirrorOf>central</mirrorOf>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
  </mirrors>
</settings>
EOF
}

# 4. Node20 + npm 淘宝源
func_install_node() {
    log_info "安装 Node20 前端打包环境"
    curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
    apt install nodejs -y
    npm config set registry https://registry.npmmirror.com
}

# 5. Nginx 安装,清理默认站点
func_install_nginx() {
    log_info "安装 Nginx"
    apt install nginx -y
    systemctl enable --now nginx
    rm -f /etc/nginx/sites-enabled/default
    mkdir -p /etc/nginx/conf.d
}

# 6. Redis 单机本地仅127.0.0.1访问
func_install_redis() {
    log_info "安装并配置本地 Redis"
    apt install redis-server -y
    sed -i 's/^bind .*/bind 127.0.0.1/' /etc/redis/redis.conf
    sed -i '/^requirepass /d' /etc/redis/redis.conf
    sed -i '/# requirepass/a\requirepass "'${REDIS_PWD}'"' /etc/redis/redis.conf
    sed -i 's/^protected-mode .*/protected-mode yes/' /etc/redis/redis.conf
    systemctl restart redis-server
}

# 7. MySQL8 单机安装 + root初始化
func_install_mysql() {
    log_info "安装 MySQL8 单机服务"
    apt install mysql-server -y
    systemctl enable --now mysql
    mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PWD}';FLUSH PRIVILEGES;"
}

# 8. 创建若依数据库、业务账号
func_init_mysql_db() {
    log_info "初始化若依数据库与业务账号"
    mysql -uroot -p${MYSQL_ROOT_PWD} -e "
CREATE DATABASE IF NOT EXISTS ${RUOYI_DB} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '${RUOYI_USER}'@'localhost' IDENTIFIED BY '${RUOYI_PWD}';
GRANT ALL ON ${RUOYI_DB}.* TO '${RUOYI_USER}'@'localhost';
FLUSH PRIVILEGES;" 2>/dev/null
}

# 9. 拉取源码 & 导入初始化SQL
func_get_source_and_import_sql() {
    log_info "拉取 RuoYi-Vue 源码"
    cd /root
    [ ! -d "RuoYi-Vue" ] && git clone https://gitee.com/y_project/RuoYi-Vue.git
    cd ${SOURCE_DIR}

    log_info "导入系统初始化SQL"
    mysql -uroot -p${MYSQL_ROOT_PWD} ${RUOYI_DB} < sql/ry_*.sql
}

# 10. 仅修改配置连接参数(sed替换,不覆盖完整yml)
func_modify_config() {
    log_info "修改数据库、Redis连接配置(仅替换参数,保留原有全部配置)"
    cd ${SOURCE_DIR}

    # ========== application-druid.yml 修改本地MySQL ==========
    DRUID_YML="ruoyi-admin/src/main/resources/application-druid.yml"
    sed -i "s|url: jdbc:mysql://.*:3306/.*?|url: jdbc:mysql://127.0.0.1:3306/${RUOYI_DB}?|" ${DRUID_YML}
        sed -i 's|useSSL=true|useSSL=false\&allowPublicKeyRetrieval=true|' ${DRUID_YML}
    sed -i "/master:/,/password:/s|        username: .*|        username: ${RUOYI_USER}|" ${DRUID_YML}
    sed -i "/master:/,/slave:/s|        password: .*|        password: ${RUOYI_PWD}|" ${DRUID_YML}

    # ========== application.yml 修改Redis、上传路径、服务端口 ==========
    APP_YML="ruoyi-admin/src/main/resources/application.yml"
    sed -i "s|profile: .*|profile: ${BASE_DIR}/uploadPath|g" ${APP_YML}
    sed -i "s/host: .*/host: 127.0.0.1/g" ${APP_YML}
    sed -i '/redis:/,/timeout:/s/\s*password:.*/      password: '"${REDIS_PWD}"'/' ${APP_YML}
}

# 11. Maven打包后端,部署Jar包
func_build_backend() {
    log_info "Maven打包后端项目"
    cd ${SOURCE_DIR}
    mvn clean package -Dmaven.test.skip=true

    log_info "迁移Jar至部署目录"
    mkdir -p ${BASE_DIR}/server ${BASE_DIR}/uploadPath
    cp ruoyi-admin/target/ruoyi-admin.jar ${BASE_DIR}/server/
}

# 12. 前端打包,部署静态资源
func_build_frontend() {
    log_info "前端打包生产静态资源"
        cd ${SOURCE_DIR}
        git checkout -b ruoyi-3.9.2 tags/v3.9.2
    cd ${SOURCE_DIR}/ruoyi-ui
    npm install
    npm run build:prod

    log_info "部署前端dist目录"
    mkdir -p ${BASE_DIR}/web
    cp -r dist ${BASE_DIR}/web/
}

# 13. 创建后端 systemd 托管服务
func_create_systemd() {
    log_info "创建 ruoyi-admin systemd 服务"
    cat > "${RUOYI_SERVICE}" <<EOF
[Unit]
Description=RuoYi-Vue Backend Admin Service
After=network.target mysql.service redis-server.service

[Service]
User=root
WorkingDirectory=${BASE_DIR}/server
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar ruoyi-admin.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable --now ruoyi-admin
}

# 14. Nginx站点反向代理配置
func_config_nginx() {
    log_info "生成 Nginx 若依站点配置"
    cat > /etc/nginx/conf.d/ruoyi.conf <<EOF
server {
    listen 80;
    server_name ${WEB_DOMAIN};
    root ${BASE_DIR}/web/dist;
    index index.html;

    location / {
        try_files \$uri \$uri/ /index.html;
    }
    location ^~ /prod-api/ {
        proxy_pass http://127.0.0.1:${APP_PORT}/;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
    location /profile/ {
        proxy_pass http://127.0.0.1:${APP_PORT}/profile/;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
    }
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1d;
        add_header Cache-Control "public";
    }
}
EOF
    nginx -t
    systemctl reload nginx
}

# 15. 部署完成提示
func_finish_tips() {
    log_info "==================== RuoYi-Vue 单机部署全部完成 ===================="
    echo "后端服务端口:${APP_PORT}"
    echo "前端访问地址:http://${WEB_DOMAIN}"
    echo "后端实时日志:journalctl -u ruoyi-admin -f"
    echo "重启后端服务:systemctl restart ruoyi-admin"
    echo "MySQL数据库:${RUOYI_DB} 账号:${RUOYI_USER} 密码:${RUOYI_PWD}"
    echo "Redis本地连接密码:${REDIS_PWD}"
        echo "清理环境的话,可以执行如下命令"
        echo "apt purge nginx* redis-* mysql-* -y"
        echo "rm -rf /data/ruoyi ${RUOYI_SERVICE} ${SOURCE_DIR}"
}

# ===================== 主执行流程 =====================
main() {
    func_sys_init
    func_install_jdk
    func_install_maven
    func_install_node
    func_install_nginx
    func_install_redis
    func_install_mysql
    func_init_mysql_db
    func_get_source_and_import_sql
    func_modify_config
    func_build_backend
    func_build_frontend
    func_create_systemd
    func_config_nginx
    func_finish_tips
}

# 启动入口
main
[root@Ubuntu24-19:~]# /bin/bash onekey_install_ruoyi_ubuntu24.sh4.sh
[root@Ubuntu24-22:~]# /bin/bash onekey_install_ruoyi_ubuntu24.sh

[root@Ubuntu24-19:~]# systemctl status ruoyi-admin.service
● ruoyi-admin.service - RuoYi-Vue Backend Admin Service
     Loaded: loaded (/etc/systemd/system/ruoyi-admin.service; enabled; preset: enabled)
     Active: active (running) since Wed 2026-10-28 08:34:16 UTC; 39s ago
   Main PID: 1321 (java)
      Tasks: 142 (limit: 4543)
     Memory: 469.8M (peak: 470.1M)
        CPU: 40.243s
     CGroup: /system.slice/ruoyi-admin.service
             └─1321 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar ruoyi-admin.jar

Oct 28 08:34:38 Ubuntu24-19 java[1321]: (♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  .-------.       ____     __
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  |  _ _   \      \   \   /  /
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  | ( ' )  |       \  _. /  '
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  |(_ o _) /        _( )_ .'
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  | (_,_).' __  ___(_ o _)'
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  |  |\ \  |  ||   |(_,_)'
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  |  | \ `'   /|   `-'  /
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  |  |  \    /  \      /
Oct 28 08:34:38 Ubuntu24-19 java[1321]:  ''-'   `'-'    `-..-'
[root@Ubuntu24-19:~]# /bin/bash lvs_dr_backend_server.sh start
请输入LVS DR模式VIP地址(默认10.0.0.100):
The RS Server is Ready!
[root@Ubuntu24-19:~]# ip a s lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.0.0.100/32 scope global lo:1
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever


[root@Ubuntu24-22:~]# systemctl status ruoyi-admin.service
● ruoyi-admin.service - RuoYi-Vue Backend Admin Service
     Loaded: loaded (/etc/systemd/system/ruoyi-admin.service; enabled; preset: enabled)
     Active: active (running) since Wed 2026-10-28 08:18:15 UTC; 57s ago
   Main PID: 7260 (java)
      Tasks: 142 (limit: 4543)
     Memory: 393.8M (peak: 400.3M)
        CPU: 25.058s
     CGroup: /system.slice/ruoyi-admin.service
             └─7260 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar ruoyi-admin.jar

Oct 28 08:18:28 Ubuntu24-22 java[7260]: (♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  .-------.       ____     __
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  |  _ _   \      \   \   /  /
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  | ( ' )  |       \  _. /  '
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  |(_ o _) /        _( )_ .'
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  | (_,_).' __  ___(_ o _)'
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  |  |\ \  |  ||   |(_,_)'
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  |  | \ `'   /|   `-'  /
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  |  |  \    /  \      /
Oct 28 08:18:28 Ubuntu24-22 java[7260]:  ''-'   `'-'    `-..-'

[root@Ubuntu24-22:~]# /bin/bash lvs_dr_backend_server.sh start
请输入LVS DR模式VIP地址(默认10.0.0.100):
The RS Server is Ready!
[root@Ubuntu24-22:~]# ip a s lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.0.0.100/32 scope global lo:1
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever

[root@Ubuntu24-19:~]# echo '10.0.0.19 nginx-RS1' > /data/ruoyi/web/dist/test.html
[root@Ubuntu24-19:~]# curl 10.0.0.19/test.html
10.0.0.19 nginx-RS1
[root@Ubuntu24-22:~]# echo '10.0.0.22 nginx-RS2' > /data/ruoyi/web/dist/test.html
[root@Ubuntu24-22:~]# curl 10.0.0.22/test.html
10.0.0.22 nginx-RS2
2.3.2、添加RS主机
bash 复制代码
# 注释
# virtual_server 定义LVS虚拟服务,对应VIP+端口,LVS的VS(Virtual Server)
virtual_server 10.0.0.100 80 {
    delay_loop 2                 # 服务轮询间隔时间,单位秒;每隔2秒对real_server做健康检查
    lb_algo rr                   # 负载均衡调度算法 rr = round‑robin 轮询,依次分发请求
    lb_kind DR                   # LVS工作模式:DR直接路由模式;另外还有NAT、TUN模式
    protocol TCP                 # 调度的传输层协议,此处为TCP协议80端口web服务

    # 后端真实服务器RS1,IP:端口,业务真实提供服务节点
    real_server 10.0.0.19 80 {
    }
    # 后端真实服务器RS2,IP:端口,另一台业务节点
    real_server 10.0.0.22 80 {
    }
}
# 1. 添加RS主机
[root@Ubuntu24-13:~]# vim /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-13:~]# tail -n 10 /etc/keepalived/conf.d/client1.conf
virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    real_server 10.0.0.19 80 {
    }
    real_server 10.0.0.22 80 {
    }
}
[root@Ubuntu24-13:~]# systemctl restart keepalived.service
[root@Ubuntu24-13:~]# hostname -I
10.0.0.13 10.0.0.100 192.168.8.13

[root@Ubuntu24-16:~]# vim /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-16:~]# tail -n 10 /etc/keepalived/conf.d/client1.conf
virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    real_server 10.0.0.19 80 {
    }
    real_server 10.0.0.22 80 {
    }
}
[root@Ubuntu24-16:~]# systemctl restart keepalived.service
[root@Ubuntu24-16:~]# hostname -I
10.0.0.16 192.168.8.16

# 测试 另外一台主机访问vip
[root@Rocky10-6 ~]# curl 10.0.0.100/test.html
10.0.0.22 nginx-RS2
[root@Rocky10-6 ~]# curl 10.0.0.100/test.html
10.0.0.19 nginx-RS1
[root@Rocky10-6 ~]# curl 10.0.0.100/test.html
10.0.0.22 nginx-RS2
[root@Rocky10-6 ~]# curl 10.0.0.100/test.html
10.0.0.19 nginx-RS1

# 可以发现两个VIP主机都有ipvsadm策略了
[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          0
  -> 10.0.0.22:80                 Route   1      0          0
2.3.3、HTTP检测
bash 复制代码
# 准备另外一台主机
[root@xyx:~]# apt install nginx -y
[root@xyx:~]# echo 'Ubuntu24-7 Error Web Page' > /var/www/html/test.html
[root@xyx:~]# systemctl restart nginx.service
[root@xyx:~]# curl 10.0.0.7/test.html
Ubuntu24-7 Error Web Page
[root@xyx:~]# /bin/bash lvs_dr_backend_server.sh start
请输入LVS DR模式VIP地址(默认10.0.0.100):
The RS Server is Ready!
[root@xyx:~]# curl 10.0.0.100/test.html
Ubuntu24-7 Error Web Page


# 1. 添加http检测
[root@Ubuntu24-13:~]# vim /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-13:~]# tail -30 /etc/keepalived/conf.d/client1.conf
virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    sorry_server 10.0.0.7 80
    real_server 10.0.0.19 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
    real_server 10.0.0.22 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
}
[root@Ubuntu24-13:~]# systemctl restart keepalived.service
[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          0
  -> 10.0.0.22:80                 Route   1      0          0



[root@Ubuntu24-16:~]# vim /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-16:~]# tail -30 /etc/keepalived/conf.d/client1.conf

virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    sorry_server 10.0.0.7 80
    real_server 10.0.0.19 80 {
      HTTP_GET {
        url {
        path /
        status_code 200
      }
        connect_timeout 1
        nb_get_retry 1
        delay_before_retry 1
      }
    }
    real_server 10.0.0.22 80 {
      HTTP_GET {
        url {
        path /
        status_code 200
      }
        connect_timeout 1
        nb_get_retry 1
        delay_before_retry 1
      }
    }
}
[root@Ubuntu24-16:~]# systemctl restart keepalived.service
[root@Ubuntu24-16:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          0
  -> 10.0.0.22:80                 Route   1      0          0

[root@Rocky10-6 ~]# while true;do curl 10.0.0.100/test.html; sleep 0.4; done
10.0.0.22 nginx-RS2

# 测试
[root@Rocky10-6 ~]# while true;do curl 10.0.0.100/test.html; sleep 0.4; done  # 长检测
10.0.0.19 nginx-RS1
10.0.0.22 nginx-RS2
10.0.0.19 nginx-RS1
10.0.0.22 nginx-RS2
10.0.0.19 nginx-RS1
10.0.0.22 nginx-RS2

# 关闭19主机的nginx服务
[root@Ubuntu24-19:~]# systemctl stop nginx.service

10.0.0.22 nginx-RS2
10.0.0.22 nginx-RS2
10.0.0.22 nginx-RS2
10.0.0.22 nginx-RS2
10.0.0.22 nginx-RS2
10.0.0.22 nginx-RS2

# keep检测到19主机的http服务丢失自动去除19主机的规则
[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.22:80                 Route   1      0          288

# 关闭22主机的nginx服务
[root@Ubuntu24-22:~]# systemctl stop nginx.service


Ubuntu24-7 Error Web Page
Ubuntu24-7 Error Web Page
Ubuntu24-7 Error Web Page
Ubuntu24-7 Error Web Page

# keep检测到22主机的http服务丢失自动去除19主机的规则,并启动sorry_server服务器
[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.7:80                  Route   1      0          102

# 开启nginx恢复正常
[root@Ubuntu24-19:~]# systemctl start nginx.service
[root@Ubuntu24-22:~]# systemctl start nginx.service

10.0.0.22 nginx-RS2
10.0.0.19 nginx-RS1
10.0.0.22 nginx-RS2
10.0.0.19 nginx-RS1
10.0.0.22 nginx-RS2
10.0.0.19 nginx-RS1

[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          147
  -> 10.0.0.22:80                 Route   1      0          145
2.3.4、TCP检测
bash 复制代码
# 修改MySQL监听地址
[root@Ubuntu24-19:~]# vim /etc/mysql/mysql.conf.d/mysqld.cnf
[root@Ubuntu24-19:~]# grep '0.0.0.0' /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address            = 0.0.0.0
mysqlx-bind-address     = 0.0.0.0
[root@Ubuntu24-19:~]# systemctl restart mysql.service
[root@Ubuntu24-19:~]# netstat -tnlp | grep mysql
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      2053/mysqld
tcp        0      0 0.0.0.0:33060           0.0.0.0:*               LISTEN      2053/mysqld

[root@Ubuntu24-22:~]# vim /etc/mysql/mysql.conf.d/mysqld.cnf
[root@Ubuntu24-22:~]# grep '0.0.0.0' /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address            = 0.0.0.0
mysqlx-bind-address     = 0.0.0.0
[root@Ubuntu24-22:~]# systemctl restart mysql.service
[root@Ubuntu24-22:~]# netstat -tnlp | grep mysql
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      2064/mysqld
tcp        0      0 0.0.0.0:33060           0.0.0.0:*               LISTEN      2064/mysqld

# 创建测试账号
[root@Ubuntu24-19:~]# mysql <<EOF
create user 'myuser'@'10.0.0.%' identified by 'Xyx@1234';
create user 'myuser'@'localhost' identified by 'Xyx@1234';
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'10.0.0.%';
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'localhost';
flush privileges;
EOF
[root@Ubuntu24-19:~]# mysql -umyuser -p'Xyx@1234' -h 10.0.0.19 -e 'show variables like "%hostname%";'
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-19 |
+---------------+-------------+
[root@Ubuntu24-19:~]#

[root@Ubuntu24-22:~]#  mysql <<EOF
create user 'myuser'@'10.0.0.%' identified by 'Xyx@1234';
create user 'myuser'@'localhost' identified by 'Xyx@1234';
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'10.0.0.%';
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'localhost';
flush privileges;
EOF
+---------------+-------------+
[root@Ubuntu24-22:~]# mysql -umyuser -p'Xyx@1234' -h 10.0.0.22 -e 'show variables like "%hostname%";'
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-22 |
+---------------+-------------+


# 安装MySQL客户端
[root@Ubuntu24-13:~]# apt install mariadb-client
[root@Ubuntu24-16:~]# apt install mariadb-client

[root@Ubuntu24-13:~]#  mysql -umyuser -p'Xyx@1234' -h 10.0.0.19 -e 'show variables like "%hostname%";'
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-19 |
+---------------+-------------+
[root@Ubuntu24-13:~]#  mysql -umyuser -p'Xyx@1234' -h 10.0.0.22 -e 'show variables like "%hostname%";'
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-22 |
+---------------+-------------+

# 1. 配置TCP检测
[root@Ubuntu24-13:~]# vim /etc/keepalived/conf.d/client1.conf
# 最后面添加
[root@Ubuntu24-13:~]# tail -n 23 /etc/keepalived/conf.d/client1.conf
virtual_server 10.0.0.100 3306 {
    delay_loop 2                # 健康检查周期,每2秒探测一次后端RS
    lvs_sched rr                # 调度算法:rr 轮询
    lb_kind DR                  # LVS模式:DR直接路由模式
    protocol TCP                # 协议:TCP(MySQL是3306 TCP)

    real_server 10.0.0.19 3306 {
        TCP_CHECK {             # 四层端口健康检查,只探测端口通断
            connect_timeout 1   # 连接超时5秒
            nb_get_retry 1      # 失败重试3次
            delay_before_retry 1 # 失败后等待3秒再重试
            connect_port 3306  # 探测端口3306
        }
    }
    real_server 10.0.0.22 3306 {
        TCP_CHECK {
            connect_timeout 1
            nb_get_retry 1
            delay_before_retry 1
            connect_port 3306
        }
    }
}
[root@Ubuntu24-13:~]# systemctl restart keepalived.service
# 可以观察到有两个集群
[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          0
  -> 10.0.0.22:80                 Route   1      0          0
TCP  10.0.0.100:3306 rr
  -> 10.0.0.19:3306               Route   1      0          0
  -> 10.0.0.22:3306               Route   1      0          0
[root@Ubuntu24-13:~]#


[root@Ubuntu24-16:~]# vim /etc/keepalived/conf.d/client1.conf
[root@Ubuntu24-16:~]# tail -n 25 /etc/keepalived/conf.d/client1.conf

virtual_server 10.0.0.100 3306 {
    delay_loop 2                # 健康检查周期,每2秒探测一次后端RS
    lvs_sched rr                # 调度算法:rr 轮询
    lb_kind DR                  # LVS模式:DR直接路由模式
    protocol TCP                # 协议:TCP(MySQL是3306 TCP)

    real_server 10.0.0.19 3306 {
        TCP_CHECK {             # 四层端口健康检查,只探测端口通断
            connect_timeout 5   # 连接超时5秒
            nb_get_retry 3      # 失败重试3次
            delay_before_retry 3 # 失败后等待3秒再重试
            connect_port 3306  # 探测端口3306
        }
    }
    real_server 10.0.0.22 3306 {
        TCP_CHECK {
            connect_timeout 5
            nb_get_retry 3
            delay_before_retry 3
            connect_port 3306
        }
    }
}

[root@Ubuntu24-16:~]# systemctl restart keepalived.service

[root@Ubuntu24-16:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          0
  -> 10.0.0.22:80                 Route   1      0          0
TCP  10.0.0.100:3306 rr
  -> 10.0.0.19:3306               Route   1      0          0
  -> 10.0.0.22:3306               Route   1      0          0

# 客户端安装MySQL客户端
[root@Rocky10-6 ~]# dnf install mysql8.4  #rocky系统安装,ubuntu可以安装13主机安装
[root@Rocky10-6 ~]# mysql -umyuser -p'Xyx@1234' -h 10.0.0.100 -e 'show variables like "%hostname%";'
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-22 |
+---------------+-------------+
[root@Rocky10-6 ~]# mysql -umyuser -p'Xyx@1234' -h 10.0.0.100 -e 'show variables like "%hostname%";'
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-19 |
+---------------+-------------+

# 2. 测试
[root@Ubuntu24-22:~]# systemctl stop mysql.service
[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          31
  -> 10.0.0.22:80                 Route   1      0          31
TCP  10.0.0.100:3306 rr
  -> 10.0.0.19:3306               Route   1      0          0
# 恢复
[root@Ubuntu24-22:~]# systemctl start mysql.service
[root@Ubuntu24-13:~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          128
  -> 10.0.0.22:80                 Route   1      0          129
TCP  10.0.0.100:3306 rr
  -> 10.0.0.19:3306               Route   1      0          0
  -> 10.0.0.22:3306               Route   1      0          0


!M)Z1m0z^B6b
2.3.5、双主模式
bash 复制代码
# 网站13主机为主16主机为辅,MySQL16主机为主13主机为辅

# 13主机配置双主模式
[root@Ubuntu24-13:~]# cd /etc/keepalived/conf.d/
[root@Ubuntu24-13:/etc/keepalived/conf.d]# ls
client1.conf
# 创建nginx和MySQL配置文件
[root@Ubuntu24-13:/etc/keepalived/conf.d]# cp client1.conf client2.conf
[root@Ubuntu24-13:/etc/keepalived/conf.d]# vim client1.conf
[root@Ubuntu24-13:/etc/keepalived/conf.d]# cat client1.conf
vrrp_instance VI_1 {
    state MASTER
    interface ens37
    virtual_router_id 51
    priority 100
    unicast_src_ip 192.168.8.13
    unicast_peer {
        192.168.8.16
    }
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
    notify_master "/etc/keepalived/send_message_by_email.sh master"
    notify_master "/etc/keepalived/send_message_by_email.sh backup"
    notify_master "/etc/keepalived/send_message_by_email.sh fault"
}

virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    sorry_server 10.0.0.7 80
    real_server 10.0.0.19 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
    real_server 10.0.0.22 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
}
[root@Ubuntu24-13:/etc/keepalived/conf.d]# vim client2.conf
[root@Ubuntu24-13:/etc/keepalived/conf.d]# cat client2.conf
vrrp_instance VI_2 {
    state BACKUP
    interface ens37
    virtual_router_id 50
    priority 90
    unicast_src_ip 192.168.8.13
    unicast_peer {
        192.168.8.16
    }
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.200 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
    notify_master "/etc/keepalived/send_message_by_email.sh master"
    notify_master "/etc/keepalived/send_message_by_email.sh backup"
    notify_master "/etc/keepalived/send_message_by_email.sh fault"
}

virtual_server 10.0.0.200 3306 {
    delay_loop 2                # 健康检查周期,每2秒探测一次后端RS
    lvs_sched rr                # 调度算法:rr 轮询
    lb_kind DR                  # LVS模式:DR直接路由模式
    protocol TCP                # 协议:TCP(MySQL是3306 TCP)

    real_server 10.0.0.19 3306 {
        TCP_CHECK {             # 四层端口健康检查,只探测端口通断
            connect_timeout 1   # 连接超时5秒
            nb_get_retry 1      # 失败重试3次
            delay_before_retry 1 # 失败后等待3秒再重试
            connect_port 3306  # 探测端口3306
        }
    }
    real_server 10.0.0.22 3306 {
        TCP_CHECK {
            connect_timeout 1
            nb_get_retry 1
            delay_before_retry 1
            connect_port 3306
        }
    }
}
[root@Ubuntu24-13:/etc/keepalived/conf.d]# systemctl restart keepalived.service



# 16主机配置双主机
[root@Ubuntu24-16:~]# cd /etc/keepalived/conf.d/
[root@Ubuntu24-16:/etc/keepalived/conf.d]# ls
client1.conf
# 创建nginx和MySQL配置文件
[root@Ubuntu24-16:/etc/keepalived/conf.d]# cp client1.conf client2.conf
[root@Ubuntu24-16:/etc/keepalived/conf.d]# vim client1.conf
[root@Ubuntu24-16:/etc/keepalived/conf.d]# cat client1.conf
vrrp_instance VI_1 {
    state BACKUP
    interface ens37
    virtual_router_id 51
    priority 90
    advert_int 1
    unicast_src_ip 192.168.8.16
    unicast_peer {
        192.168.8.13
    }
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
    notify_master "/etc/keepalived/send_message_by_email.sh master"
    notify_master "/etc/keepalived/send_message_by_email.sh backup"
    notify_master "/etc/keepalived/send_message_by_email.sh fault"
}
virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    sorry_server 10.0.0.7 80
    real_server 10.0.0.19 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
    real_server 10.0.0.22 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
}


[root@Ubuntu24-16:/etc/keepalived/conf.d]# vim client2.conf
[root@Ubuntu24-16:/etc/keepalived/conf.d]# cat client2.conf
vrrp_instance VI_2 {
    state MASTER
    interface ens37
    virtual_router_id 50
    priority 100
    advert_int 1
    unicast_src_ip 192.168.8.16
    unicast_peer {
        192.168.8.13
    }
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.200 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
    notify_master "/etc/keepalived/send_message_by_email.sh master"
    notify_master "/etc/keepalived/send_message_by_email.sh backup"
    notify_master "/etc/keepalived/send_message_by_email.sh fault"
}

virtual_server 10.0.0.200 3306 {
    delay_loop 2                # 健康检查周期,每2秒探测一次后端RS
    lvs_sched rr                # 调度算法:rr 轮询
    lb_kind DR                  # LVS模式:DR直接路由模式
    protocol TCP                # 协议:TCP(MySQL是3306 TCP)

    real_server 10.0.0.19 3306 {
        TCP_CHECK {             # 四层端口健康检查,只探测端口通断
            connect_timeout 5   # 连接超时5秒
            nb_get_retry 3      # 失败重试3次
            delay_before_retry 3 # 失败后等待3秒再重试
            connect_port 3306  # 探测端口3306
        }
    }
    real_server 10.0.0.22 3306 {
        TCP_CHECK {
            connect_timeout 5
            nb_get_retry 3
            delay_before_retry 3
            connect_port 3306
        }
    }
}
[root@Ubuntu24-13:/etc/keepalived/conf.d]# systemctl restart keepalived.service

[root@Ubuntu24-13:~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7c:2f:bd brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 10.0.0.13/24 brd 10.0.0.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.100/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7c:2fbd/64 scope link
       valid_lft forever preferred_lft forever
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7c:2f:c7 brd ff:ff:ff:ff:ff:ff
    altname enp2s5
    inet 192.168.8.13/24 brd 192.168.8.255 scope global ens37
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7c:2fc7/64 scope link
       valid_lft forever preferred_lft forever

[root@Ubuntu24-16:~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:ca:bd:25 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 10.0.0.16/24 brd 10.0.0.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.200/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:feca:bd25/64 scope link
       valid_lft forever preferred_lft forever
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:ca:bd:2f brd ff:ff:ff:ff:ff:ff
    altname enp2s5
    inet 192.168.8.16/24 brd 192.168.8.255 scope global ens37
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:feca:bd2f/64 scope link
       valid_lft forever preferred_lft forever

# 后端真实主机增加vip
[root@Ubuntu24-19:~]# ifconfig lo:2 10.0.0.200 netmask 255.255.255.255
[root@Ubuntu24-19:~]# ip a s lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.0.0.100/32 scope global lo:1
       valid_lft forever preferred_lft forever
    inet 10.0.0.200/32 scope global lo:2
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
[root@Ubuntu24-22:~]# ifconfig lo:2 10.0.0.200 netmask 255.255.255.255
[root@Ubuntu24-22:~]# ip a s lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.0.0.100/32 scope global lo:1
       valid_lft forever preferred_lft forever
    inet 10.0.0.200/32 scope global lo:2
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
[root@xyx:~]# ifconfig lo:2 10.0.0.200 netmask 255.255.255.255
[root@xyx:~]# ip a s lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.0.0.100/32 scope global lo:1
       valid_lft forever preferred_lft forever
    inet 10.0.0.200/32 scope global lo:2
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever


# 测试
[root@Rocky10-6 ~]# mysql -umyuser -p'Xyx@1234' -h 10.0.0.100 -e 'show variables like "%hostname%";'
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.100:3306' (111)
[root@Rocky10-6 ~]# mysql -umyuser -p'Xyx@1234' -h 10.0.0.200 -e 'show variables like "%hostname%";'
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-22 |
+---------------+-------------+
[root@Rocky10-6 ~]# mysql -umyuser -p'Xyx@1234' -h 10.0.0.200 -e 'show variables like "%hostname%";'
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| hostname      | Ubuntu24-19 |
+---------------+-------------+
[root@Rocky10-6 ~]# while true;do curl 10.0.0.100/test.html; sleep 0.4; done
10.0.0.22 nginx-RS2
10.0.0.19 nginx-RS1
10.0.0.22 nginx-RS2

三、项目改造

3.1、NFS后端改造

bash 复制代码
[root@Ubuntu24-22:~]# apt install nfs-kernel-server -y
[root@Ubuntu24-22:~]# mkdir -p /nfs/{ruoyi_web,ruoyi_uploadPath,ruoyi_server}
[root@Ubuntu24-22:~]# chmod 777 /nfs/*
[root@Ubuntu24-22:~]# chown nobody:nogroup /nfs/*
[root@Ubuntu24-22:~]# vim /etc/exports
[root@Ubuntu24-22:~]# tail -4 /etc/exports
/nfs/ruoyi_web 10.0.0.0/24(rw,sync,no_subtree_check,no_root_squash)
/nfs/ruoyi_uploadPath 10.0.0.0/24(rw,sync,no_subtree_check,no_root_squash)
/nfs/ruoyi_server 10.0.0.0/24(rw,sync,no_subtree_check,no_root_squash)
[root@Ubuntu24-22:~]# exportfs -arv
exporting 10.0.0.0/24:/nfs/ruoyi_server
exporting 10.0.0.0/24:/nfs/ruoyi_uploadPath
exporting 10.0.0.0/24:/nfs/ruoyi_web
[root@Ubuntu24-22:~]# systemctl enable --now nfs-kernel-server
Synchronizing state of nfs-kernel-server.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable nfs-kernel-server
[root@Ubuntu24-22:~]# showmount -e 10.0.0.22
Export list for 10.0.0.22:
/nfs/ruoyi_server     10.0.0.0/24
/nfs/ruoyi_uploadPath 10.0.0.0/24
/nfs/ruoyi_web        10.0.0.0/24

3.2、redis后端改造

bash 复制代码
[root@Ubuntu24-22:~]# systemctl disable --now redis-server.service
[root@Ubuntu24-19:~]# vim /etc/redis/redis.conf
[root@Ubuntu24-19:~]# grep -E "^bind" /etc/redis/redis.conf
bind 0.0.0.0
[root@Ubuntu24-19:~]# systemctl restart redis-server.service
[root@Ubuntu24-19:~]# red
red              redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli        redis-server
[root@Ubuntu24-19:~]# redis-cli -a Redis@2026 ping
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
PONG
[root@Ubuntu24-19:~]# redis-cli -a Redis@2026 -h 10.0.0.19 ping
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
PONG
[root@Ubuntu24-19:~]#

3.3、MySQL后端改造

bash 复制代码
[root@Ubuntu24-22:~]# systemctl disable --now mysql.service
Synchronizing state of mysql.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install disable mysql
Removed "/etc/systemd/system/multi-user.target.wants/mysql.service".
[root@Ubuntu24-19:~]# vim /etc/mysql/mysql.conf.d/mysqld.cnf
[root@Ubuntu24-19:~]# grep -E '^bind-|^mysqlx-' /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address            = 0.0.0.0
mysqlx-bind-address     = 0.0.0.0
[root@Ubuntu24-19:~]# systemctl restart mysql.service
[root@Ubuntu24-19:~]# mysql -e "select user,host from mysql.user where user='ruoyi';"
+-------+-----------+
| user  | host      |
+-------+-----------+
| ruoyi | localhost |
+-------+-----------+
[root@Ubuntu24-19:~]# mysql <<eof
CREATE USER IF NOT EXISTS 'ruoyi'@'10.0.0.%' IDENTIFIED BY 'Ruoyi@123';
GRANT ALL ON ry_vue.* TO 'ruoyi'@'10.0.0.%';
FLUSH PRIVILEGES;
eof
[root@Ubuntu24-19:~]# mysql -e "select user,host from mysql.user where user='ruoyi';"
+-------+-----------+
| user  | host      |
+-------+-----------+
| ruoyi | 10.0.0.%  |
| ruoyi | localhost |
+-------+-----------+
[root@Ubuntu24-19:~]#

3.4、ruoyi改造

3.4.1、19主机后端改造
bash 复制代码
[root@Ubuntu24-19:~]# apt install nfs-common -y
[root@Ubuntu24-19:~]# showmount -e 10.0.0.22
Export list for 10.0.0.22:
/nfs/ruoyi_server     10.0.0.0/24
/nfs/ruoyi_uploadPath 10.0.0.0/24
/nfs/ruoyi_web        10.0.0.0/24
[root@Ubuntu24-19:~]# mkdir /backup
[root@Ubuntu24-19:~]# mv /data/ruoyi /backup/
[root@Ubuntu24-19:~]# mkdir -p /data/ruoyi/{web,uploadPath,server,file} -p
[root@Ubuntu24-19:~]# vim /etc/fstab
[root@Ubuntu24-19:~]# tail -3 /etc/fstab
10.0.0.22:/nfs/ruoyi_web        /data/ruoyi/web         nfs     defaults,_netdev 0 0
10.0.0.22:/nfs/ruoyi_uploadPath /data/ruoyi/uploadPath  nfs     defaults,_netdev 0 0
10.0.0.22:/nfs/ruoyi_server     /data/ruoyi/file        nfs     defaults,_netdev 0 0
[root@Ubuntu24-19:~]# systemctl daemon-reload
[root@Ubuntu24-19:~]# mount -a
[root@Ubuntu24-19:~]# df -h | grep /data/ruoyi
10.0.0.22:/nfs/ruoyi_web            47G  8.5G   37G  20% /data/ruoyi/web
10.0.0.22:/nfs/ruoyi_uploadPath     47G  8.5G   37G  20% /data/ruoyi/uploadPath
10.0.0.22:/nfs/ruoyi_server         47G  8.5G   37G  20% /data/ruoyi/file
[root@Ubuntu24-19:~]# cd RuoYi-Vue/
[root@Ubuntu24-19:~/RuoYi-Vue]# vim ruoyi-admin/src/main/resources/application.yml
[root@Ubuntu24-19:~/RuoYi-Vue]# grep -C 3 'host: 10.0.0.19' ruoyi-admin/src/main/resources/application.yml    # redis 配置
    redis:
      # 地址
      host: 10.0.0.19
      # 端口,默认为6379
      port: 6379
      # 数据库索引
[root@Ubuntu24-19:~/RuoYi-Vue]# vim ruoyi-admin/src/main/resources/application-druid.yml
[root@Ubuntu24-19:~/RuoYi-Vue]# grep -C 3 '10.0.0.19' ruoyi-admin/src/main/resources/application-druid.yml
        druid:
            # 主库数据源
            master:
                url: jdbc:mysql://10.0.0.19:3306/ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
                username: ruoyi
                password: Ruoyi@123
            # 从库数据源
[root@Ubuntu24-19:~/RuoYi-Vue]# mvn clean package -Dmaven.test.skip=true
[root@Ubuntu24-19:~/RuoYi-Vue]# ls ruoyi-admin/target/ruoyi-admin.jar
ruoyi-admin/target/ruoyi-admin.jar
[root@Ubuntu24-19:~/RuoYi-Vue]# cp ruoyi-admin/target/ruoyi-admin.jar /data/ruoyi/server/
[root@Ubuntu24-19:~/RuoYi-Vue]# cp ruoyi-admin/target/ruoyi-admin.jar /data/ruoyi/file/
[root@Ubuntu24-19:~/RuoYi-Vue]# cp /etc/systemd/system/ruoyi-admin.service /data/ruoyi/file/
[root@Ubuntu24-19:~/RuoYi-Vue]# systemctl restart ruoyi-admin.service
[root@Ubuntu24-19:~/RuoYi-Vue]# systemctl status ruoyi-admin.service
● ruoyi-admin.service - RuoYi-Vue Backend Admin Service
     Loaded: loaded (/etc/systemd/system/ruoyi-admin.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-11-02 01:32:09 UTC; 1min 27s ago
   Main PID: 3518 (java)
      Tasks: 142 (limit: 4543)
     Memory: 336.4M (peak: 341.6M)
        CPU: 23.985s
     CGroup: /system.slice/ruoyi-admin.service
             └─3518 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar ruoyi-admin.jar

Nov 02 01:32:21 Ubuntu24-19 java[3518]: (♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  .-------.       ____     __
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  |  _ _   \      \   \   /  /
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  | ( ' )  |       \  _. /  '
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  |(_ o _) /        _( )_ .'
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  | (_,_).' __  ___(_ o _)'
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  |  |\ \  |  ||   |(_,_)'
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  |  | \ `'   /|   `-'  /
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  |  |  \    /  \      /
Nov 02 01:32:21 Ubuntu24-19 java[3518]:  ''-'   `'-'    `-..-'
[root@Ubuntu24-19:~/RuoYi-Vue]# netstat -tunlp | grep 8080
tcp6       0      0 :::8080                 :::*                    LISTEN      3518/java
[root@Ubuntu24-19:~/RuoYi-Vue]# cp a /backup/ruoyi/web/dist/ /data/ruoyi/web/
cp: cannot stat 'a': No such file or directory
cp: -r not specified; omitting directory '/backup/ruoyi/web/dist/'
[root@Ubuntu24-19:~/RuoYi-Vue]# cp -a /backup/ruoyi/web/dist/ /data/ruoyi/web/
[root@Ubuntu24-19:~/RuoYi-Vue]# ls /data/ruoyi/web/
dist
[root@Ubuntu24-19:~/RuoYi-Vue]# cp /etc/nginx/conf.d/ruoyi.conf /data/ruoyi/file/
[root@Ubuntu24-19:~/RuoYi-Vue]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@Ubuntu24-19:~/RuoYi-Vue]# systemctl restart nginx.service
3.4.2、22主机后端改造
bash 复制代码
[root@Ubuntu24-22:~]# apt install nfs-common -y
[root@Ubuntu24-22:~]# showmount -e 10.0.0.22
Export list for 10.0.0.22:
/nfs/ruoyi_server     10.0.0.0/24
/nfs/ruoyi_uploadPath 10.0.0.0/24
/nfs/ruoyi_web        10.0.0.0/24
[root@Ubuntu24-22:~]# # mkdir /backup
[root@Ubuntu24-22:~]# mv /data/ruoyi /backup
[root@Ubuntu24-22:~]# mkdir -p /data/ruoyi/{web,uploadPath,server,file} -p
[root@Ubuntu24-22:~]# df -h
Filesystem                         Size  Used Avail Use% Mounted on
tmpfs                              387M  1.6M  386M   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv   47G  8.6G   36G  20% /
tmpfs                              1.9G     0  1.9G   0% /dev/shm
tmpfs                              5.0M     0  5.0M   0% /run/lock
/dev/sda2                          2.0G  104M  1.7G   6% /boot
tmpfs                              387M   16K  387M   1% /run/user/0
[root@Ubuntu24-22:~]# vim /etc/fstab
[root@Ubuntu24-22:~]# tail -3 /etc/fstab
10.0.0.22:/nfs/ruoyi_web        /data/ruoyi/web         nfs     defaults,_netdev 0 0
10.0.0.22:/nfs/ruoyi_uploadPath /data/ruoyi/uploadPath  nfs     defaults,_netdev 0 0
10.0.0.22:/nfs/ruoyi_server     /data/ruoyi/file        nfs     defaults,_netdev 0 0
[root@Ubuntu24-22:~]# systemctl daemon-reload
[root@Ubuntu24-22:~]# mount -a
[root@Ubuntu24-22:~]# df -h | grep ruoyi
10.0.0.22:/nfs/ruoyi_web            47G  8.6G   36G  20% /data/ruoyi/web
10.0.0.22:/nfs/ruoyi_uploadPath     47G  8.6G   36G  20% /data/ruoyi/uploadPath
10.0.0.22:/nfs/ruoyi_server         47G  8.6G   36G  20% /data/ruoyi/file
[root@Ubuntu24-22:~]# cp /data/ruoyi/file/ruoyi-admin.jar /data/ruoyi/server/
[root@Ubuntu24-22:~]# systemctl restart ruoyi-admin.service
[root@Ubuntu24-22:~]# systemctl status ruoyi-admin.service
● ruoyi-admin.service - RuoYi-Vue Backend Admin Service
     Loaded: loaded (/etc/systemd/system/ruoyi-admin.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-11-02 01:45:25 UTC; 22s ago
   Main PID: 4238 (java)
      Tasks: 142 (limit: 4543)
     Memory: 357.4M (peak: 358.2M)
        CPU: 22.561s
     CGroup: /system.slice/ruoyi-admin.service
             └─4238 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar ruoyi-admin.jar

Nov 02 01:45:36 Ubuntu24-22 java[4238]: (♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  .-------.       ____     __
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  |  _ _   \      \   \   /  /
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  | ( ' )  |       \  _. /  '
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  |(_ o _) /        _( )_ .'
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  | (_,_).' __  ___(_ o _)'
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  |  |\ \  |  ||   |(_,_)'
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  |  | \ `'   /|   `-'  /
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  |  |  \    /  \      /
Nov 02 01:45:36 Ubuntu24-22 java[4238]:  ''-'   `'-'    `-..-'
[root@Ubuntu24-22:~]# netstat -tunlp | grep 8080
tcp6       0      0 :::8080                 :::*                    LISTEN      4238/java
[root@Ubuntu24-22:~]# ls /data/ruoyi/web/
dist
[root@Ubuntu24-22:~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@Ubuntu24-22:~]# systemctl restart nginx.service
3.4.3、25主机后端改造
bash 复制代码
# 先使用之前的安装ruoyi的安装脚本
[root@UBuntu24-25:~]# /bin/bash onekey_install_ruoyi_ubuntu24.sh
[root@UBuntu24-25:~]# systemctl disable --now mysql.service
Synchronizing state of mysql.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install disable mysql
Removed "/etc/systemd/system/multi-user.target.wants/mysql.service".
^[[A[root@UBuntu24-25:~]# systemctl disable --now redis-server.service
Synchronizing state of redis-server.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install disable redis-server
Removed "/etc/systemd/system/multi-user.target.wants/redis-server.service".
Removed "/etc/systemd/system/redis.service".
[root@UBuntu24-25:~]# apt install nfs-common -y
[root@UBuntu24-25:~]# showmount -e 10.0.0.22
Export list for 10.0.0.22:
/nfs/ruoyi_server     10.0.0.0/24
/nfs/ruoyi_uploadPath 10.0.0.0/24
/nfs/ruoyi_web        10.0.0.0/24
[root@UBuntu24-25:~]# mkdir /backup
[root@UBuntu24-25:~]# mv /data/ruoyi /backup/
[root@UBuntu24-25:~]# mkdir -p /data/ruoyi/{web,uploadPath,server,file} -p
[root@UBuntu24-25:~]# vim /etc/fstab
[root@UBuntu24-25:~]# tail -3 /etc/fstab
10.0.0.22:/nfs/ruoyi_web        /data/ruoyi/web         nfs     defaults,_netdev 0 0
10.0.0.22:/nfs/ruoyi_uploadPath /data/ruoyi/uploadPath  nfs     defaults,_netdev 0 0
10.0.0.22:/nfs/ruoyi_server     /data/ruoyi/file        nfs     defaults,_netdev 0 0
[root@UBuntu24-25:~]# systemctl daemon-reload
[root@UBuntu24-25:~]# mount -a
[root@UBuntu24-25:~]# df -h | grep ruoyi
10.0.0.22:/nfs/ruoyi_web            47G  8.7G   36G  20% /data/ruoyi/web
10.0.0.22:/nfs/ruoyi_uploadPath     47G  8.7G   36G  20% /data/ruoyi/uploadPath
10.0.0.22:/nfs/ruoyi_server         47G  8.7G   36G  20% /data/ruoyi/file
[root@UBuntu24-25:~]# cp /data/ruoyi/file/ruoyi-admin.jar /data/ruoyi/server/
[root@UBuntu24-25:~]# systemctl restart ruoyi-admin.service
[root@UBuntu24-25:~]# systemctl status ruoyi-admin.service
● ruoyi-admin.service - RuoYi-Vue Backend Admin Service
     Loaded: loaded (/etc/systemd/system/ruoyi-admin.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-11-02 01:51:27 UTC; 1min 56s ago
   Main PID: 3770 (java)
      Tasks: 143 (limit: 4543)
     Memory: 405.4M (peak: 416.4M)
        CPU: 25.288s
     CGroup: /system.slice/ruoyi-admin.service
             └─3770 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar ruoyi-admin.jar

Nov 02 01:51:40 UBuntu24-25 java[3770]: (♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙
Nov 02 01:51:40 UBuntu24-25 java[3770]:  .-------.       ____     __
Nov 02 01:51:40 UBuntu24-25 java[3770]:  |  _ _   \      \   \   /  /
Nov 02 01:51:40 UBuntu24-25 java[3770]:  | ( ' )  |       \  _. /  '
Nov 02 01:51:40 UBuntu24-25 java[3770]:  |(_ o _) /        _( )_ .'
Nov 02 01:51:40 UBuntu24-25 java[3770]:  | (_,_).' __  ___(_ o _)'
Nov 02 01:51:40 UBuntu24-25 java[3770]:  |  |\ \  |  ||   |(_,_)'
Nov 02 01:51:40 UBuntu24-25 java[3770]:  |  | \ `'   /|   `-'  /
Nov 02 01:51:40 UBuntu24-25 java[3770]:  |  |  \    /  \      /
Nov 02 01:51:40 UBuntu24-25 java[3770]:  ''-'   `'-'    `-..-'
[root@UBuntu24-25:~]# ls /data/ruoyi/web/
dist
[root@UBuntu24-25:~]# cp /data/ruoyi/file/ruoyi.conf /etc/nginx/conf.d/
[root@UBuntu24-25:~]# rm -f /etc/nginx/sites-enabled/default
[root@UBuntu24-25:~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@UBuntu24-25:~]# systemctl restart nginx.service

3.5、keepalived改造

bash 复制代码
[root@Ubuntu24-19:~]# /bin/bash lvs_dr_backend_server.sh start
请输入LVS DR模式VIP地址(默认10.0.0.100):
The RS Server is Ready!
[root@Ubuntu24-22:~]# /bin/bash lvs_dr_backend_server.sh start
请输入LVS DR模式VIP地址(默认10.0.0.100):
The RS Server is Ready!
[root@Ubuntu24-25:~]# /bin/bash lvs_dr_backend_server.sh start
请输入LVS DR模式VIP地址(默认10.0.0.100):
The RS Server is Ready!

[root@Ubuntu24-13:~]# cd /etc/keepalived/conf.d/
[root@Ubuntu24-13:/etc/keepalived/conf.d]# ls
client1.conf  client2.conf
[root@Ubuntu24-13:/etc/keepalived/conf.d]# rm -rf client2.conf
[root@Ubuntu24-13:/etc/keepalived/conf.d]# vim client1.conf
[root@Ubuntu24-13:/etc/keepalived/conf.d]# cat client1.conf
vrrp_instance VI_1 {
    state MASTER
    interface ens37
    virtual_router_id 51
    priority 100
    unicast_src_ip 192.168.8.13
    unicast_peer {
        192.168.8.16
    }
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
    notify_master "/etc/keepalived/send_message_by_email.sh master"
    notify_master "/etc/keepalived/send_message_by_email.sh backup"
    notify_master "/etc/keepalived/send_message_by_email.sh fault"
}

virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    sorry_server 10.0.0.7 80
    real_server 10.0.0.19 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
    real_server 10.0.0.22 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
    real_server 10.0.0.25 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
}
[root@Ubuntu24-13:/etc/keepalived/conf.d]# systemctl restart keepalived.service
[root@Ubuntu24-13:/etc/keepalived/conf.d]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          0
  -> 10.0.0.22:80                 Route   1      0          0
  -> 10.0.0.25:80                 Route   1      0          0

[root@Ubuntu24-16:~]# cd /etc/keepalived/conf.d/
[root@Ubuntu24-16:/etc/keepalived/conf.d]# ls
client1.conf  client2.conf
[root@Ubuntu24-16:/etc/keepalived/conf.d]# rm -rf client2.conf
[root@Ubuntu24-16:/etc/keepalived/conf.d]# vim client1.conf
[root@Ubuntu24-16:/etc/keepalived/conf.d]# cat client1.conf
vrrp_instance VI_1 {
    state BACKUP
    interface ens37
    virtual_router_id 51
    priority 90
    advert_int 1
    unicast_src_ip 192.168.8.16
    unicast_peer {
        192.168.8.13
    }
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.100 dev ens33
    }

    # Allow packets addressed to the VIPs above to be received
    accept
    notify_master "/etc/keepalived/send_message_by_email.sh master"
    notify_master "/etc/keepalived/send_message_by_email.sh backup"
    notify_master "/etc/keepalived/send_message_by_email.sh fault"
}
virtual_server 10.0.0.100 80 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    protocol TCP
    sorry_server 10.0.0.7 80
    real_server 10.0.0.19 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
    real_server 10.0.0.22 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
    real_server 10.0.0.25 80 {
        HTTP_GET {
                url {
                path /                # 健康检查访问的URL路径:访问根路径 /
                status_code 200       # 要求HTTP返回码为200才判定后端正常
        }
        connect_timeout 1         # 建立TCP连接超时时间,单位秒
        nb_get_retry 1            # 健康检查失败后的重试次数:重试1次
        delay_before_retry 1      # 失败后,等待1秒再发起重试
        }
    }
}
[root@Ubuntu24-16:/etc/keepalived/conf.d]# systemctl restart keepalived.service
[root@Ubuntu24-16:/etc/keepalived/conf.d]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.19:80                 Route   1      0          0
  -> 10.0.0.22:80                 Route   1      0          0
  -> 10.0.0.25:80                 Route   1      0          0

epalived/conf.d]# ipvsadm -Ln

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

-> RemoteAddress:Port Forward Weight ActiveConn InActConn

TCP 10.0.0.100:80 rr

-> 10.0.0.19:80 Route 1 0 0

-> 10.0.0.22:80 Route 1 0 0

-> 10.0.0.25:80 Route 1 0 0

root@Ubuntu24-16:\~# cd /etc/keepalived/conf.d/

root@Ubuntu24-16:/etc/keepalived/conf.d# ls

client1.conf client2.conf

root@Ubuntu24-16:/etc/keepalived/conf.d# rm -rf client2.conf

root@Ubuntu24-16:/etc/keepalived/conf.d# vim client1.conf

root@Ubuntu24-16:/etc/keepalived/conf.d# cat client1.conf

vrrp_instance VI_1 {

state BACKUP

interface ens37

virtual_router_id 51

priority 90

advert_int 1

unicast_src_ip 192.168.8.16

unicast_peer {

192.168.8.13

}

authentication {

auth_type PASS

auth_pass 1111

}

virtual_ipaddress {

10.0.0.100 dev ens33

}

复制代码
# Allow packets addressed to the VIPs above to be received
accept
notify_master "/etc/keepalived/send_message_by_email.sh master"
notify_master "/etc/keepalived/send_message_by_email.sh backup"
notify_master "/etc/keepalived/send_message_by_email.sh fault"

}

virtual_server 10.0.0.100 80 {

delay_loop 2

lb_algo rr

lb_kind DR

protocol TCP

sorry_server 10.0.0.7 80

real_server 10.0.0.19 80 {

HTTP_GET {

url {

path / # 健康检查访问的URL路径:访问根路径 /

status_code 200 # 要求HTTP返回码为200才判定后端正常

}

connect_timeout 1 # 建立TCP连接超时时间,单位秒

nb_get_retry 1 # 健康检查失败后的重试次数:重试1次

delay_before_retry 1 # 失败后,等待1秒再发起重试

}

}

real_server 10.0.0.22 80 {

HTTP_GET {

url {

path / # 健康检查访问的URL路径:访问根路径 /

status_code 200 # 要求HTTP返回码为200才判定后端正常

}

connect_timeout 1 # 建立TCP连接超时时间,单位秒

nb_get_retry 1 # 健康检查失败后的重试次数:重试1次

delay_before_retry 1 # 失败后,等待1秒再发起重试

}

}

real_server 10.0.0.25 80 {

HTTP_GET {

url {

path / # 健康检查访问的URL路径:访问根路径 /

status_code 200 # 要求HTTP返回码为200才判定后端正常

}

connect_timeout 1 # 建立TCP连接超时时间,单位秒

nb_get_retry 1 # 健康检查失败后的重试次数:重试1次

delay_before_retry 1 # 失败后,等待1秒再发起重试

}

}

}

root@Ubuntu24-16:/etc/keepalived/conf.d# systemctl restart keepalived.service

root@Ubuntu24-16:/etc/keepalived/conf.d# ipvsadm -Ln

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

-> RemoteAddress:Port Forward Weight ActiveConn InActConn

TCP 10.0.0.100:80 rr

-> 10.0.0.19:80 Route 1 0 0

-> 10.0.0.22:80 Route 1 0 0

-> 10.0.0.25:80 Route 1 0 0

浏览器访问10.0.0.100

复制代码
[外链图片转存中...(img-JwNwBYFB-1793585244247)]
相关推荐
Jenni see3 小时前
服装厂裁剪自动化怎么搞?自动铺布+激光裁床+六轴机械手裁片分拣,省料省人的实战指南
运维·自动化
Fruiticecake3 小时前
C 变量住在哪里,进程内存为什么越来越大:从 .data / .bss 到 smaps 排查内存增长
linux
Escalating_xu3 小时前
【Linux 网络编程】NAT、代理服务与内网穿透:从一个公网 IP,到一条真正可达的连接
linux·网络·tcp/ip
阿标在干嘛3 小时前
容器编排的“场景适配”:我们为什么在部分服务中回归了Docker Compose?
运维·docker·容器
来让爷抱一个3 小时前
Linux 磁盘 100% 但 du 查不出东西,五种情况逐个排
linux·网络·chrome
墨理学AI4 小时前
虚拟机导致的服务器交换内容占用过大(服务器卡顿)问题 快速解决
运维·服务器
金色光环4 小时前
【DSP学习】C2000_ADC中断_笔记
笔记·学习
Дерек的学习记录4 小时前
Unreal Engine 5:第三人称运动系统和人物动画
开发语言·学习·ue5
zhangrelay4 小时前
mrpt杂乱笔记-26-10-31
笔记·学习