Keepalived 是一个基于 VRRP 协议来实现的服务高可用方案,可以利用其来避免 IP 单点故障,一般与其它负载均衡技术(如 LVS 、HAProxy 、Nginx)一起工作来达到集群的高可用。Keepalived 是 LVS 的扩展项目, 因此它们之间具备良好的兼容性,可直接通过 Keepalived 的配置文件来配置 LVS。
相关术语
- LB (Load Balancer 负载均衡)
- HA (High Available 高可用)
- Failover (失败切换)
- Cluster (集群)
- LVS (Linux Virtual Server Linux 虚拟服务器)
- DS (Director Server),指的是前端负载均衡器节点
- RS (Real Server),后端真实的工作服务器
- VIP (Virtual IP),虚拟的 IP 地址,向外部直接面向用户请求,作为用户请求的目标的 IP 地址
- DIP (Director IP),主要用于和内部主机通讯的 IP 地址
- RIP (Real Server IP),后端服务器的 IP 地址
- CIP (Client IP),访问客户端的 IP 地址
- 准备两台主机,四个IP:
192.168.100.226 192.168.100.224 192.168.100.201(VIP) 192.168.100.202(VIP)
2.安装keepalived
- 通过 yum源进行安装
yum -y install keepalived
- 通过源码安装
官方下载keepalived源码包
# 安装依赖 yum install -y libnfnetlink-devel zlib zlib-devel gcc gcc-c++ openssl openssl-devel openssh
tar -xf keepalived-2.1.0 # 解压安装包 cd keepalived-2.1.0 # 进入安装包 ./config --prefix=/usr/local/keepalived # 编译指定安装路径 make && make install # 编译完成后进行安装 ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/ # 创建软连接 ls /usr/sbin/ | grep keepalived > keepalived cd /usr/local/keepalived/etc/ cp -r keepalived /etc/keepalived cp sysconfig/keepalived /etc/sysconfig/keepalived
- 修改配置
配置文件在/usr/local/keepalived目录下
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived global_defs { script_user root 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 LVS_DEVEL vrrp_skip_check_adv_addr vrrp_strict vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_script chk_http_port { script "/data/shell/check.sh httpd" interval 0 weight -2 vrrp_instance VI_1 { state BACKUP # BACKUP为备 interface eth0 virtual_router_id 101 priority 80 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.100.201 dev eth0 label eth0:1 } vrrp_instance VI_2 { # 当有两个VIP时vrrp_instance应当区分开 state MASTER # MASTER为主 interface eth0 # 工作接口 virtual_router_id 102 # 虚拟路由ID,如果是一组虚拟路由就定义一个ID,如果是多组就要定义多个; # 而且这个虚拟ID还是虚拟MAC最后一段地址的信息,取值范围0-255 priority 100 # 定义优先级,数值越高,优先级越高 advert_int 1 # 通告频率,秒 track_interface { # 监听的网卡,网卡故障马上切换vip eth0 ens33 } authentication { # 通信机制,这里是明文,还有加密 auth_type PASS auth_pass 1111 } virtual_ipaddress { # 配置虚拟VIP,这里配置在网卡eth0,别名是eth0:2 192.168.100.202 dev eth0 label eth0:2 } }
主机2的配置文件,只需修改参数
state BACKUP # 主机1为MASTER时,主机2为BACKUP priority 80 # 这里配置坚持master的优先级大于backup即可,根据state属性定义
- 启动keepalived
systemctl restart keepalived
另一台是没有vip
停掉主机
查看备机
配置监控脚本
vim check.sh
#!/bin/bash Date=$(date "+%Y-%m-%d %H:%M:%S") log_file="/var/log/keepalived.log" check_process() { if [ -z "$1" ]; then echo "进程名为空........" echo "[$Date] 执行脚本无参数......" >> $log_file exit fi process_status=`pidof $1` if [ "$process_status" != "" ]; then return 10 else: return 11 fi } check_process $1 if [ $? -eq 10 ]; then echo 0 exit 0 else echo "[$Date] 进程[$1]异常,正在准备重启....." >> $log_file count=0 while (($count < 3)) do ((count++)) echo "[$Date] 尝试第$count次拉起进程$1......" >> $log_file systemctl restart $1 2&> /dev/null check_process $1 if [ $? -eq 10 ]; then echo "[$Date] 进程$1已拉起......." >> $log_file echo 0 exit 0 fi done echo 1 echo "[$Date] 尝试拉起进程$1三次均失败......" >> $log_file systemctl stop keepalived exit 1 fi
调试脚本,脚本需要传参,传参为进程名
/bin/bash check_process.sh nginx
- 创建用户keepalived_script
useradd keepalived_script
启动失败可查看keepalived日志
tail -f /var/log/messages
python的一键部署keepalived脚本
从下载源码包到修改配置启动服务
# encoding: utf-8 import sys import os version = '2.2.2' # keepalived版本号 tar_name = "keepalived-{}.tar.gz".format(version) # 源码包名 download_file = "https://www.keepalived.org/software/{}".format(tar_name) # keepalived的官网下载地址 instanll_path = "/usr/local/keepalived" # 安装路径 file_path = '/tmp/keepalived' # 源码包存储位置 MASTER = 0 # 0表示为主,非0表示为从 network = 'ens33' # 监听的网卡名 network_bn = "ens33:02" # 网卡别名 virtual_router_id = 52 # 路由id,两个keepalived的需要一致 priority = 99 # 权重,master的要大于从的 advert_int = 1 Vip = "192.168.43.111" # 虚拟ip chk_http_port = 'chk_http_port' httpd = "httpd" # 监控的进程名(需要依赖上面的监控脚本,将上面的监控脚本复制一份保存为/data/shell/check.sh) def mkdir_path(files_path): if not os.path.exists(files_path): os.makedirs(files_path) def wget_tar(): s = os.system("which wget") if s != 0: print("主机无wget命令,正在尝试安装.....") install_wget = "yum -y install wget" w = os.system("install_wget") if w == 0: print("安装wget成功!!") return "ok" else: print("wget命令安装失败,请检查网络或yum源!!!") exit(0) else: return "ok" def sed_file(file): s = '\ script_user root' s1 = '\ vrrp_script chk_http_port {' s2 = '\ script "/data/shell/check.sh {} "'.format(httpd) s3 = '\ interval 0' s4 = '\ weight -2' s5 = '}' s6 = '\ vrrp_instance VI_2 {' if MASTER == 0: s7 = '\ state MASTER' else: s7 = '\ state BACKUP' s8 = '\ interface {}'.format(network) s9 = '\ virtual_router_id {}'.format(virtual_router_id) s10 = '\ priority {}'.format(priority) s11 = '\ advert_int {}'.format(advert_int) s12 = '\ track_interface {' s13 = '\ {}'.format(network) s14 = '\ }' s15 = '\ authentication {' s16 = '\ auth_type PASS' s17 = '\ auth_pass 1111' s18 = '\ }' s19 = '\ virtual_ipaddress {' s20 = '\ {} dev {} label {}'.format(Vip, network, network_bn) s21 = '\ }' s22 = '\ track_script {' s23 = '\ chk_http_port' s24 = '\ }' s25 = '}' cmd_list = [s, s1, s2, s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s20,s21,s22,s23,s24,s25] os.system("sed -i '18,$d' {}".format(file)) for cmd in cmd_list: os.system("echo {} >> {}".format(cmd, file)) def download_tar(): install_yl = os.system('yum install -y libnfnetlink-devel zlib zlib-devel gcc gcc-c++ openssl openssl-devel openssh') if install_yl == 0: print("依赖安装完成!!!") else: print("依赖安装失败!!!") exit(0) d_status = os.system('cd {} && wget {}'.format(file_path, download_file)) #d_status = 0 if d_status ==0: if os.path.exists(file_path + '/' + tar_name): mkdir_path(instanll_path) tar_cmd = 'cd {} &&tar -xf {} && cd {}/keepalived-{} && ./configure --prefix={} && make && make install'.format(file_path, tar_name,file_path, version, instanll_path) tar_s = os.system(tar_cmd) if tar_s ==0: print("安装编译成功!!!") ln_cmd = "ln -s {}/sbin/keepalived /usr/sbin/" ln_s = os.system(ln_cmd) if ln_s == 0: print("软连接创建成功!!") cp_cmd = "cp -r {}/etc/keepalived /etc/ && cp -r {}/etc/sysconfig/keepalived /etc/sysconfig/".format(instanll_path, instanll_path) cp_s = os.system(cp_cmd) if cp_s == 0: add_cmd = "useradd keepalived_script" os.system(add_cmd) print("配置文件copy完毕!!") sed_file('/etc/keepalived/keepalived.conf') # os.system("sed -i '/PIDFile/d' /lib/systemd/system/keepalived.service") # os.system("sed -i '7iPIDFile=run/keepalived.pid' /lib/systemd/system/keepalived.service") os.system("systemctl daemon-reload") start_cmd = "systemctl restart keepalived" start_s = os.system(start_cmd) if start_s == 0: print("keepalived安装完毕,已启动!!!") else: print("keepalived启动失败!!!") else: print("配置文件copy失败!!") else: print("软连接创建失败!!") else: print("安装编译失败!!!") exit(0) def main(): mkdir_path(file_path) status = wget_tar() if status == "ok": download_tar() else: print("退出安装!!") if __name__ == '__main__': main()
使用注意:
- 需要将上面的检查脚本保存为/data/shell/check.sh
监控的进程需要为system管理的进程,否则在检测到进程故障时无法重新拉起,将会直接ip漂移 - 使用时可以将一下代码保存为install_keepalived.py
- 配置文件中的基本参数可在脚本开头配置,如(安装路径、源码包存储路径、安装的软件包版本、VIP、是否为主等)
- 使用 python install_keepalived.py 命令执行
模块在centos系统自带python中有无需安装模块