LVS DR模型实践

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战


LVS DR模型原理

通过修改请求报文的目标MAC地址,然后根据算法挑选出合适的RS节点,进行转发。(请求进入DS时做MAC地址替换,后端返回数据报文时无需经过DS节点,直接返回给客户端即可。)

DR模型基础图解

image-20211125101221117

DR模型底层实现

image-20211125101504551

  1. 路由器如何找到VIP以及MAC地址呢?
    • 路由器通过ARP广播获取VMAC,然后封装CIP、VIP、CMAC、VMAC,通过交换机转发至目标主机。
  2. RS处理请求直接返回给CIP,不经过DS,那么RS如何将数据包回传给CIP
    • 由于CIP请求的是VIP,而响应是通过RIP响应给CIP,所以数据报文一定会被丢弃。那么就需要在所有的RS的接口上配置VIP的地址,由RS上的VIP响应给CIP即可。
  3. 所有RS节点都配置VIP,那么路由器在广播的时候,岂不是所有的VIP都会响应?
    • 方式1:在路由器上静态绑定VIPVMAC的关系。(但可能没有操作权限)
    • 方式2:在所有RS节点上配置ARP抑制,简单来说就是路由器广播获取VMAC时,所有的RS都不应答,其次所有的RS都不对外宣布自己的VIP
  4. VIP、DIP、RIP需要在同—网段中吗?
    • 一般来说DIPRIP在同一物理网络中,并不一定在同一网段中。

DR模型访问流程

  1. 当用户请求到达DS节点,此时请求的数据报文会先到内核空间的PREROUTING链。此时报文的源IP为CIP目标IP为VIP
  2. PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链;
  3. IPVS比对数据包请求的服务是否为集群服务,是则将请求报文中的源MAC修改为DMAC,将目标MAC修改为RMAC,然后将数据包通过POSTROUTING链发出。此时的源IP目标IP均未修改,仅将源MAC修改为DMAC目标MAC修改为RMAC
  4. 由于DSRS在同一个网络中,所以是通过二层来传输。POSTROUTING链检查目标MACRIP的MAC地址,那么此时数据包将通过DIP发送到RS节点;
  5. RS拆解数据报文发现请求的IP地址是本机,则会接收该数据报文,而后构建响应报文向外发出,此时的源IPVIP目标IPCIP
  6. 响应报文最终送达至客户端;

DR模型特性

  • 请求报文必须由DS节点转发,但响应报文必须不经过DS节点;
  • RS不能将网关指向DS节点的DIP
  • DSRS节点必须位于同一物理网络中;
  • DR模型不支持地址转换,也不支持端口映射;
  • RS可以是常见的操作系统Windows、Linux、Macos
  • RSlo接口上配置VIPeth1(arp);

DR模型ARP

  • arp_ignore(控制系统在收到外部的arp请求时,是否需要应答)
    • 0 默认值,将本机所有接口的所有信息像每个连接的网络进行通告;
    • 1 只应答本地主机访问网络接口(eth0-->lo),才给予响应;
  • arp_announce(控制系统是否对外宣布自己的地址)
    • 0 默认值,把本机所有接口的所有信息向每个接口的网络进行通告;
    • 1 "尽量避免"将接口信息向非直接连接网络进行通告;
    • 2 "必须避免"将接口信息向非本网络进行通告;

LVS DR模型实践

DR架构规划

image-20211125101829997

