32---keepalived功能及使用场景(2)

来源:互联网 发布:日本和服淘宝 编辑:程序博客网 时间:2024/06/06 02:14
==========
两个问题:
在继续讲keepalived之前让我们先思考两个问题:
1.如果我们只有一台调度器(lvs/Nginx),且它到后端real server集群的物理连接断了(如网卡、光模块、线缆等损坏),那该怎么应对?
2.如果我们只有一台调度器(Nginx等软件实现的),但是不巧的是Nginx进程被杀死了,那该怎么应对?
显然以上都是单点故障,遇到单点故障很棘手,我们应该避免。一般来讲网络中关键节点都应该有至少两个,所以我们的调度器也应该至少两台,组成高可用(HA)集群,如下图

图中有两台调度器,正常情况下流量仅流经director1,也就是director1 作为MASTER,director2 作为BACKUP。我们期望的是当MASTER的 eth1或 eth3 接口挂掉后,director2 能够承接director1的所有流量。同时,如果direcotr1为Nginx反代(包括7层和伪34层),当Nginx进程挂掉后,也能完成流量切换。如何实现呢?用 keepalived。
在数通网络中,我们通常使用VRRP来做默认网关的冗余,keepalived也是靠实现VRRP协议来完成流量从 director1 到director2 的倒换的。如果不熟悉VRRP,建议去某度文库搜索下数通厂商的vrrp技术白皮书。理解了VRRP的工作原理后再来看 keepalived, so easy。(务必要先搞懂VRRP协议,厂商的vrrp技术白皮书已经写的很详细了,如华为。)
言归正传,使用keepalived,以下3种情况下会触发倒换(也就是图中流量从 director1 切到 director2):
场景描述:图中eth1和eth2起vrrp,且eth1被选举为MASTER(准确地说MASTER和BACKUP都是针对接口说的,不过我们在一定场合下也称路由器的状态为MASTER/BACKUP)
1.  director1 的eth1接口down掉,这很容易理解,物理接口down掉了,无法发送vrrp advertisement,作为BACKUP的director2这时候就会接替原来director1的角色,成为MASTER。
2. 我们可以让 keepalived 进程在director1监控eth3接口的状态,如果该接口down掉,则停止在eth1接口上发送vrrp advertisement,把MASTER角色让个director2。这通过keepalived.conf中的track_interface命令配置来实现。
3. 我们可以让 keepalived 执行某脚本,该脚本周期性地检测诸如进程等的设备状态并返回code,keepalived根据脚本返回的code值调整(减小)director1发出的vrrp 通告中的priority至小于director2发出的通告中的priority,把MASTER角色让给director2。这通过keepalived.conf中的track_script命令配置来实现。
好,现在给出几个实例,我们通过如下两个拓扑完成实验验证。

Note:如中rs1,rs2,rs3是3台不同的物理机,只不过图中画在了一起。
实例一:
使用拓扑一,仅仅在 director1 和 director2 的左侧接口起 vrrp,VRIP为192.168.10.131,物理接口分别为 192.168.10.128 和 192.168.10.135。设置 192.168.10.128所在借口有 higher priority,以使之被选举为master,当master接口挂掉后,backup接口开始发送 vrrp advertisement,成为master。director 1 和 director2 的配置分别如下:
补充:组播地址 && VRID 要设置成一样才会被认为是同一个 vrrp_instance
===== director1 配置 =====
global_defs {
  notification_email {
    root@localhost
  }
  notification_email_from root@localhost
  smtp_server 127.0.0.1
  smtp_connect_timeout 30
  router_id 6A   //设置 router-id
  vrrp_mcast_group4 224.0.0.18  //设置组播地址,同一个vrrp_instance中的组播地址一定要相同
}
vrrp_instance OUTSIDE_VI_1 {  //创建一个instance,名字随意(本地有效,报文不含之),但是建议主备同名
   state MASTER  //预设置角色,其实没有大用,鹿死谁手还得比拼priority等
   interface eth1  //指定加入instance的接口
   virtual_router_id 1 //设置VRID,同一个vrrp_instance中的VRID一定要相同
   priority 100 //本机在vrrp_instance中的优先级,准确说应该是接口的优先级
   advert_int 1 //通告每隔1s发送一次
   authentication { //通告验证使用简单验证,仅vrrp 2.0支持,而keepalived就是实现的vrrp 2.0
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131   //vrrp的VRIP
   }
}

