傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波
写在前面
今天和小伙伴们分享一些 Keepalived 相关笔记
博文内容涉及:
vrrp 协议由来
Ansible 方式 Keepalived安装部署
Keepalived 脚本方式配置服务检查
Keepalived 自动化部署 Ansible 角色编写
食用方式:
需要 Linux 基础知识
需要 Ansible 基础知识
理解不足小伙伴帮忙指正
傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波
官网帮助文档:https://www.keepalived.org/manpage.html
关于keepalived是什么,在官网中这样描述:
Keepalived 是一个用 C 语言编写的路由软件
。该项目的主要目标是为 Linux 系统和基于 Linux 的基础架构提供简单而强大的负载平衡
和高可用性设施
。
负载平衡
框架依赖于众所周知且广泛使用的Linux 虚拟服务器 (IPVS
) 内核模块,提供第 4 层负载平衡。Keepalived 实现了一组检查器,以根据其健康状况动态和自适应地维护和管理负载平衡的服务器池。(本文不涉及)
高可用性
是通过 VRRP实现的协议
。VRRP 是路由器故障转移的基础。此外,Keepalived 实现了一组与 VRRP 有限状态机的挂钩,提供低级和高速协议交互。为了提供最快的网络故障检测,Keepalived 实现了BFD协议。VRRP 状态转换可以考虑 BFD 提示来驱动快速状态转换。Keepalived 框架可以单独使用,也可以一起使用,以提供弹性基础架构
Keepalived 是免费软件;您可以根据自由软件基金会发布的 GNU 通用公共许可条款重新分发和/或修改它;许可证的第 2 版,或(由您选择)任何更高版本。
今天和小伙伴分享的主要是高可用热备部署
,关于负载均衡方面的之后和小伙伴们分享,在部署keepalived之前,需要了解下VRRP协议
vrrp协议由来 当网关路由器出现故障时,本网段内以该设备为网关的主机都不能与 Internet 进行通信。所以需要进行容灾处理,但是通过部署多网关的方式实现网关的备份,存在一些问题:网关间IP地址冲突;主机会频繁切换网络出口。所以为解决网关路由的单点故障,有了VRRP协议。
VRRP即虚拟路由冗余协议
,VRRP能够在不改变组网的情况下,从多台网关
设备里产生一个虚拟路由器
,通过配置虚拟路由器的IP地址为默认网关
,实现网关的备份。
对外提供网关服务的是这个虚拟路由器。这样不管是真实路由器哪个出现问题,都不会影响整个网络的运行,提高了网络结构的稳定性。
VRRP配置方式:
配置VRRP的成员;
配置VRRP的优先级 (默认100);
查看VRRP信息
VRRP协议通过一种竞选机制来将路由任务交给某个vrrp路由器的。
在VRRP物理结构中,有多个物理的VRRP路由器,其中有一台称为“master”(主节点路由器),其他的都是“backup”(备节点路由器)
在VRRP虚拟结构中,虚拟路由都是通过MAC+VRID
的形式来标识的,如54-89-98-6F-3D-B5-{vrid}
只有master节点才会发送VRRP包(vrrp advertisement message)当master节点宕掉的时候,backup中优先级最高的VRRP设备会抢占并升级为master
下面为配置的简单Demo
三层交换机SW1上配置, 主路由器(Master)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <Huawei>system-view [Huawei]sysname SW1 [SW1] [SW1]undo info-center enable [SW1]interface Vlanif 1 [SW1-Vlanif1]ip address 192.168.1.252 255.255.255.0 [SW1-Vlanif1]vrrp vrid 1 virtual-ip 192.168.1.254 [SW1-Vlanif1]vrrp vrid 1 priority 105 [SW1-Vlanif1] [SW1-Vlanif1]display vrrp brief
三层交换机SW2上配置,,备用路由器(backup)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <Huawei>system-view [Huawei]sysname SW2 [SW2] [SW2]undo info-center enable [SW2]interface Vlanif 1 [SW2-Vlanif1]ip address 192.168.1.253 255.255.255.0 [SW2-Vlanif1]vrrp vrid 1 virtual-ip 192.168.1.254 [SW2-Vlanif1]display vrrp brief
keepalived 安装部署 回到keepalived中,keepalived 通过VRRP(Virtual Router Redundancy Protocol)虚拟路由冗余协议来实现故障转移。keepalived正常工作时,主节点(master)会不断的发送心跳信息给备节点(backup)
1 2 3 4 5 6 7 8 9 10 11 12 13 ┌──[root@vms153.liruilongs.github.io]-[~] └─$tcpdump -i ens32 -nn host 224.0.0.18 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens32, link-type EN10MB (Ethernet), capture size 262144 bytes 23:27:36.149062 IP 192.168.26.153 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20 23:27:37.150969 IP 192.168.26.153 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20 23:27:38.152021 IP 192.168.26.153 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 100, authtype simple, intvl 1s, length 20 ^C 3 packets captured 3 packets received by filter 0 packets dropped by kernel ┌──[root@vms153.liruilongs.github.io]-[~] └─$
当备节点在一定时间内没有收到主节点的心跳信息时,备节点会认为主节点宕了,就会接管主节点上的资源,并继续向外提供服务保证其可用性,当主节点恢复时,备节点会自动让出资源并再次自动成为备节点
这里我们通过 ansible 安装配置,下面的两台机器为我们要配置的机器,也就是node组,在master节点操作
192.168.26.153
192.168.26.154
1 2 3 4 5 6 7 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat inventory [master] 192.168.26.152 [node] 192.168.26.153 192.168.26.154
安装web服务测试用
1 2 ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible node -m shell -a "yum -y install httpd"
编写一个小剧本用于环境初始化,这个剧本实现对httpd服务的欢迎页进行内容填充,重启服务,设置防火墙域为trusted,即没有规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat httpd.yaml --- - name: httpd init hosts: node tasks: - name: httpd content shell: "echo `hostname` > /var/www/html/index.html" - name: Restart service httpd, in all cases service: name: httpd state: restarted - name: firewall shell: firewall-cmd --set-default-zone=trusted ┌──[root@vms152.liruilongs.github.io]-[~] └─$
执行剧本并测试填充结果测试
1 2 3 4 5 6 7 8 9 10 11 ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible -playbook httpd.yaml ........ ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible node -m shell -a 'hostname;cat /var/www/html/index.html' 192.168.26.154 | CHANGED | rc=0 >> vms154.liruilongs.github.io vms154.liruilongs.github.io 192.168.26.153 | CHANGED | rc=0 >> vms153.liruilongs.github.io vms153.liruilongs.github.io
安装 keepalived,我们使用的版本为:keepalived-1.3.5-19.el7.x86_64
1 2 3 4 ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible node -m yum -a 'name=keepalived state=installed' 192.168.26.154 | SUCCESS => { 。。。。。。
编辑配置文件模板
,把主备节点配置文件中不一样的,或者希望单独设置的内容做成变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat keepalived.conf.j2 ! Configuration File for keepalived global_defs { router_id LVS_DEVEL vrrp_iptables } vrrp_instance VI_1 { state {{ role }} interface ens32 virtual_router_id 51 priority {{ priority }} advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.26.200 } }
编写剧本,复制模板文件,然后重启keepalived服务,这里我们通过两个小剧本的方式传递不同的变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat keepalived.yaml --- - name: vms153.liruilongs.github.io config hosts: 192.168 .26 .153 tags: - master vars: role: MASTER priority: 100 tasks: - name: copy keeplived config template: src: keepalived.conf.j2 dest: /etc/keepalived/keepalived.conf - name: restart keeplived service: name: keepalived state: restarted - name: vms154.liruilongs.github.io config hosts: 192.168 .26 .154 tags: - backup vars: role: BACKUP priority: 50 tasks: - name: copy keepalived config template: src: keepalived.conf.j2 dest: /etc/keepalived/keepalived.conf - name: restart keepalived service: name: keepalived state: restarted
运行剧本并测试
1 2 3 ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible -playbook keepalived.yaml 。。。。。。。。。。。
假设153机器应为某些原因,需要进行停机处理,我们可以直接把 keepalived 干掉,vip自动切到154
1 2 3 4 5 6 7 8 9 10 11 12 ┌──[root@vms152.liruilongs.github.io]-[~] └─$curl 192.168.26.200:80 vms153.liruilongs.github.io ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible 192.168.26.153 -m shell -a "systemctl stop keepalived" 192.168.26.153 | CHANGED | rc=0 >> ┌──[root@vms152.liruilongs.github.io]-[~] └─$curl 192.168.26.200:80 vms154.liruilongs.github.io ┌──[root@vms152.liruilongs.github.io]-[~] └─$
如果这个时候153机器恢复,那么我们可以重新拉起keepalived服务,vip回到153
1 2 3 4 5 6 7 ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible 192.168.26.153 -m shell -a "systemctl start keepalived" 192.168.26.153 | CHANGED | rc=0 >> ┌──[root@vms152.liruilongs.github.io]-[~] └─$curl 192.168.26.200:80 vms153.liruilongs.github.io
上面的操作,我们可以整合到一个剧本里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat keepalived.yaml --- - name: keepalived init hosts: node tasks: - name: install yum: name: - httpd - keepalived state: installed - name: httpd content shell: "echo `hostname` > /var/www/html/index.html" - name: Restarted httpd service: name: httpd state: restarted - name: firewall clons shell: firewall-cmd --set-default-zone=trusted - name: vms153.liruilongs.github.io config hosts: 192.168 .26 .153 tags: - master vars: role: MASTER priority: 100 vip: 192.168 .26 .200 interface: ens32 tasks: - name: copy keeplived config template: src: keepalived.conf.j2 dest: /etc/keepalived/keepalived.conf - name: restart keepalived service: name: keepalived state: restarted - name: vms154.liruilongs.github.io config hosts: 192.168 .26 .154 tags: - backup vars: role: BACKUP priority: 90 vip: 192.168 .26 .200 interface: ens32 tasks: - name: copy keepalived config template: src: keepalived.conf.j2 dest: /etc/keepalived/keepalived.conf - name: restart keepalived service: name: keepalived state: restarted
对于配置文件也可以更灵活一点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat keepalived.conf.j2 ! Configuration File for keepalived global_defs { router_id LVS_DEVEL vrrp_iptables } vrrp_instance VI_1 { state {{ role }} interface {{ interface }} virtual_router_id 51 priority {{ priority }} advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { {{ vip }} } }
有小伙伴会讲,这也太水了,每次故障都需要自己去进行主备切换,其实上面的配置为keepalived的最简单配置,没有使用keepalived 的检查配置,,告警等其他的功能。
如果是IPVS使用keepalived,可以对后端RealServer进行健康状况检查,支持网络层、传输层、应用层进行健康检查。
配置文件解析 熟悉下配置文件,keepalived的配置文件主要由3部分构造,ipvs配置,全局配置,VRRP配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 global_defs { ... } vrrp_instance NAME { ... } vrrp_sync_group NAME { ... } Virtual server groups Virtual server
下面为具体的参数解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat /etc/keepalived/keepalived.conf ! 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 192.168.200.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_mcast_group4 225.0.0.18 } vrrp_script <SCRIPT_NAME> { script "/etc/keepalived/chk_script.sh" interval INT weight -INT } 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 { 192.168.200.16 192.168.200.17 192.168.200.18 } track_script { chk_service } nopreempt preempt_delay TIME notify_master <STRING>|<QUOTED-STRING> notify_backup <STRING>|<QUOTED-STRING> notify_fault <STRING>|<QUOTED-STRING> notify <STRING>|<QUOTED-STRING> }
服务检查 在上面的Demo的基础上,我们添加一个检查脚本,使用下面的检查策略。来检查httpd服务是否可用
1 2 3 4 5 6 7 8 9 10 11 12 ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl status httpd > /dev/null ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$echo $? 0 ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl stop httpd.service ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl status httpd > /dev/null ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$echo $? 3
也可以這樣
1 2 3 4 5 6 7 8 9 10 11 12 ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl is-active httpd -q ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$echo $? 3 ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl start httpd ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl is-active httpd -q ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$echo $? 0
或者這樣
1 2 3 4 5 6 ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl show httpd -p ActiveState ActiveState=active ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl show httpd -p ActiveState | sed 's/ActiveState=//g' active
是否运行和是否活跃是两个概念,对于某些一次性服务可以使用下面的方式验证
1 2 3 4 5 6 7 8 ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl show httpd -p ActiveState | cut -d'=' -f2 active ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$systemctl show httpd -p SubState | cut -d'=' -f2 running ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$
keepalived部署服务健康检查剧本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat keepaliveds.yaml --- - name: keepalived init hosts: node tasks: - name: install yum: name: - httpd - keepalived state: installed - name: httpd content shell: "echo `hostname` > /var/www/html/index.html" - name: Restarted httpd service: name: httpd state: restarted - name: firewall clons shell: firewall-cmd --set-default-zone=trusted - name: vms153.liruilongs.github.io config hosts: 192.168 .26 .153 tags: - master vars: role: MASTER priority: 100 tasks: - name: copy keeplived config template: src: keepalived.conf.j2 dest: /etc/keepalived/keepalived.conf - name: copy che_service copy: content: "#!/bin/sh\nsystemctl is-active httpd -q" dest: /etc/keepalived/che_service.sh backup: yes mode: '0755' - name: restart keepalived service: name: keepalived state: restarted - name: vms154.liruilongs.github.io config hosts: 192.168 .26 .154 tags: - backup vars: role: BACKUP priority: 90 tasks: - name: copy keepalived config template: src: keepalived.conf.j2 dest: /etc/keepalived/keepalived.conf - name: copy che_service copy: content: "#!/bin/sh\nsystemctl is-active httpd -q" dest: /etc/keepalived/che_service.sh mode: '0755' backup: yes - name: restart keepalived service: name: keepalived state: restarted
运行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ┌──[root@vms152.liruilongs.github.io]-[~] └─$curl 192.168.26.200 vms153.liruilongs.github.io ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible 192.168.26.153 -m service -a 'name=httpd state=stopped' 192.168.26.153 | CHANGED => { "ansible_facts" : { "discovered_interpreter_python" : "/usr/bin/python" }, "changed" : true , "name" : "httpd" , "state" : "stopped" , ............. ┌──[root@vms152.liruilongs.github.io]-[~] └─$curl 192.168.26.200 vms154.liruilongs.github.io ┌──[root@vms152.liruilongs.github.io]-[~] └─$
配置文件模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ┌──[root@vms152.liruilongs.github.io]-[~] └─$cat keepalived.conf.j2 ! Configuration File for keepalived global_defs { router_id LVS_DEVEL vrrp_iptables } vrrp_script chk_service { script /etc/keepalived/che_service.sh interval 2 } vrrp_instance VI_1 { state {{ role }} interface ens32 virtual_router_id 51 priority {{ priority }} advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.26.200 } track_script { chk_service } }
这个剧本调了好些时间,需要注意的是,配置文件不能有其他的非空格的字符,检查脚本要记得授权
,如果没有执行检查脚本,可以看下 /var/log/messages
日志文件
1 2 ┌──[root@vms153.liruilongs.github.io]-[/etc/keepalived] └─$cat /var/log /messages | grep -C 10 track
keepalived 角色编写 我们也可以把上面的剧本编写为角色,需要把handlers和和其他的东西抽出来
1 2 3 4 5 6 7 8 9 ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible -galaxy init keepalived --init-path=./roles - Role keepalived was created successfully ┌──[root@vms152.liruilongs.github.io]-[~] └─$ansible -galaxy list - keepalived, (unknown version) ┌──[root@vms152.liruilongs.github.io]-[~] └─$
编写task
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$cat tasks/main.yml --- - name: Install keepalived yum: name: keepalived state: latest tags: keepalived notify: restart keepalived - name: Keepalived configuration template: src: keepalived.conf.j2 dest: /etc/keepalived/keepalived.conf notify: restart keepalived - when: check_service_name | default(False) name: Install check script copy: content: "#!/bin/sh\nsystemctl is-active {{ check_service_name }} -q" dest: /etc/keepalived/che_service.sh backup: yes mode: 0755 owner: root group: root notify: restart keepalived - name: Start keepalived service: name: keepalived state: started enabled: yes
编写handlers
1 2 3 4 5 6 7 8 9 10 11 ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$cat handlers/main.yml --- - name: restart keepalived service: name: keepalived state: restarted ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$
编写template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$cat templates/keepalived.conf.j2 ! Configuration File for keepalived global_defs { router_id LVS_DEVEL vrrp_iptables } vrrp_script chk_service { script /etc/keepalived/che_service.sh interval 2 } vrrp_instance VI_1 { state {{ keep_role }} interface {{ keep_interface }} virtual_router_id 51 {% if keep_role.lower() == 'master' %} priority {{ keep_priority }} {% else %} priority {{ keep_backup_priority }} {% endif %} advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { {{ virtual_ipaddress }} dev {{ keep_interface }} } track_script { chk_service } } ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$
编写defaults变量
1 2 3 4 5 6 7 8 9 10 11 ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$cat defaults/main.yaml --- keep_role: "master" keep_priority: 100 keep_backup_priority: 50 keep_interface: "ens32" virtual_ipaddress: "192.168.26.200" check_service_name: httpd
编写调用剧本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$cat tests/test.yml --- - hosts: 192.168.26.153 vars: keep_role: MASTER roles: - keepalived - hosts: 192.168.26.154 vars: keep_role: BACKUP roles: - keepalived ┌──[root@vms152.liruilongs.github.io]-[~/roles/keepalived] └─$
博文参考
https://www.keepalived.org/manpage.html
https://www.cnblogs.com/hgzero/p/13718516.html
https://unix.stackexchange.com/questions/396630/the-proper-way-to-test-if-a-service-is-running-in-a-script
https://github.com/tcomerma/ansible-keepalived/
https://github.com/demis-svenska/aws-echis/tree/master/src/commcare_cloud/ansible/roles/keepalived