DR路由器配置

  1. Linux服务器配置为路由器,先配置其IP地址;

    • eth0配置信息如下
    [root@route ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0
    TYPE=Ethernet
    BOOTPROTO=none
    DEFROUTE=yes
    NAME=eth0
    DEVICE=eth0
    ONBOOT=yes
    IPADDR=10.0.0.200
    PREFIX=24
    GATEWAY=10.0.0.2			# 指向能出公网的IP
    DNS1=223.5.5.5
    复制代码
    • eth1配置信息如下
    [root@route ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth1
    TYPE=Ethernet
    BOOTPROTO=none
    DEFROUTE=yes
    NAME=eth1
    DEVICE=eth1
    ONBOOT=yes
    IPADDR=172.16.1.200
    PREFIX=24
    复制代码
  2. Route节点启用FORWARD转发功能,实现路由功能;

    [root@route ~]# echo "net.ipv4.ip_forward = 1" >>/etc/sysctl.conf
    [root@route ~]# sysctl -p
    复制代码

DR RS配置

  1. 配置RS节点eth1网卡为LAN模式,然后将网关指向能出公网的路由即可;(所有RS节点都需要操作)

    [root@rs01 ~]# ifdown eth0		# 关闭eth0网关,真实生产环境也仅有一块网卡
    [root@rs01 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth1
    TYPE=Ethernet
    BOOTPROTO=none
    DEFROUTE=yes
    NAME=eth1
    DEVICE=eth1
    ONBOOT=yes
    IPADDR=172.16.1.5			# 不同的 RS 节点地址不一样
    GATEWAY=172.16.1.200		# 所有的 RS 节点都需要能出公网网关
    PREFIX=24
    DNS=223.5.5.5
    复制代码
  2. 配置RS节点VIP地址;

    [root@rs01 ~]# cat /etc/sysconfig/network-scripts/ifcfg-lo:0
    DEVICE=lo:0
    IPADDR=172.16.1.100
    NETMASK=255.0.0.0
    ONBOOT=yes
    NAME=loopback
    复制代码
  3. 重启eth1lo:0网络,使其生效;

    [root@rs01 ~]# ifdown eth1 && ifup eth1
    [root@rs01 ~]# ifdown lo:0 && ifup lo:0
    复制代码
  4. 配置arp,不对外宣告本机VIP地址,也不响应其他节点发起ARP请求本机的VIP

    [root@rs01 ~]# echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
    [root@rs01 ~]# echo "1" >/proc/sys/net/ipv4/conf/default/arp_ignore
    [root@rs01 ~]# echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
    
    [root@rs01 ~]# echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
    [root@rs01 ~]# echo "2" >/proc/sys/net/ipv4/conf/default/arp_announce
    [root@rs01 ~]# echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
    复制代码
  5. 检查RS节点路由信息;

    [root@rs01 ~]# route -n
    Destination	Gateway			Genmask			Flags	Metric	Ref	Use	Iface
    0.0.0.0		172.16.1.200	0.0.0.0			UG		100		0	0	eth1
    172.16.1.0	0.0.0.0			255.255.255.0	U		100		0	0	eth1
    复制代码
  6. 配置后端所有RSweb服务,注意RS1RS2页面不一样,方便验证效果;

    • rs1节点配置
    [root@rs01 ~]# yum install nginx -y
    [root@rs01 ~]# cat /etc/nginx/conf.d/lvs.birenchong.cn.conf
    server {
        listen 80;
        server_name lvs.birenchong.cn;
        root /opt;
        
        location / {
        	index index.html;
        }
    }
    [root@rs01 ~]# echo "Web Page RS-Node1" > /opt/index.html
    [root@rs01 ~]# systemctl start nginx
    
    # 本机测试访问
    [root@rs01 ~]# curl -HHost:lvs.birenchong.cn http://172.16.1.5
    Web Page RS-Node1
    复制代码
    • rs2节点配置
    [root@rs02 ~]# yum install nginx -y
    [root@rs02 ~]# cat /etc/nginx/conf.d/lvs.birenchong.cn.conf
    server {
        listen80;
        server_name lvs.birenchong.cn;
        root /opt;
        
        location / {
        	index index.html;
        }
    }
    [root@rs02 ~]# echo "Web Page RS-Node2" >/opt/index.html
    [root@rs02 ~]# systemctl start nginx
    
    # 本机测试访问
    [root@rs02 ~]# curl -HHost:lvs.birenchong.cn http://172.16.1.6
    Web Page RS-Node2
    复制代码

DR DS配置

  1. 编辑网卡配置,将DS节点的eth1网关指向路由节点;

    [root@lb01 ~]# ifdown eth0
    [root@lb01 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth1
    TYPE=Ethernet
    BOOTPROTO=none
    DEFROUTE=yes
    NAME=eth1
    DEVICE=eth1
    ONBOOT=yes
    IPADDR=172.16.1.3
    PREFIX=24
    GATEWAY=172.16.1.200		# 填写一个网关即可
    DNS1=223.5.5.5
    复制代码
  2. 新增VIP地址的网卡配置,将VIP绑定到eth1:1网卡上;

    [root@lb01 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth1:1
    TYPE=Ethernet
    BOOTPROTO=none
    DEFROUTE=yes
    NAME=eth1:1
    DEVICE=eth1:1
    ONBOOT=yes
    IPADDR=172.16.1.100
    PREFIX=24
    复制代码
  3. 重启DS节点eth1、eth1:1的网卡;

    [root@lb01 ~]# ifdown eth1 && ifup eth1
    [root@lb01 ~]# ifdown eth1:1 && ifup eth1:1
    复制代码
  4. 开启DS节点的内核转发功能;(DR模型不需要,因为不需要DS节点转发RS请求)

    [root@lb01 ~]# echo "net.ipv4.ip_forward = 1" >>/etc/sysctl.conf
    [root@lb01 ~]# sysctl -p
    复制代码
  5. DS节点负载均衡配置;

    # 定义LVS集群
    [root@lb01 ~]# ipvsadm -C
    [root@lb01 ~]# ipvsadm -A -t 172.16.1.100:80 -s rr
    
    # 添加RS1、RS2集群节点,采用官网模式
    [root@lb01 ~]# ipvsadm -a -t 172.16.1.100:80 -r 172.16.1.5:80 -g
    [root@lb01 ~]# ipvsadm -a -t 172.16.1.100:80 -r 172.16.1.6:80 -g
    
    # 查看集群状态信息
    [root@lb01 ~]# ipvsadm -L -n
    IP virtual server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
    	-> RemoteAddress; Port	Forward	weight	ActiveConn	InActConn
    TCP	172.16.1.100:80 rr
    	-> 172.16.1.5:80		Route	1		0			0
    	-> 172.16.1.6:80		Route	1		0			0
    复制代码

DR Client测试

  1. 配置Client节点eth0网络;

    [root@client ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0
    TYPE=Ethernet
    BOOTPROTO=none
    DEFROUTE=yes
    NAME=eth0
    DEVICE=eth0
    ONBOOT=yes
    IPADDR=10.0.0.100
    PREFIX=24
    GATEWAY=10.0.0.200		# 真实场景不可能将客户端网关指向企业的路由器上
    复制代码
  2. 重启Client节点网络;

    [root@client ~]# systemctl restart network
    复制代码
  3. 使用Client测试访问效果;

    [root@client ~]# curl -HHost:lvs.birenchong.cn http://172.16.1.100
    Web Page RS-Node1
    [root@client ~]# curl -HHost:lvs.birenchong.cn http://172.16.1.100
    Web Page RS-Node2
    复制代码
  4. 模拟真实场景,首先删除Client节点指向Route的网关信息,然后配置Route打开IP映射DNAT、以及SNAT(共享上网功能);

    • 删除Client节点的网关配置
    [root@client ~]# sed -i '/GATEWAY/d' /etc/sysconfig/network-scripts/ifcfg-eth0
    [root@client ~]# systemctl restart network
    复制代码
    • 配置Route路由节点的DNAT以及SNAT
    # DNAT(地址映射,企业环境使用)
    [root@route ~]# iptables -t nat -A PREROUTING -d 10.0.0.200 -j DNAT --to 172.16.1.100
    # DNAT(端口映射,虚拟环境使用)
    [root@route ~]# iptables -t nat -A PREROUTING -d 10.0.0.200 -p tcp --dport 80 -j DNAT --to 172.16.1.100:80
    
    # SNAT(让内部主机通过路由可以上网)
    [root@route ~]# iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j SNAT --to 10.0.0.200
    复制代码
  5. 最后用Client再次测试;

    # 真实情况下,客户端节点也是无法连接企业内部网络
    [root@client ~]# curl -HHost:lvs.birenchong.cn http://172.16.1.100
    curl:(7) Failed to connect to 172.16.1.100:网络不可达
    
    # 需要通过访问路由的公网IP
    [root@client ~]# curl -HHost:lvs.birenchong.cn http://10.0.0.200
    Web Page RS-Node2
    [root@client ~]# curl -HHost:lvs.birenchong.cn http://10.0.0.200
    Web Page RS-Node1
    复制代码

LVS DR模型脚本实践

在网络规划没有问题的情况下,通过脚本来实现LVS DR模型。(注意修改脚本中的IP地址)

DS配置脚本

[root@lb01 ~]# cat lvs_ds.sh
#!/usr/bin/bash
VIP=172.16.1.100
RS1=172.16.1.5
RS2=172.16.1.6
PORT=80
DEV=eth1:1

case $1 in
    start)
        cat  >/etc/sysconfig/network-scripts/ifcfg-${DEV} <<-EOF
        TYPE=Ethernet
        BOOTPROTO=none
        DEFROUTE=yes
        NAME=${DEV}
        DEVICE=${DEV}
        ONBOOT=yes
        IPADDR=${VIP}
        PREFIX=24
        EOF

        # 启动网卡
        ifup ${DEV}

        # 配置LVS规则
        ipvsadm -C
        ipvsadm -A -t ${VIP}:${PORT} -s rr
        ipvsadm -a -t ${VIP}:${PORT} -r ${RS1} -g
        ipvsadm -a -t ${VIP}:${PORT} -r ${RS2} -g
        ;;

    stop)
        ifdown ${DEV}
        rm -f /etc/sysconfig/network-scripts/ifcfg-${DEV}
        ipvsadm -C
		;;
    *)
        echo "Usage: sh $0 { start | stop }"
    	;;
esac

复制代码

RS配置脚本

[root@rs01 ~]# cat lvs_rs.sh
#!/usr/bin/bash
VIP=172.16.1.100
DEV=lo:0

case $1 in
    start)
        echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
        echo "1" >/proc/sys/net/ipv4/conf/default/arp_ignore
        echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore

        echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
        echo "2" >/proc/sys/net/ipv4/conf/default/arp_announce
        echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce


        cat  >/etc/sysconfig/network-scripts/ifcfg-${DEV} <<-EOF
        DEVICE=lo:0
        IPADDR=${VIP}
        NETMASK=255.0.0.0
        ONBOOT=yes
        NAME=loopback
        EOF

        ifup ${DEV}    # 启动网卡
        systemctl start nginx
        ;;
    stop)
        echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
        echo "0" >/proc/sys/net/ipv4/conf/default/arp_ignore
        echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore

        echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
        echo "0" >/proc/sys/net/ipv4/conf/default/arp_announce
        echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce

        ifdown ${DEV}  # 停止网卡
        rm -f /etc/sysconfig/network-scripts/ifcfg-${DEV}
        systemctl stop nginx
        ;;
    *)
        echo "Usage: sh $0 { start | stop }"
        ;;
