keepalived实现双主模型的nginx proxy高可用集群

前言

在此前我的博客中介绍过均衡负载集群,也做过动静分离,这些解决方案在实际处理问题的时候都是很有效且大面积使用的方法,但是从之前的博客中不难产生一个疑问:虽然我对后端服务器做了负载均衡,但是如果宕机的是代理服务器怎么办?在我之前的博客中代理服务器一直都是单点。

单点?不存在的,这篇博客我就来通过实例演示解决代理服务器单点的问题。


网络拓扑


操作

准备

这次的目的是要实现双主模型的高可用集群,那么需要配置两个VIP,同时要让这两个VIP在正常情况下分别在两台代理服务器上正常工作,同时如果其中一台故障要能实现IP自动移动到另外一台代理服务器,两台代理服务器互为主备。

准备了四台CentOS7.3,分别角色为:
1,keepalived,nginx服务器,IP:172.16.253.143,VIP1:172.16.222.1,VIP2:172.16.222.2
2,keepalived,nginx服务器,IP:172.16.250.135,VIP1:172.16.222.1,VIP2:172.16.222.2
3,httpd服务器,IP:172.16.254.235
4,httpd服务器,IP:172.16.250.39

这里还有一台客户机就不算在内了。


第一步,配置httpd服务器并创建测试页

#httpd1配置
[root@httpd1 ~]# yum install httpd -y
[root@httpd1 ~]# echo 'webserver1' > /var/www/html/index.html
[root@httpd1 ~]# systemctl start httpd

#httpd2配置
[root@httpd2 ~]# yum install httpd -y
[root@httpd2 ~]# echo 'webserver2' > /var/www/html/index.html
[root@httpd2 ~]# systemctl start httpd

第二步,配置nginx代理服务器

这里keepalived服务和nginx代理服务都在同一台上,先配置nginx然后测试之后再配置keepalived

[root@router1 ~]# yum install nginx -y #安装包
[root@router1 ~]# vim /etc/nginx/nginx.conf #打开配置文件在http中写入
upstream httpds {
    server 172.16.254.235:80; #这个是配置负载均衡的,在之前的博客中貌似不止配置过一次了,这个很容易理解
    server 172.16.250.39:80;
}
#在server中找到未定义的 
location / {
}
改为
location / {
        proxy_pass http://httpds;
}
#注意:这个步骤在router2上也重复一次
[root@router1 ~]# systemctl start nginx #启动服务

在router2上也重复操作后最好测试一下nginx代理是否正常

[root@client ~]# curl 172.16.253.143
webserver1
[root@client ~]# curl 172.16.253.143
webserver2
[root@client ~]#  #router1没问题

[root@client ~]# curl 172.16.250.135
webserver1
[root@client ~]# curl 172.16.250.135
webserver2
[root@client ~]#  #router2也没问题

第三步,配置keepalived

[root@router1 ~]# yum install keepalived -y #安装包
[root@router1 ~]# vim /etc/keepalived/keepalived.conf #打开配置文件
#将vrrp_instance VI_1字段后的所有内容删掉然后将配置文件写成如下
! Configuration File for keepalived

global_defs {
   notification_email { #这里的内容是设置提醒邮箱地址,在测试环境可以不改,但是在实际环境中这里很重要
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc #定义服务器发出通知邮件的地址
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id router1 #这里定义本机的路由ID
   vrrp_mcast_group4 224.2.2.2 #组播地址,这个很重要,两台虚拟主机必须配置同一个地址才能正常实现IP转移
}

vrrp_instance VI_1 { #配置虚拟IP相关内容
    state MASTER #主从设置,MASTER为主,BACKUP为从
    interface ens33 #选定是哪个网卡设备
    virtual_router_id 1 #虚拟路由ID这里可以随便定义,但是两台虚拟主机需要相同
    priority 100 #优先级,可以理解为权重,哪一台虚拟主机优先级越高就由哪台获取改虚拟IP来工作
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111 #定义密码,最高八位多了无效,两台虚拟主机需要相同
    }
    virtual_ipaddress {
        172.16.222.1 #虚拟IP地址
    }
}