===== director2 配置 =====
global_defs {
  notification_email {
    root@localhost
  }
  notification_email_from root@localhost
  smtp_server 127.0.0.1
  smtp_connect_timeout 30
  router_id 6B
  vrrp_mcast_group4 224.0.0.18  //同一vrrp_instance的组播地址要一致
}
vrrp_instance OUTSIDE_VI_1 {
   state BACKUP
   interface eth6  //指定加入instance的接口
   virtual_router_id 1  //同一vrrp_instance的VRID要一致
   priority 99
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131
   }
}
配置完成后,重启keepalived。手动关闭 director1 的eth1,ip link set eth1 down,然后在vmnet1 上抓包,发现director2 的eth6 开始发送vrrp advertisement,也就是说director2的eth6已经是MASTER,切换完成。实验完成后再恢复eth1到up状态。
实例二:
使用拓扑一,在实验一的基础上,验证当MASTER监控的某借口down掉后,发生角色切换。也就是验证 track_interface的作用。
===== director1 配置 =====
global_defs {
   //节约版面,这部分内容请自己补上
}
vrrp_instance OUTSIDE_VI_1 {
   state MASTER
   interface eth1
   virtual_router_id 1
   priority 100
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
}
   virtual_ipaddress {
       192.168.10.131
   }
   track_interface {  //仅在实验一的基础上添加这个配置段
       eth0
   }
}

===== director2 配置 =====
global_defs {
   //节约版面,这部分内容请自己补上
}
vrrp_instance OUTSIDE_VI_1 {
   state BACKUP
   interface eth6
   virtual_router_id 1
   priority 99
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
}
   virtual_ipaddress {
       192.168.10.131
   }
   track_interface {  //仅在实验一的基础上添加这个配置段
       eth2
   }
}
配置完成后,重启keepalived。手动关闭 director1 的eth0,ip link set eth0 down,然后在vmnet1 上抓包,发现director2 的eth6 开始发送vrrp advertisement,也就是说director2的eth6已经是MASTER,切换完成。实验完毕后恢复eth0到up状态。
实例三:
使用拓扑一,在实验一的基础上,验证 track_script 的作用,即周期性地执行脚本,然后根据脚本的返回值调整weight,从而达到MASTER/BACKUP角色切换的目的。
===== director1 配置 =====
global_defs {
   //节约版面,这部分内容请自己补上
}
vrrp_script my_test {           //定义如何追踪脚本,及根据脚本返回代码执行何种动作
   script "[ -f /tmp/hehe  ]"   //检查shell脚本表达式的值,这里双引号内可以是外置脚本(要有exec权限)
   interval 1      //多长时间执行一次脚本并检查其返回值
   weight -2      //如果脚本执行失败后的动作(weight-2,仅执行一次);如果后续检查发现脚本执行成功则执行反动作(把减去的2加回来)
   fall 3  //返回几次非0,才认为失败,执行 weight-2的动作
   rise 1  //返回几次0,才认为成功,执行weight-2的反动作,即当前weight+2
}
vrrp_instance OUTSIDE_VI_1 {
   state MASTER
   interface eth1
   virtual_router_id 1
   priority 100
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131
   }
   track_script {   //追踪my_test中指明的脚本,my_test要在vrrp_instance前定义好
       my_test
   }
}

===== director2 配置 =====
global_defs {
  //节约版面,这部分内容请自己补上
}
vrrp_script my_test {           //本次实验这一段不加也可,但是建议主备配置一致
   script "[ -f /tmp/hehe  ]"
   interval 1
   weight -2
   fall 3
   rise 1
}
vrrp_instance OUTSIDE_VI_1 {
   state BACKUP
   interface eth6
   virtual_router_id 1
   priority 99
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131
   }
   track_script {  //本次实验这一段不加也可,但是建议主备配置一致
       my_test
   }
}
配置完成后,现在touch一个/tmp/hehe,重启keepalived,在vmnet1上抓包。这时候由于 [ -f /tmp/hehe ] 返回值为0,也就是 weight 不变化,所以director1还是MASTER。这时候 rm -f /tmp/hehe,当director1 检查脚本表达式时,发现3此都是非0,所以weight-2,由100变成了98,小于director2的priority99,让出了MASTER。观察抓到的报文,发现director2 确实已经再发 vrrp advertisement了。
这里只是拿 [ -f /tmp/hehe ]做个例子而已,生产环境中一般都是检查某个进程是否存活,如 [ killall -0 nginx ] 若 nginx 进程存在,则返回0,weight不变。若进程已死,则weight变化,一般是减小以让出MASTER。 当然,引用外部具有可执行权限的脚本也是ok的。
实例四:
使用如下拓扑二,我们实现一个 lvs-dr的高可用集群(集群这名总是感觉高达上,其实也就是director1和director2组成一个lvs-dr组)