esac

复制代码

LVS 持久连接实践

什么是持久化连接

LVS persistence持久连接,无论使用任何调度算法,在一段时间内(默认300s),能够实现将来自同一个地址的请求始终发往同一个RS

持久化连接配置

[root@lb01 ~]# ipvsadm -E -t 172.16.1.100:80 -p 30
[root@lb01 ~]# ipvsadm -L -n
IP virtual server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
	-> RemoteAddress:Port	Forward	weight	ActiveConn	InActConn
TCP 172.16.1.100:80 wlc persistent 30
	-> 172.16.1.5:80		Route	1		0			0
	-> 172.16.1.6:80		Route	1		0			0
复制代码

持久化连接测试

客户端请求后,可以登陆LVS节点查看,是否有一个连接处于长连接状态。(需要每个请求都TIME-WAIT结束,才会断开长连接)

[root@lb01 ~]# ipvsadm -L -n -c
IPvS connection entries
pro expire state	source				virtual			destination
TCP 01:52 FIN_WAIT	10.0.0.100:60100	172.16.1.100:80	172.16.1.6:80
# 这个就是长连接的计数器,为O就断开了长连接
TCP 00:22 NONE		10.0.0.100:0		172.16.1.100:80	172.16.1.6:80
复制代码

LVS DR模型高可用