#因为是双主模型,所以下面还需要定义一个虚拟IP的相关配置,而且上面的那个虚拟IP设置的是MASTER,那么要想顺利实现双主模型需要让两个虚拟IP都同时工作起来,所以下面这个虚拟IP我需要设置成BACKUP,由router2来做MASTER,设置如下
vrrp_instance VI_2 { #上面的1这里是2
    state BACKUP #这里需要定义为从,由另外一台虚拟主机作为主
    interface ens33
    virtual_router_id 2
    priority 95 #优先级每秒钟广播一次,如果没有发现比自己优先级低的就获取IP,所以这里作为BACKUP就需要把优先级设置低于MASTER(另外一台主机这里设置100)
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 2222
    }
    virtual_ipaddress {
        172.16.222.2
    }
}

#上面是router1的配置文件,然后将router2的配置文件更改至如下:
! Configuration File for keepalived

global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id router2 #注意与router1不同的配置
   vrrp_mcast_group4 224.2.2.2
}

vrrp_instance VI_1 {
    state BACKUP #注意区别
    interface ens33
    virtual_router_id 1
    priority 95 #注意区别
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.16.222.1
    }
}

vrrp_instance VI_2 {
    state MASTER #注意区别
    interface ens33
    virtual_router_id 2
    priority 100 #注意区别
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 2222
    }
    virtual_ipaddress {
        172.16.222.2
    }
}
#最后别忘了启动keepalived服务

配置文件已经写好,为了更深入理解keepalived接下来需要做的测试还有不少


第四步,测试

我在上面已经配置好了所有需要配置的服务,那么现在启动keepalived后router1应该获得了172.16.222.1这个IP,且router2获得了172.16.222.2这个IP

[root@router1 ~]# ip a
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:72:89:34 brd ff:ff:ff:ff:ff:ff
    inet 172.16.253.143/16 brd 172.16.255.255 scope global dynamic ens33
       valid_lft 71251sec preferred_lft 71251sec
    inet 172.16.222.1/32 scope global ens33
       valid_lft forever preferred_lft forever
#通过ip a命令可以看到172.16.222.1已经在router1上了,那么router1上的keepalived算是配置成功了
[root@router2 ~]# ip a
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:76:b4:e6 brd ff:ff:ff:ff:ff:ff
    inet 172.16.250.135/16 brd 172.16.255.255 scope global dynamic ens33
       valid_lft 71504sec preferred_lft 71504sec
    inet 172.16.222.2/32 scope global ens33
       valid_lft forever preferred_lft forever
#如上所示,router2也配置成功

通过ip a命令可以知道现在两个虚拟ip已经成功配置在两台虚拟主机上,而这两台虚拟主机上都配置了对于后端httpd1和httpd2的代理服务nginx,那么我现在可以用一台客户机访问测试一下是否能够正常工作。

[root@client ~]# for i in {1..6};do curl http://172.16.222.1/;done
webserver1
webserver2
webserver1
webserver2
webserver1
webserver2
[root@client ~]# 
#如上所示,访问172.16.222.1能够正常调度
[root@client ~]# for i in {1..6};do curl http://172.16.222.2/;done
webserver1
webserver2
webserver1
webserver2
webserver1
webserver2
[root@client ~]# 
#172.16.222.2也正常工作

上面这个测试可以确定这次实验是完成了。但是如果其中一台虚拟主机宕机了的话两个虚拟IP还能正常调度吗?我这里直接关闭router1的keepalived服务来测试一下

[root@router1 ~]# systemctl stop keepalived #停止keeplived
[root@router1 ~]# ip a
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:72:89:34 brd ff:ff:ff:ff:ff:ff
    inet 172.16.253.143/16 brd 172.16.255.255 scope global dynamic ens33
#停掉服务后用ip a命令可以看到虚拟ip172.16.222.1地址不见了,此时172.16.222.1地址已经被转移到了router2上面

[root@router2 ~]# ip a
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:76:b4:e6 brd ff:ff:ff:ff:ff:ff
    inet 172.16.250.135/16 brd 172.16.255.255 scope global dynamic ens33
       valid_lft 70942sec preferred_lft 70942sec
    inet 172.16.222.2/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet 172.16.222.1/32 scope global ens33
       valid_lft forever preferred_lft forever
#虚拟ip172.16.222.1此时已经在router2上了,那么现在两个虚拟ip都在router2上还能不能正常调度呢?我使用客户机访问一下就知道了

