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)]