LVS可以实现负载均衡功能,但是没有健康检查机制,如果一台RS节点故障,LVS仍然会将请求调度至该故障RS节点服务器;

  • 那么我们可以使用Keepalived来实现解决:
    • 使用Keepalived可以实现LVS的健康检查机制,RS节点故障,则自动剔除该故障的RS节点,如果RS节点恢复则自动加入集群;
    • 使用Keeplaived可以解决LVS单点故障,以此实现LVS的高可用;
    • 可以理解Keepalived就是为LVS而诞生的;

Master节点配置

  1. 安装Keepalived软件

    [root@lb01 ~]# yum install keepalived -y
    复制代码
  2. 配置KeepalivedMASTER角色

    [root@lb01 ~]# cat /etc/keepalived/keepalived.conf
    global_defs {
        router_id lb01
    }
    
    vrrp_instance VI_1 {
        state MASTER
        priority 200
    
        interface eth1
        virtual_router_id 50
        advert_int 3
        authentication {
            auth_type PASS
            auth_pass 1111
     }
        virtual_ipaddress {
            172.16.1.100
        }
    }
    
    # 配置集群地址访问的IP+Port
    virtual_server 172.16.1.100 80 {
        # 健康检查的时间,单位:秒
        delay_loop 6
        # 配置负载均衡的算法
        lb_algo wlc
        # 设置LVS的模式NAT|TUN|DR
        lb_kind DR
        # 设置会话持久化的时间
        perssisstence_timeout 5
        # 设置协议
        protocol TCP
    
        # 负载均衡后端的真实服务节点RS-1
        real_server 172.16.1.5 80 {
            # 权重配比设置为1
            weight 1
            # 设置健康检查
            TCP_CHECK {
                # 检测后端80端口
                connect_port 80
                # 超时时间
                connect_timeout 3
                # 重试次数2次
                nb_get_retry 2
                # 间隔时间3s
                delay_beefore_retry 3
            }
        }
         # 负载均衡后端的真实服务节点RS-2
        real_server 172.16.1.6 80 {
            # 权重配比设置为1
            weight 1
            # 设置健康检查
            TCP_CHECK {
                # 检测后端80端口
                connect_port 80
                # 超时时间
                connect_timeout  3
                # 重试次数2次
                nb_get_retry 2
                # 间隔时间3s
                delay_beefore_retry 3
            }
        }
    }
    复制代码