===== director1 配置 =====
global_defs {
  //节约版面,这部分内容请自己补上
}
vrrp_instance OUTSIDE_VI_1 {
   state MASTER
   interface eth1
   virtual_router_id 1
   priority 100
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131  //即做VRIP,也做lvs概念中的VIP
   }
}
virtual_server 192.168.10.131 80 {
   delay_loop 6
   lb_algo rr
   lb_kind DR    //定义lvs类型为dr
   persistence_timeout 0 
   protocol TCP

   real_server 192.168.10.140 80 {
       weight 1
       HTTP_GET {
           url {
               path /
               status_code 200
           }
           nb_get_retry 3
           delay_before_retry 1
           connect_timeout 1
       }
   }
   real_server 192.168.10.141 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
   real_server 192.168.10.142 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
}

===== director2 配置 =====
global_defs {
  //节约版面,这部分内容请自己补上
}
vrrp_instance OUTSIDE_VI_1 {
   state BACKUP
   interface eth6
   virtual_router_id 1
   priority 99
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131
   }
}

virtual_server 192.168.10.131 80 {
   delay_loop 6
   lb_algo rr
   lb_kind DR    //定义lvs类型为dr
   persistence_timeout 0 
   protocol TCP

   real_server 192.168.10.140 80 {
       weight 1
       HTTP_GET {
           url {
               path /
               status_code 200
           }
           nb_get_retry 3
           delay_before_retry 1
           connect_timeout 1
       }
   }
   real_server 192.168.10.141 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
   real_server 192.168.10.142 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
}

===== real server 的配置 =====
rs1:启动httpd,通过 ip add add 192.168.10.131 dev lo 给real server添加VIP
rs2:启动httpd,通过 ip add add 192.168.10.131 dev lo 给real server添加VIP
rs3:启动httpd,通过 ip add add 192.168.10.131 dev lo 给real server添加VIP
此时的高可用就体现在 director1 的master接口down掉后的流量切换。
实例五:
使用拓扑一,我们实现一个 lvs-nat 的高可用集群。为了方便理解配置,再贴一遍图,请对照拓扑理解配置。

先思考个问题,使用lvs-nat的话,real server把默认网关指向谁?在只有一台director的时候这个问题是不存在的,但是现在两台director,怎么办?还是用vrrp,把两台director右侧的interface加入另一个vrrp_instance,然后让real server把默认网关只想这个vrrp_instance的VRIP就可以了。这又引入了另一个问题,director上保存着nat表,所以同一条tcp流的上下行数据要经过同一台director(主director,也就是director1)。也就是两个vrrp_instance的master接口要在同一台director上,一个vrrp_instance发生了接口角色切换,另一个vrrp_instance 也要发生切换,如何实现?用vrrp同步组。

===== director1 配置 =====
lobal_defs {
   //节约版面,这部分内容请自己补上
}
vrrp_sync_group VG_1 {   //定义vrrp同步组,把两个vrrp_instance加入改组。当一个vrrp_instance接口切换时,另一个同步切换
   group {
       INSIDE_VI_1     //加入同步组的vrrp_instance
       OUTSIDE_VI_1
   }
}
vrrp_instance OUTSIDE_VI_1 {
   state MASTER
   interface eth1
   virtual_router_id 1
   priority 100   //左侧的vrrp_instance中,通过设置优先级让director1上的接口被选举为master
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131    //左侧vrrp_instance的VRIP
   }
}
vrrp_instance INSIDE_VI_1 {
   state MASTER
   interface eth0
   virtual_router_id 2
   priority 100   //左侧的vrrp_instance中,通过设置优先级让director1上的接口被选举为master
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.20.135    //右侧vrrp_instance的VRIP
   }

}
virtual_server 192.168.10.131 80 {
   delay_loop 6
   lb_algo rr
   lb_kind NAT   //实现lvs-nat
   persistence_timeout 0  # during which time, request is distributed to the same real server
   protocol TCP

   real_server 192.168.20.130 80 {
       weight 1
       HTTP_GET {
           url {
               path /
               status_code 200
           }
           nb_get_retry 3
           delay_before_retry 1
           connect_timeout 1
       }
   }
   real_server 192.168.20.131 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
   real_server 192.168.20.132 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
}

