侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 747 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

使用keepalived完成高可用架构的构建

zze
zze
2020-04-08 / 0 评论 / 0 点赞 / 1049 阅读 / 16067 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

keepalived 介绍

keepalived 是什么

keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防止单点故障。

keepalived 工作原理

keepalived 是以 VRRP 协议为实现基础的,VRRP 全称 Virtual Router Redundancy Protocol,即虚拟路由冗余协议。
虚拟路由冗余协议,可以认为是实现路由器高可用的协议,即将 N 台提供相同功能的路由器组成一个路由器组,这个组里面有一个 master 和多个 backup,master 上面有一个对外提供服务的 vip(该路由器所在局域网内其他机器的默认路由为该 vip),master 会发组播,当 backup 收不到 vrrp 包时就认为 master 宕掉了,这时就需要根据 VRRP 的优先级来选举一个 backup 当 master。这样的话就可以保证路由器的高可用了。

image

keepalived 主要有三个模块,分别是 core、check 和 vrrp。

  • core 模块为 keepalived 的核心,负责主进程的启动、维护以及全局配置文件的加载和解析;
  • check 负责健康检查,包括常见的各种检查方式;
  • vrrp 模块是来实现 VRRP 协议的;

VRRP 详细可参考『VRRP 技术白皮书』。

keepalived 的配置文件

keepalived 只有一个配置文件 keepalived.conf,里面主要包括以下几个配置区域,分别是 global_defsstatic_ipaddressstatic_routesvrrp_scriptvrrp_instancevirtual_server

下面为示例配置文件,各配置段及指令的功用以注释的方式描述。

# 全局配置块
global_defs {
    # 故障发生时给谁发邮件通知,目标邮件地址可有多个。
    notification_email {
        acassen@firewall.loc
        failover@firewall.loc
        sysadmin@firewall.loc
    }
    # 通知邮件从哪个地址发出。
    notification_email_from Alexandre.Cassen@firewall.loc
    # 通知邮件的 smtp 地址。
    smtp_server 192.168.200.1
    # 连接 smtp 服务器的超时时间。
    smtp_connect_timeout 30
    # 标识本节点的字条串,通常为 hostname,但不一定非得是 hostname,故障发生时,邮件通知会用到。
    router_id LVS_DEVEL
}
# 静态地址配置块
static_ipaddress {
    # 启动 keepalived 时在本机执行如下命令:
    # /sbin/ip addr add 10.210.214.163/24 brd 10.210.214.255 dev eth0
    # 关闭 keepalived 时在本机执行如下命令:
    # /sbin/ip addr del 10.210.214.163/24 brd 10.210.214.255 dev eth0
    10.210.214.163/24 brd 10.210.214.255 dev eth0
}
# 静态路由配置块
static_routes {
    # 启动 keepalived 时在本机执行如下命令
    # /sbin/ip route add 10.0.0.0/8 via 10.210.214.1 dev eth0
    # 关闭 keepalived 时在本机执行如下命令
    # /sbin/ip route del 10.0.0.0/8 via 10.210.214.1 dev eth0
    10.0.0.0/8 via 10.210.214.1 dev eth0
}
# static_ipaddress、static_routes 这两个块不常用,也没必要使用这俩东东来配置路由和地址吧~~~

# 用来做健康检查的,当时检查失败时会将 vrrp_instance 的 priority 减少相应的值。
vrrp_script chk_down {
    script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0"
    interval 1
    weight -10
}
# 以上意思是如果 script 中的指令执行失败(退出状态码不为 0),那么相应的 vrrp_instance 的优先级会减少 10 个点。

