基于 CentOS 7 构建 LVS-DR 群集
- 1、LVS-DR的基本工作原理
- 2、LVS-DR模式工作原理
- 3、LVS-DR模式应用特点
- 4、LVS-DR模式ARP抑制
- 1)静态地址绑定
- 2)arptables
- 3)修改Linux内核参数
- 5、配置
- 1)实验环境
- 2)设置环境
- ① DS(Director Server)
- ② RS(Real Server)
- 3)配置LVS
- 4)配置ARP抑制
- 5)Client访问测试
- 6、脚本
1、LVS-DR的基本工作原理
- 当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间;
- PREROUTING链首先会接收到用户请求,判断目标IP确定是本机IP,将数据包发往INPUT链;
- IPVS是工作在INPUT链上的,当用户请求到达INPUT时,IPVS会将用户请求和自己已定义好的集群服务进行比对,如果用户请求的就是定义的集群服务,那么此时IPVS会强行修改数据包里的目标IP地址及端口,并将新的数据包发往POSTROUTING链;
- POSTROUTING链接收数据包后发现目标IP地址刚好是自己的后端服务器,那么此时通过选路,将数据包最终发送给后端的服务器。
2、LVS-DR模式工作原理
首先,来自客户端计算机CIP的请求被发送到Director的VIP。然后Director使用相同的VIP目的IP地址将请求发送到集群节点或真实服务器。然后,集群某个节点将回复该数据包,并将该数据包直接发送到客户端计算机(不经过director),并且以此回复数据包使用的目的VIP 地址作为源IP地址。因此,实际上是客户计算机被“欺骗”了,客户计算机始终认为它正与同一台计算机对话,而实际上它正在发送请求数据包给一台计算机(LB),并从另一台计算机(RS)接收回复的数据包。
LVS DR模式集群结构图分解展示:
图1:LVS DR模式集群结构图
图2:客户端准备发出请求报文
图3:报文到达调度器后的改变
图4:RS处理报文后的报文情况
3、LVS-DR模式应用特点
1)所有集群节点RS必须和Director在相同的物理网段(即同一个局域网中);
2)所有客户端入站(而不是出站)请求由Director首先接收,并转发给集群节点RS;
3)集群节点RS通常来说最好带外部IP,而不使用Director及某固定机器作为默认网关,以便将数据包直接回复给客户端计算机,且不会产生回包的瓶颈;
4)所有集群节点RS上必须在lo网卡上绑定VIP地址,以便验证通过目的IP非RS的数据包;
5)由于所有集群节点RS上必须在lo网卡上绑定VIP地址,因此,带来arp问题,即集群节点RS默认会相应发往Director VIP的数据包。因此要对所有集群节点RS做ARP抑制处理,把响应VIP的请求交给LVS Director;
6)很多操作系统都可以用在集群内部的RS真实服务器上只要该操作系统能够实现ARP隐藏,如:Windows,linux,unix;
7)LVS/DR模式不需要开启调度器转发功能,这点和LVS/NAT模式是不同的。
8)LVS/DR Director(服务器数量100台)可以比LVS-NAT Director(服务器数量10-20台)承受更多的并发请求和转发更多的服务器数量。
4、LVS-DR模式ARP抑制
如果不抑制RS端arp影响:
图1:抑制RS端arp前的广播情况
图2:抑制RS端arp前响应情况
提示:广播消息会通过物理网卡到达真实服务器,而真实服务器上有VIP,所以,会响应此请求抑制RS端arp响应后:
图1:抑制RS端arp后广播情况
图2:抑制RS后arp响应情况图
ARP抑制方法:
1)静态地址绑定
未必有路由器的配置权限;
Director调用时静态地址绑定将难以适用;
2)arptables
Disable ARP for VIP
Basically, we have the following commands to disable ARP for VIP at real servers.
arptables -F
arptables -A INPUT -d $VIP -j DROP
arptables -A OUT -s $VIP -j mangle --mangle-ip-s $RIP
3)修改Linux内核参数
将RS上的VIP配置为lo接口的别名,限制Linux仅对对应接口的ARP请求做响应
调整内核参数,关闭arp响应
[root@RS1 ~]# echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@RS1 ~]# echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@RS1 ~]# echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@RS1 ~]# echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
5、配置
1)实验环境
DS(Director Server):DIP 192.168.25.136 & VIP 192.168.25.200
RS1(Real Server):RIP 192.168.25.137
RS2(Real Server):RIP 192.168.25.138
Client:CIP 192.168.25.139(建议设置不一样的网段,此处偷懒了)
2)设置环境
① DS(Director Server)
配置虚拟IP(VIP)
[root@136 ~]# nmcli connection show
NAME UUID TYPE DEVICE
ens33 5acaad27-b469-3a0b-b633-672e401c50fe ethernet ens33
[root@136 ~]# nmcli connection modify ens33 +ipv4.addresses 192.168.25.200/24
[root@136 ~]# nmcli connection up ens33
[root@136 ~]# 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
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:c9:ac:45 brd ff:ff:ff:ff:ff:ff
inet 192.168.25.136/24 brd 192.168.25.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet 192.168.25.200/24 brd 192.168.25.255 scope global secondary noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::f470:be2a:91fd:a7af/64 scope link noprefixroute
valid_lft forever preferred_lft forever
② RS(Real Server)
RS1
手工绑定VIP
[root@137 ~]# ifconfig lo:200 192.168.25.200 netmask 255.255.255.255 up
[root@137 ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.25.137 netmask 255.255.255.0 broadcast 192.168.25.255
inet6 fe80::8fed:5970:dfc6:462b prefixlen 64 scopeid 0x20<link>
inet6 fe80::7a43:663:7982:38fa prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:31:c9:0b txqueuelen 1000 (Ethernet)
RX packets 5084 bytes 320138 (312.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 340 bytes 36309 (35.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 2 bytes 180 (180.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 180 (180.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo:200: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 192.168.25.200 netmask 255.255.255.255
loop txqueuelen 1000 (Local Loopback)
手写本机访问VIP的路由
[root@137 ~]# route add -host 192.168.25.200 dev lo
[root@137 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.25.2 0.0.0.0 UG 100 0 0 ens33
192.168.25.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33
192.168.25.200 0.0.0.0 255.255.255.255 UH 0 0 0 lo
RS2
[root@138 ~]# ifconfig lo:200 192.168.25.200 netmask 255.255.255.255 up
[root@138 ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.25.138 netmask 255.255.255.0 broadcast 192.168.25.255
inet6 fe80::8fed:5970:dfc6:462b prefixlen 64 scopeid 0x20<link>
inet6 fe80::17fa:b9ca:b217:b9c1 prefixlen 64 scopeid 0x20<link>
inet6 fe80::7a43:663:7982:38fa prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:fa:08:eb txqueuelen 1000 (Ethernet)
RX packets 5276 bytes 324571 (316.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 234 bytes 22026 (21.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo:200: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 192.168.25.200 netmask 255.255.255.255
loop txqueuelen 1000 (Local Loopback)
[root@138 ~]# route add -host 192.168.25.200 dev lo
[root@138 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.25.2 0.0.0.0 UG 100 0 0 ens33
192.168.25.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33
192.168.25.200 0.0.0.0 255.255.255.255 UH 0 0 0 lo
3)配置LVS
安装LVS工具包
[root@136 ~]# yum install ipvsadm -y
ipvsadm参数说明
[root@localhost ~]# ipvsadm –h
-A 添加虚拟服务器
-t 设置群集地址(VIP,Virtual IP)
-s 指定负载调度算法
-a 添加真实服务器
-d 删除真实服务器
-r 指定真实服务器(Real Server)的地址
-m 使用NAT模式
-g 使用DR模式
-i 使用TUN模式
-w 为节点服务器设置权重,默认为1
手工执行配置添加LVS服务
[root@136 ~]# ipvsadm -A -t 192.168.25.200:80 -s rr
[root@136 ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.25.200:80 rr
绑定RS
[root@136 ~]# ipvsadm -a -t 192.168.25.200:80 -r 192.168.25.137 -g -w 1
[root@136 ~]# ipvsadm -a -t 192.168.25.200:80 -r 192.168.25.138 -g -w 1
[root@136 ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.25.200:80 rr
-> 192.168.25.137:80 Route 1 0 0
-> 192.168.25.138:80 Route 1 0 0
4)配置ARP抑制
RS1
通过修改Linux内核参数进行ARP抑制
[root@137 ~]# echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@137 ~]# echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@137 ~]# echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@137 ~]# echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
Linux内核参数说明arp_ignore- INTEGER
定义对目标地址为本地IP的ARP询问不同的应答模式
0 -(默认值):回应任何网络接口上对任何本地IP地址的arp查询请求;
1 – 只回答目标IP地址是来访网络接口本地地址的ARP查询请求;
2 – 只回答目标IP地址是来访网络接口本地地址的ARP查询请求,且来访IP必须在该网络接口的子网段内;
3 – 不回应该网络界面的arp请求,而只对设置的唯一和连接地址做出回应;
4-7 –保留未使用;
8 – 不回应所有(本地地址)的arp查询。
arp_announce - INTEGER
对网络接口上,本地IP地址发出的,ARP回应,做出相应级别的限制;确定不同程度的限制,宣布对来自本地源IP地址发出ARP请求的接口
0 -(默认)在任意网络接口(eth0,eth1,lo)上的任何本地地址;
1 – 尽量避免不在该网络接口子网段的本地地址做出arp回应,当发起ARP请求的源IP地址是被设置应该经由路由到达此网络接口的时候很有用,此时会检查来访IP是否为所有接口上的子网段内ip之一。如果该来访IP不属于各个网络接口上的子网段内,那么将采用级别2的方式来进行处理;
2 – 对查询目标是要最适当的本地地址,在此模式下将忽略这个IP数据包的源地址并尝试选择与能与该地址通信的本地地址。首要是选择所有的网络接口的子网中外出访问子网中包含该目标IP地址的本地地址。如果没有合适的地址被发现,将选择当前的网络发送接口或其他的有可能接受到该ARP回应的网络接口来进行发送。限制了使用本地的vip地址作为优先的网络接口。
RS2
通过添加arptables规则进行ARP抑制
yum源没有对应安装包,在网络中下载:rpmfind.net
yum install https://rpmfind.net/linux/centos/7.9.2009/os/x86_64/Packages/arptables-0.0.4-8.el7.x86_64.rpm -y
添加规则
[root@138 ~]# arptables -A INPUT -d 192.168.25.200 -j DROP
[root@138 ~]# arptables -A OUTPUT -s 192.168.25.200 -j mangle --mangle-ip-s 192.168.25.138
保存规则
[root@138 ~]# arptables-save > /etc/sysconfig/arptables
[root@138 ~]# systemctl enable --now arptables.service
5)Client访问测试
使用for循环访问VIP
[root@139 ~]# for ((i=1;i<=10;i++)); do curl 192.168.25.200; done
web2 test page, ip: 192.168.25.138
web1 test page, ip: 192.168.25.137
web2 test page, ip: 192.168.25.138
web1 test page, ip: 192.168.25.137
web2 test page, ip: 192.168.25.138
web1 test page, ip: 192.168.25.137
web2 test page, ip: 192.168.25.138
web1 test page, ip: 192.168.25.137
web2 test page, ip: 192.168.25.138
web1 test page, ip: 192.168.25.137
#可以清晰看出每一个RS轮流被访问
DS上查看
[root@136 ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.25.200:80 rr
-> 192.168.25.137:80 Route 1 0 5
-> 192.168.25.138:80 Route 1 0 5
# 可以清晰看出末尾平均每个RS都被访问了5次
6、脚本
lvs director 上的脚本
=================================================================
#!/bin/sh
#
# Startup script handle the initialisation of LVS
# chkconfig: - 28 72
# description: Initialise the Linux Virtual Server for DR
#
### BEGIN INIT INFO
# Provides: ipvsadm
# Required-Start: $local_fs $network $named
# Required-Stop: $local_fs $remote_fs $network
# Short-Description: Initialise the Linux Virtual Server
# Description: The Linux Virtual Server is a highly scalable and highly
# available server built on a cluster of real servers, with the load
# balancer running on Linux.
# description: start LVS of DR
LOCK=/var/lock/ipvsadm.lock
VIP=192.168.25.200
RIP1=192.168.25.137
RIP2=192.168.25.138
DipName=ens33
. /etc/rc.d/init.d/functions
start() {
PID=`ipvsadm -Ln | grep ${VIP} | wc -l`
if [ $PID -gt 0 ];
then
echo "The LVS-DR Server is already running !"
else
#Set the Virtual IP Address
/sbin/ifconfig ${DipName}:10 $VIP broadcast $VIP netmask 255.255.255.255 up
/sbin/route add -host $VIP dev ${DipName}:10
#Clear IPVS Table
/sbin/ipvsadm -C
#Set Lvs
/sbin/ipvsadm -At $VIP:80 -s rr
/sbin/ipvsadm -at $VIP:80 -r $RIP1:80 -g
/sbin/ipvsadm -at $VIP:80 -r $RIP2:80 -g
/bin/touch $LOCK
#Run Lvs
echo "starting LVS-DR Server is ok !"
fi
}
stop() {
#clear Lvs and vip
/sbin/ipvsadm -C
/sbin/route del -host $VIP dev ${DipName}:10
/sbin/ifconfig ${DipName}:10 down >/dev/null
rm -rf $LOCK
echo "stopping LVS-DR server is ok !"
}
status() {
if [ -e $LOCK ];
then
echo "The LVS-DR Server is already running !"
else
echo "The LVS-DR Server is not running !"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo "Usage: $1 {start|stop|restart|status}"
exit 1
esac
exit 0
======================================================
RS上的脚本
#!/bin/sh
#
# Startup script handle the initialisation of LVS
# chkconfig: - 28 72
# description: Initialise the Linux Virtual Server for DR
#
### BEGIN INIT INFO
# Provides: ipvsadm
# Required-Start: $local_fs $network $named
# Required-Stop: $local_fs $remote_fs $network
# Short-Description: Initialise the Linux Virtual Server
# Description: The Linux Virtual Server is a highly scalable and highly
# available server built on a cluster of real servers, with the load
# balancer running on Linux.
# description: start LVS of DR-RIP
LOCK=/var/lock/ipvsadm.lock
VIP=192.168.25.200
. /etc/rc.d/init.d/functions
start() {
PID=`ifconfig | grep lo:10 | wc -l`
if [ $PID -ne 0 ];
then
echo "The LVS-DR-RIP Server is already running !"
else
/sbin/ifconfig lo:10 $VIP netmask 255.255.255.255 broadcast $VIP up
/sbin/route add -host $VIP dev lo:10
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/eth0/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/eth0/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
/bin/touch $LOCK
echo "starting LVS-DR-RIP server is ok !"
fi
}
stop() {
/sbin/route del -host $VIP dev lo:10
/sbin/ifconfig lo:10 down >/dev/null
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/eth0/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/eth0/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
rm -rf $LOCK
echo "stopping LVS-DR-RIP server is ok !"
}
status() {
if [ -e $LOCK ];
then
echo "The LVS-DR-RIP Server is already running !"
else
echo "The LVS-DR-RIP Server is not running !"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo "Usage: $1 {start|stop|restart|status}"
exit 1
esac
exit 0