Backup节点配置

  1. 安装Keepalived软件

    [root@lb02 ~]# yum instal1 keepalived -y
    复制代码
  2. 配置KeepalivedBACKUP角色

    [root@lb02 ~]# cat /etc/keepalived/keepalived.conf
    global_defs {
        router_id lb02
    }
    
    vrrp_instance VI_1 {
        state BACKUP
        priority 150
    
        interface eth1
        virtual_router_id 50
        advert_int 3
        authentication {
            auth_type PASS
            auth_pass 1111
     }
        virtual_ipaddress {
            172.16.1.100
        }
    }
    
    # 配置集群地址访问的IP+Port
    virtual_server 172.16.1.100 80 {
        # 健康检查的时间,单位:秒
        delay_loop 6
        # 配置负载均衡的算法
        lb_algo wlc
        # 设置LVS的模式NAT|TUN|DR
        lb_kind DR
        # 设置会话持久化的时间
        perssisstence_timeout 5
        # 设置协议
        protocol TCP
    
        # 负载均衡后端的真实服务节点RS-1
        real_server 172.16.1.5 80 {
            # 权重配比设置为1
            weight 1
            # 设置健康检查
            TCP_CHECK {
                # 检测后端80端口
                connect_port 80
                # 超时时间
                connect_timeout 3
                # 重试次数2次
                nb_get_retry 2
                # 间隔时间3s
                delay_beefore_retry 3
            }
        }
         # 负载均衡后端的真实服务节点RS-2
        real_server 172.16.1.6 80 {
            # 权重配比设置为1
            weight 1
            # 设置健康检查
            TCP_CHECK {
                # 检测后端80端口
                connect_port 80
                # 超时时间
                connect_timeout  3
                # 重试次数2次
                nb_get_retry 2
                # 间隔时间3s
                delay_beefore_retry 3
            }
        }
    }
    复制代码