# vrrp 实例组配置块
vrrp_sync_group VG_1 {
    # 下面 group 块将 VI_1 实例和 VI_2 实例配置在同一个组。
    # 说一个使用场景,比如要给多台使用 lvs-nat 模型的 director 添加 VIP,此时内网主机的网关就需要同步指向 VIP 所在的 director 的内网地址,
    # 即 director 的 VIP 和 DIP 需要同步流动,所以需要将它们定义在一个组中。
    group {
        VI_1
        VI_2
    }
    # 下面几项的功能和 vrrp_instance 块中的功能相同,只不过在这里它们是针对上述组中定义的所有实例同时生效的。
    notify_master /path/to_master.sh
    notify_backup /path/to_backup.sh
    notify_fault "/path/fault.sh VG_1"
    notify /path/notify.sh
    smtp_alert
}

# vrrp 实例配置块
vrrp_instance VI_1 {
    # 可以是 MASTER 或 BACKUP,不过当其他节点的 keepalived 启动时会将 priority 比较大的节点选举为 MASTER,所以此项其实没有实质用途。
    state MASTER
    # 设定用来发 VRRP 包的网卡。
    interface eth0
    # 取值在 0-255 之间,用来区分多个 instance 的 VRRP 组播。
    # 注意:不同虚拟路由器中 virtual_router_id 的值不能重复,否则会出错。
    # 原因是虚拟 MAC 地址的格式为 00-00-5E-00-01-{VRID},相同即虚拟 MAC 重复了。
    virtual_router_id 51
    # 配置权重用来选举 master,要成为 master,那么这个选项的值最好高于其他机器 50 个点,该项取值范围是 1-255(在此范围之外会被识别成默认值 100)。
    priority 100
    # 是否使用 VRRP 的虚拟 MAC 地址。
    use_vmac
    # 发 VRRP 包的时间间隔,即多久进行一次 master 选举(可以认为是健康查检时间间隔)。
    advert_int 1
    # authentication 认证区域,认证类型有 PASS 和 HA(IPSEC),推荐使用 PASS(密码只识别前 8 位)。
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 虚拟 IP 地址
    virtual_ipaddress {
        192.168.200.16
        192.168.200.17
        192.168.200.18
    }
    # 虚拟路由,当 IP 漂过来之后需要添加的路由信息。
    virtual_routes {
        172.16.0.0/12 via 10.210.214.1
        192.168.1.0/24 via 192.168.1.1 dev eth1
        default via 202.102.152.1
    }
    # virtual_ipaddress_excluded 发送的 VRRP 包里不包含的 IP 地址,为减少回应 VRRP 包的个数。在网卡上绑定的 IP 地址比较多的时候用。
    virtual_ipaddress_excluded {
        172.16.1.202
    }
    # 启用非抢占模式,即允许一个 priority 比较低的节点作为 master,即使有 priority 更高的节点启动。
    # 当使用 track_script 时可以不用加 nopreempt,只需要加上 preempt_delay 5,这里的间隔时间要大于 vrrp_script 中定义的时长。
    # 首先 nopreempt 必须在 state 为 BACKUP 的节点上才生效,需要将所有节点的 state 都设置为 BACKUP,或者将 master 节点的 priority 设置的比 BACKUP 低。我个人推荐使用将所有节点的 state 都设置成 BACKUP 并且都加上 nopreempt 选项,当想手动将某节点切换为 MASTER 时只需去掉该节点的 nopreempt 选项并且将 priority 改的比其他节点大,然后重新加载配置文件即可。
    nopreempt
    # master 启动多久之后进行接管资源(VIP/Route 信息等),前提是没有 nopreempt 选项。
    preempt_delay 300
    # 切换为主节点时所执行的脚本。
    notify_master <STRING>|<QUOTED-STRING>
    # 切换为备节点时所执行的脚本。
    notify_backup <STRING>|<QUOTED-STRING>
    # 切换出错时所执行的脚本。
    notify_fault <STRING>|<QUOTED-STRING>
    # 表示任何一状态切换时都会调用该脚本,并且该脚本在以上三个脚本执行完成之后进行调用,keepalived 会自动传递三个参数($1 = "GROUP"|"INSTANCE",$2 = name of group or instance,$3 = target state of transition(MASTER/BACKUP/FAULT))。
    notify <STRING>|<QUOTED-STRING>
    # 表示是否开启邮件通知(用全局区域的邮件设置来发通知)。
    smtp_alert
    # 忽略 VRRP 网卡错误。
    dont_track_primary 
    # 修改 vrrp 组播包的源地址,默认源地址为 master 的 IP(由于是组播,因此即使修改了源地址,该 master 还是能收到回应的)。
    mcast_src_ip <IPADDR> 
    # 绑定 lvs syncd 的网卡。
    lvs_sync_daemon_interface eth1
    # 调用 vrrp_script 检查脚本块
    track_script {
        chk_down
    }
    #  监控以下网卡,如果任何一个不通就会切换到 FAIL 状态。
    track_interface {
        eth0
        eth1
    }
    # 当切为主状态后多久更新 ARP 缓存,默认 5 秒。
    garp_master_delay 10
}
# LVS ipvs 配置
virtual_server 192.168.200.100 443 {
    # 延迟轮询时间(单位秒)。
    delay_loop 6
    # 后端调试算法(load balancing algorithm)。
    lb_algo rr
    # LVS 调度类型 NAT/DR/TUN。
    lb_kind NAT
    # 用来给 HTTP_GET 和 SSL_GET 配置请求 header 的。
    virtualhost <STRING>
    # 当所有 real server 宕掉时,sorry server 顶替。
    sorry_server <IPADDR><PORT>
    # 掩码
    nat_mask 255.255.255.0
    persistence_timeout 50
    # 使用的协议
    protocol TCP
    # 真正提供服务的服务器。
    real_server 192.168.201.100 443 {
        # 权重
        weight 1
        # 当 real server 启动时执行的脚本。
        notify_up <STRING>|<QUOTED-STRING>
        # 当 real server 宕掉时执行的脚本。
        notify_down <STRING>|<QUOTED-STRING>
        # HTTPS 监控检测,除此之外常用的还有 HTTP_GET、TCP_CHECK
        SSL_GET {
            url {
              # 请求 real serserver 上的路径。
              path /
              # 用 genhash 算出的结果。
              digest ff20ad2481f97b1754ef3e12ecd3a9cc
              #  http 状态码。
              status_code <INT>
            }
            # 健康检查,如果端口通则认为服务器正常。
            connect_port <PORT>
            # 超时时长。
            connect_timeout 3
            # 重试次数。
            nb_get_retry 3
            # 下次重试的时间延迟。
            delay_before_retry 3
        }
    }
}