[root@client ~]# for i in {1..6};do curl http://172.16.222.1/;done
webserver1
webserver2
webserver1
webserver2
webserver1
webserver2
[root@client ~]# for i in {1..6};do curl http://172.16.222.2/;done
webserver1
webserver2
webserver1
webserver2
webserver1
webserver2
[root@client ~]#  
#如上,两个ip依然可以正常访问,不过这个时候虽然访问的ip地址不同,但是提供服务的是同一台虚拟主机

其实ip转移的原理就是刚才在上面配置文件里写的优先级问题,因为两台虚拟主机在同一个广播域内每秒钟广播一次自己的优先级数值,一旦发现没有机器比自己的优先级更高那么就将对应的虚拟ip地址添加到对应的设备上,就如同上面的例子,我在将router1的keepalived服务关闭之后,本来router1对于172.16.222.1的优先级是100,router2的优先级是95,在router1在线的时候router1的优先级是最高的所以拿到了172.16.222.1地址,当router1宕机(关掉服务)后,没有虚拟主机对于172.16.222.1地址的优先级大于router2,所以router2就拿到了172.16.222.1这个地址。

为了能看清楚这个过程,可以用tcpdump命令来查看过程,这里我用router2来监控广播信息,然后在router1上启动keepalived,看看会发生什么

[root@router2 ~]# tcpdump -i ens33 -nn host 224.2.2.2 #在router2上监控组播地址224.2.2.2
[root@router1 ~]# systemctl start keepalived #在router1上启动keepalived服务
#以下为在router1启动服务期间router2获取到的信息,信息很多很杂乱,但是我们只需要关注prio的值就行了,我将在下面讲解
14:58:07.487680 IP 172.16.250.135 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 95, authtype simple, intvl 1s, length 20
14:58:07.489639 IP 172.16.250.135 > 224.2.2.2: VRRPv2, Advertisement, vrid 2, prio 100, authtype simple, intvl 1s, length 20
14:58:08.489099 IP 172.16.250.135 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 95, authtype simple, intvl 1s, length 20
14:58:08.489472 IP 172.16.253.143 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
14:58:08.489574 IP 172.16.250.135 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 95, authtype simple, intvl 1s, length 20
14:58:08.490482 IP 172.16.253.143 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
14:58:08.499092 IP 172.16.250.135 > 224.2.2.2: VRRPv2, Advertisement, vrid 2, prio 100, authtype simple, intvl 1s, length 20
14:58:09.492610 IP 172.16.253.143 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
14:58:09.499619 IP 172.16.250.135 > 224.2.2.2: VRRPv2, Advertisement, vrid 2, prio 100, authtype simple, intvl 1s, length 20

如上面获取到的信息可以发现,在router1的keepalived没启动的时候(宕机)router2每秒钟广播一次自己对于vrid1(172.16.222.1)的优先级prio为95,router2每秒钟也广播一次自己对于vrid2(172.16.222.2)的优先级prio为100,当我启动router1上的keepalived服务后可以发现:

14:58:08.489574 IP 172.16.250.135 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 95, authtype simple, intvl 1s, length 20
14:58:08.490482 IP 172.16.253.143 > 224.2.2.2: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20

router1和router2都广播了一次自己对于vrid1的优先级,router1为100,router2为95,从这里以后router2就不再广播自己对于vrid1的优先级了,这个时候因为router1优先级更高所以router1又重新获取了172.16.222.1地址

[root@router1 ~]# ip a
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:72:89:34 brd ff:ff:ff:ff:ff:ff
    inet 172.16.253.143/16 brd 172.16.255.255 scope global dynamic ens33
       valid_lft 69478sec preferred_lft 69478sec
    inet 172.16.222.1/32 scope global ens33

如上面所示,router1重新获取172.16.222.1地址,对于172.16.222.2也是一样的道理,如果router2宕机的话172.16.222.2就会转移到router1上。

那么测试到这里就结束了。


结语

这篇博客虽然没有讲解出多么高深的内容,但是相信刚接触此类服务的朋友好好看了这篇博客的话会对keepaived高可用集群有一定的了解。
完结撒花,要转载的朋友请注明源地址,谢谢。