===== director2 配置 =====
lobal_defs {
   //节约版面,这部分内容请自己补上
}
vrrp_sync_group VG_1 {
   group {
       INSIDE_VI_1
       OUTSIDE_VI_1
   }
}
vrrp_instance OUTSIDE_VI_1 {
   state BACKUP
   interface eth6
   virtual_router_id 1
   priority 99    //director2作为backup
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131   //左侧vrrp_instance的VRIP
   }
}
vrrp_instance INSIDE_VI_1 {
   state BACKUP
   interface eth2
   virtual_router_id 2
   priority 99     //director2作为backup
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.20.135   //右侧vrrp_instance的VRIP
   }
}

virtual_server 192.168.10.131 80 {
   delay_loop 6
   lb_algo rr
   lb_kind NAT
   persistence_timeout 0 #dechao: during which time the request is distributed to same real server
   protocol TCP

   real_server 192.168.20.130 80 {
       weight 1
       HTTP_GET {
           url {
               path /
               status_code 200
           }
           nb_get_retry 3
           delay_before_retry 1
           connect_timeout 1
       }
   }
   real_server 192.168.20.131 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
   real_server 192.168.20.132 80 {
       weight 1
       TCP_CHECK {
           connect_timeout 1
       }
   }
}
2台director 上 echo 1 > /proc/sys/net/ipv4/ip_forward 设置 ip_forward=1
3台real server上添加默认路由 ip route add default via 192.168.20.135,同时启动httpd,建议给出不同页面。这时候通过client访问 192.168.10.131,请求就可以被轮询调度到后端不同的real server上了。
这个实例的高可用体现在vrrp的同步倒换上,我们手动关闭director1上右侧端口,发现右侧的vrrp_instance角色切换,同时左侧vrrp_instance的角色也发生切换。但是启用vrrp同步后,发现和track_script冲突,track_script不管用了。通过日志可以看出来,文章最后会讲到keepalived日志相关的东西。
实例六:
使用如下拓扑,我们实现一个Nginx的调度器高可用集群。director1平时作为master,当他上面的Nginx挂掉后,让出master角色给director2,同时执行一些动作,如发邮件给管理员。
说明:由于Nginx作反代调度器的时候,无论伪34层还是7层都可以认为是full-nat,也就是SNAT+DNAT,所以两台director的右侧接口没有起vrrp。


===== director1 配置 =====
global_defs {
  //节约版面,这部分内容请自己补上
}
vrrp_script my_test {
   script "killall -0 nginx"
   interval 1
   weight -2
   fall 3
   rise 1
}
vrrp_instance OUTSIDE_VI_1 {
   state MASTER
   interface eth1
   virtual_router_id 1
   priority 100
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131
   }
   track_script {
       my_test
   }
   notify_master "/tmp/2master.sh"
   notify_backup "/tmp/2backup.sh"
}

===== director2 配置 =====
global_defs {
  //节约版面,这部分内容请自己补上
}
vrrp_script my_test {
    script "killall -0 nginx"
    interval 1
    weight -2
    fall 3
    rise 1
}
vrrp_instance OUTSIDE_VI_1 {
   state BACKUP
   interface eth6
   virtual_router_id 1
   priority 99
   advert_int 1
   authentication {
       auth_type PASS
       auth_pass 1111
   }
   virtual_ipaddress {
       192.168.10.131
   }
    track_script {
       my_test
   }  
   notify_master "/tmp/2master.sh"
   notify_backup "/tmp/2backup.sh"
}
director1 和 director2 上都运行Nginx,作为7层代理或者伪34层代理。此时director1被选举为master。
/tmp/2master.sh 和 /tmp/2backup.sh 要有执行权限,在本实验中脚本内容如下:
/tmp/2master.sh 内容:
#!/bin/bash
echo 2master@`date` >> /tmp/keepalived.state
/tmp/2backup.sh 内容:
#!/bin/bash
echo 2backup@`date` >> /tmp/keepalived.state
这里只是举一个简单的例子,角色转换时执行的脚本可以是任意的。
现在我们手动停掉director1上的Nginx,这时候director1的vrrp weight由100-2变为98,让出了master,我们可以抓包看到此时director2开始发送vrrp advertisement。同时可以 cat /tmp/keepalived.state ,发现确实角色发生了转化。
===============
keepalived日志相关:
CentOS6上keepalived的日志默认记录在/var/log/messages里面,不好看,通过如下方式定向到一个文件。
  /etc/sysconfig/keepalived
       编辑:KEEPALIVED_OPTIONS="-D -d -S 3"
  /etc/rsyslog.conf 
       编辑:local3.* /var/log/keepalived.log
  service rsyslog restart
  service keepalived restart

Oh,my god。总算说完了。




原创粉丝点击