启用日志记录

keepalived 默认是没启用日志记录的,如果要启用,则需要手动指定记录日志的设施,以将日志记录到自定的 local3 设施为例。

1、修改 /etc/sysconfig/keepalived 配置如下:

KEEPALIVED_OPTIONS="-D -S 3"

这个配置的选项之所以能生效,是因为 keepalived 的 unit 启动文件中有加载 KEEPALIVED_OPTIONS 这个变量,对应的 unit 文件为 /usr/lib/systemd/system/keepalived.service

2、然后需要在 rsyslog 配置中添加 local3 设施:

$ vim /etc/rsyslog.conf 
local3.*                                                /var/log/keepalived.log

3、重启 rsyslog 服务并启动 keepalived:

$ systemctl restart rsyslog
$ systemctl restart keepalived

当然,如果多台主机都要开启 keepalived 日志,那么每台主机都要做如上修改。

实例

我这里先准备如下 IP 地址的两台主机:

主机名IP
test21010.0.1.210
test20510.0.1.205

在两台主机上都启用 keepalived(当然这两台主机上的 keepalived 属于同一组),配置这组 keepalived 的 VIP 为 10.0.1.220,并设置 A 主机的优先级高于 B 主机。

实例一:抢占模式

抢占模式的效果是,当 A 主机宕机时,VIP 将会自动飘到 B 主机,然后当 A 主机启用后,VIP 又会被 A 主机抢占回来,因为 A 主机的优先级更高。