高可用架构测试

当启动两台LVS节点的Keepalived软件后,会发现两台节点都有LVS的规则,但仅标记为Master节点的服务器有VIP地址;

当有新的请求进入时,所有的请求都会发送至Master节点,当Master节点故障,VIP地址会漂移到Backup节点,由Backup节点继续对外提供服务,以此来实现LVS的高可用。

  • LVS-MASTER节点地址检查,LVS规则检查。

    [root@lb01 ~]# ip addr | grep 172.16.1.100
    inet 172.16.1.100/32 scope global eth1
    
    [root@lb01 ~]# ipvsadm -L -n
    IP virtual server version 1.2.1 (size=4096)
    Prot	LocalAddress:Port Scheduler	Flags
    	-> RemoteAddress:Port	Forward	weight	ActiveConn	InActConn
    TCP 172.16.1.100:80 wlc
    	-> 172.16.1.5:80		Route	1		0			0
    	-> 172.16.1.6:80		Route	1		0			0
    复制代码
  • LVS-BACKUP节点地址检查,LVS规则检查。

    [root@lb02 ~]# ip addr | grep 172.16.1.100
    [root@lb02 ~]# 
    
    [root@lb02 ~]# ipvsadm -L -n
    IP virtual server version 1.2.1 (size=4096)
    Prot	LocalAddress:Port Scheduler	Flags
    	-> RemoteAddress:Port	Forward	weight	ActiveConn	InActConn
    TCP 172.16.1.100:80 wlc
    	-> 172.16.1.5:80		Route	1		0			0
    	-> 172.16.1.6:80		Route	1		0			0
    复制代码
  • 假设目前有一台Real server故障,Keeplaived检测后会自动将节点移除。

    [root@lb01 ~]# ipvsadm -L -n
    IP virtual server version 1.2.1 (size=4096)
    Prot	LocalAddress:port Scheduler	Flags
    -> RemoteAddress:Port		Forward	weight	ActiveConn	InActConn
    TCP 172.16.1.100:80 wlc
    	-> 172.16.1.6:80		Route	1		0			0
    
    # 观察Keeplaived的详情
    [root@lb01 ~]# systemctl status keepalived
    ...
    1月 08 10:11:55 lb01 Keepalived_healthcheckers[25006]:TCP connection to [172.16.1.5]:80 failed.
    1月 08 10:11:56 lb01 Keepalived_healthcheckers[25006]:TCP connection to [172.16.1.5]:80 failed.
    1月 08 10:11:56 lb01 Keepalived_healthcheckers[25006]:Check on service [172.16.1.5]:80 failed after 1 retry.
    1月 08 10:11:56 lb01 Keepalived_healthcheckers[25006]:Removing service [172.16.1.5]:80 from VS [172.16.1.100]:80
    复制代码

おすすめ

転載: juejin.im/post/7035085714538627109
おすすめ