A 主机配置:

global_defs {
   router_id test210
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.1.220
    }
}

B 主机配置:

global_defs {
   router_id test205
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
	    10.0.1.220
    }
}

上面其实有说过当其他节点的 keepalived 启动时会将 priority 比较大的节点选举为 MASTER,此项其实没有实质用途。但是在抢占模式下还是推荐将高优先级的主节点的 state 需指定为 MASTER,备节点的 state 需指定为 BACKUP,这样配置会更加清晰~~~

除了上述的抢占模式还可配置非抢占模式,在非抢占模式下,当 VIP 确定在绑定 A 主机上后,即便有 B 主机上 keepalvied 配置的优先级比 A 主机配置的优先级高,VIP 依旧会绑定在当前 A 主机上,除非 A 主机的 keepalived 服务不可用了,VIP 才会流动到 B 主机。
非抢占模式的配置非常简单,只需要将上述两个主机的配置中的 state 都设为 BACKUP,并在 vrrp_instance 块中添加 nopreempt 指令即可,我这里就不再演示啦~~~。

实例二:执行检查脚本

在上面的配置说明中已经有讲到,我们可以通过 vrrp_script 块来指定要执行的脚本或命令,然后通过在 vrrp_instance 块中定义 track_script 块来调用 vrrp_script 块定义的脚本,并且可以定义这个脚本的执行间隔时间,还可以定义当脚本执行失败时对当前的 vrrp_instance 权重(priority)的增降。

直接看实例吧~下面基于「实例一:抢占模式」进行修改,仅修改 A 主机配置,B 主机配置不变。

在 A 主机配置中添加如下 vrrp_script 块,并在 vrrp_instance 中通过 track_script 调用它:

global_defs {
    ...
}

vrrp_script check_down {
    script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0"
    interval 1
    weight -3
}

vrrp_instance VI_1 {
    ...
    track_script {
        check_down
    }
}

下面对如上配置做下解释,首先,在实例一中 A 主机为主节点且它的权重值为 100,B 主机为备节点且它的权重值为 99,我们来通过 check_down 脚本块每秒钟执行一次 [[ -f /etc/keepalived/down ]] && exit 1 || exit 0,即当存在指定文件时,就把命令执行退出码设为非 0,此时对应调用此 vrrp_scriptvrrp_instance 的权重值就会对应的减 3,在这里也就是 A 主机的权重值 100-3,此时 A 主机的权重值就低于 B 主机的 99,由于此时是抢占模式,VIP 会被 B 主机所抢占。当我们删除 A 主机上的指定文件时,此时脚本的退出执行状态码为 0,则恢复正常的权重值 100,比 B 主机的权重值高,所以此时 B 主机的 VIP 又会被 A 主机抢占回来。

实例三:高可用 LVS

这里我们就基于「lvs-dr」实例来进行修改。
这里主要的几个修改点如下:

  • 由于这里我们要给 Director 做高可用,所以我们要在该实例的基础上再添加一个 Director 主机;
  • 原来 Director 的 VIP 是我们通过命令手动添加的,而现在我们需要将 VIP 交给 keepalived 管理;

我这里的修改后的主机规划如下:

IP描述
10.0.1.200Director1
10.0.1.204Director2
10.0.1.201Real Server1
10.0.1.202Real Server2

这四台主机使用同一个 VIP,并且 RIP、VIP、DIR 在同一网段,这里我们依旧使用之前的 10.0.1.199 作为 VIP。

这里 Real Server 就不用修改了,我们仅需要把原来的 Director 上的 ipvs 规则清空,然后配置一下 keepalived 即可,下面就开始吧~~

下面的操作是在 Director 已经清空 ipvs 规则并且安装好 keepalived 之后进行的。

1、修改 Director1 的 keepalived 配置如下:

global_defs {
   router_id director1
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.1.199/32
    }
}
# 配置一个集群服务
virtual_server 10.0.1.199 80 {
    # 轮询延迟时间为 6 秒
    delay_loop 6
    # 调度算法
    lb_algo wrr
    # lvs 模式/类型
    lb_kind DR
    # 掩码
    netmask 255.255.255.255
    # 协议
    protocol TCP
    # 当 Real Server 都不能正常访问时,返回 sorry_server 指定的内容,前提是指定的 sorry_server 开启了 web 服务
    sorry_server 127.0.0.1 80
    # 配置第一个 Real Server
    real_server 10.0.1.201 80 {
        # 权重
        weight 1
        # 监控检查方式,这里也可以使用 TCP_CHECK,内部只指定超时时间即可
        HTTP_GET {
            # 配置健康检查的 URL 
            url {
                # 指定 URL
                path /
                # 当响应状态码为 200 时才视为服务正常
                status_code 200
            }
            # 连接超时时间
            connect_timeout 3
            # 失败重试次数
            nb_get_retry 3
            # 重试延迟时间
            delay_before_retry 3
        }
    }
    # 配置第二个 Real Server
    real_server 10.0.1.202 80 {
        weight 2
        HTTP_GET {
            url {
                path /
                status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

2、修改 Director2 的 keepalived 配置如下:

global_defs {
   router_id director2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.1.199/32
    }
}

virtual_server 10.0.1.199 80 {
    delay_loop 6
    lb_algo wrr
    lb_kind DR
    netmask 255.255.255.255
    protocol TCP
    sorry_server 127.0.0.1 80

    real_server 10.0.1.201 80 {
        weight 1
        HTTP_GET {
            url {
                path /
                status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
    real_server 10.0.1.202 80 {
        weight 2
        HTTP_GET {
            url {
                path /
                status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

完成上述配置后,启动两个 Director 上的 keepalived 服务,此时两个 Director 上会自动配置上如下 ipvs 规则:

$ 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.1.199:80 wrr
  -> 10.0.1.201:80                Route   1      0          0         
  -> 10.0.1.202:80                Route   2      0          0     

是不是和我们手动通过 ipvsadm 命令添加的规则一模一样~只是这里 Director 的 VIP 是由 keepalived 服务控制流动的,当一个 Director 宕机时,VIP 就会流动到另一个 Director 上,由另一个 Director 正常提供服务,从而完成了 LVS 高可用架构的构建~~~

实例四:高可用 Nginx

对于 Nginx 的高可用其实仅需要在实例一的基础上进行修改,只需要保证 VIP 所在主机上的 Nginx 可用即可。那 keepalived 如何能获知 Nginx 是否可用呢?

我们可以编写一个 shell 脚本,该脚本的功用为判断 Nginx 的状态,当检测到 Nginx 进程不存在或不正常时,就重启 Nginx,如果重启失败,则停止当前主机的 keepalived 服务,如果当前主机的 keepalived 服务不可用了,那么 VIP 将会流动到其它可用的主机上,从而实现 Nginx 的高可用。

实现步骤如下:

1、编写检测 Nginx 健康状态的脚本:

$ cat /scripts/check_nginx.sh 
killall -0 nginx
if [ $? -ne 0 ];then
    systemctl start nginx
    sleep 5
        killall -0 nginx
    if [ $? -ne 0 ];then
        systemctl stop keepalived
    fi
fi

killall0 信号可以用来检测一个进程的健康状态,如果进程是健康状态,那么将会返回状态码 0,否则将会返回 1

2、在 keepalived 的配置文件中使用 vrrp_script 块来周期性的调用这个脚本:

vrrp_script check_nginx
{
        script "/scripts/check_nginx.sh"
        interval 2
}

3、在对应 vrrp_instance 块中使用 track_script 块启用上面定义的 vrrp_script 块:

track_script {
        check_nginx
}

这里我就不演示 Nginx 的配置及启动效果啦~~重点是要理解上述内容的含义。

0

评论区