Keepalived是个一个基于VRRP 协议来实现的 LVS 服务高可用方案的开源组件,可以利用其来解决单点故障问题。一个LVS服务器(Linux Virtual Server Linux虚拟服务器)会有2台服务器运行Keepalived,一台为主服务器(MASTER),一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,主服务器会发送特定的消息给备份服务器,当备份服务器收不到这个消息的时候,即主服务器宕机的时候, 备份服务器就会接管虚拟IP,继续提供服务,从而保证了高可用性。
当利用keepalived配置主备ip地址进行组建HA时,发现当使用的ip为子网卡上的ip时,组建HA失败。
[ root@localhost ~]# ifconfig
eth0: flags=4163 mtu 1500
inet 101.13.17.174 netmask 255.255.255.0 broadcast 10.14.15.255
inet6 2001:123::121 prefixlen 64 scopeid 0x0
inet6 fe80::eda:4lff:feld:b3f0 prefixlen 64 scopeid 0x20
ether 0c:da:4l:ld:b3:f0 txqueuelen 1000 (Ethernet)
RX packets 4275596 bytes 902081284 (860.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1526855 bytes 209418917 (199.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0:1: flags=4l63 mtu 1500
inet 101.13.17.233 netmask 255.255.255.0 broadcast 10.14.15.255
ether 0c:da:4l:ld:b3:f0 txqueuelen 1000 (Ethernet)
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0xl0
loop txqueuelen 1000 (L ocal Loopback )
RX packets 1062532 bytes 164572192 (156.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1062532 bytes 164572192 (156.9 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost ~]#
其中eth0:1 为eth0的子网卡。
先了解下eth0 和 eth0:1 的区别, eth0属于物理网卡,eth0:1属于子网卡。
物理网卡:物理网卡指的是服务器上实际的网络接口设备,比如上面的配置中只有一个eth0网络接口。
子网卡:子网卡在这里并不是实际上的网络接口设备,但是可以作为网络接口在系统中出现,如eth0:1、eth1:2这种网络接口。它们必须要依赖于物理网卡,虽然可以与物理网卡的网络接口同时在系统中存在并使用不同的IP地址,而且也拥有它们自己的网络接口配置文件。但是当所依赖的物理网卡不启用时(Down状态)这些子网卡也将一同不能工作。
因此从上面了解到,子网卡并不是实际的网络接口设备,依赖于对应的物理网卡。
接下来继续keepalived组HA时,主节点或者备节点配置子网卡上的ip时组HA失败问题。
当配置HA时,主或备节点使用子网卡上的ip时,启动keepalived时会出现如下错误
# cat keepalived.conf
! Configuration File for keepalived
global_defs{
router_id 11.12.13.54
}
vrrp_instance VI_1_t{
state BACKUP
insterface eth0:1
mcast_src_cp 11.12.13.54
virtual_router_id 99
priority 20
advert_int 1
nopreempt
authentication{
auth_type PASS
auth_pass 1111
}
virtual_ipaddress{
11.12.13.99
}
}
通过查看日志发现,主节点使用的ip为eth0上的ip,而备节点使用的ip为eth0:1上的ip,搭建HA时失败,通过查看日志,显示如下
# cat /var/log/messages
Keepalived_vrrp[42201]: Opening file '/opt/keepalived.conf'
...
Keepalived_vrrp[42201]: Cant find interface eth0:1 for vrrp_instance VI_1_t !!!
Keepalived_vrrp[42201]: Configuration error: VRRP definition must belong to an interface
Keepalived_vrrp[42201]: VRRP_Instance(VI_1_t) Unknown interface !
Keepalived_vrrp[42201]: Thread task.
...
从上面的日志来看,是没有找到实例对应的eth0:1网络接口。
根据keepalived的源码进行分析了解到
static void start_vrrp(void)
{
...
kernel_netlink_init();
...
init_data(conf_file, vrrp_init_keywords);
...
if(!vrrp_complete_init())
{
stop_vrrp(KEEPALIVED_EXIT_CONFIG);
return;
}
}
kernel_netlink_init()
{
...
init_interface_queue();
...
}
void init_interface_queue()
{
init_if_queue();
netlink_interface_lookup(NULL);
#ifdef _HAVE_VRRP_VMAC
set_base_ifp();
#endif
}
static void init_if_queue()
{
if_queue = alloc_list(free_if, dump_if);
}
1、keepalived启动时,在调用start_vrrp(void)时,会调用init_interface_queue(), 该函数的作用就是从内核中读取系统的网卡设备,然后把网卡信息放到if_queue的全局链表中。
if_queue链表中保存的都是实际的网卡设备信息,而eth0:1属于子网卡并不是实际的网络接口设备。因此链表中不存在eth0:1的信息。
void init_data(const char *conf_file, vector_t *(*init_keywords)(void))
{
...
(*init_keywords)();
...
}
vector_t * vrrp_init_keywords(void)
{
init_global_keywords(reload);
init_vrrp_keywords(true);
#ifdef _WITH_LVS_
init_check_keywords(false);
#endif
#ifdef _WITH_BFD_
init_bfd_keywords(true);
#endif
return keywords;
}
2、接下来start_vrrp(void)调用init_data(conf_file, vrrp_init_keywords)进行初始化。
init_data的作用就是读取keepalived.conf配置文件中的实例来初始化全局vrrp_data链表,vrrp_data中有个vrrp的链表,vrrp链表节点中保存的是vrrp_instance, 该vrrp_instance就是keepalived.conf配置文件中的关键字,然后获取配置中的信息,挂到vrrp链表节点中。
在初始化节点过程中当读到interface eth0:1时,会根据获取的名字eth0:1 从if_queue的全局链表中获取网卡接口实例信息来初始化vrrp节点中的ifp字段。由于获取不到,所以日志会打印:
Cant find interface eth0:1 for vrrp_instance VI_1_t !!!
此时ifp字段是空的。
在从配置文件读取virtual_ipaddress 初始化虚拟ip的时候(对应函数vrrp_vip_handler),它会判断ifp字段是否为空,若为空,则打印日志
Configuration error: VRRP definition must belong to an interface
bool vrrp_complete_init(void)
{
...
LIST_FOREACH(vrrp_data->vrrp, vrrp, e){
if(!vrrp_complete_instance(vrrp))
return false;
if(vrrp->ifp->mtu > max_mtu_len)
max_mtu_len = vrrp->ifp->mtu;
}
...
}
static bool vrrp_complete_instance(vrrp_t *vrrp)
{
....
if(!chk_min_cfg(vrrp))
return false;
...
}
static bool chk_min_cfg(vrrp_t *vrrp)
{
...
if(!vrrp->ifp){
log_message(LOG_INFO, "(%s) Unknown interface!", vrrp->iname);
return false;
}
}
3、接下来start_vrrp(void)调用vrrp_complete_init()进一步完成vrrp的初始化工作,同时判断一些之前的初始化值是否成功,由于第二步初始化ifp字段时该值为空,也就是找不到eth0:1的接口实例,因此会打印日志:
VRRP_Instance(VI_1_t) Unknown interface !
并返回失败,结束keepalived。
所以使用keepalived组HA使用子网卡的ip时,由于子网卡不是网络设备,导致keepalived启动时根据配置文件获取不到网卡信息,导致keepalived启动失败。
因此使用keepalived组HA使用子网卡的ip时,keepalived.conf中的insterface 字段要设置为子网卡(eth0:1)对应的物理网卡(eth0)。
脚本中根据子网卡ip获取物理网卡脚本如下:
[ rootelocalhost ~]# ip addr
l: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00: 00:00:00:00 brd 00: 00: 00:00:00:00
inet 127.0.0.1/8 scope host lo valid lft forever preferred lft forever inet6 : :1/128 scope host
valid lft forever preferred lft forever
2: eth0: mtu 1500 qdisc pfifo fast state UP group default qle1000
link/ether 0c:da:41:1d:b3:f0 brd ff:ff:ff:ff:ff:ff 10
inet 101.11.12.174/23 brd 10.14.15.255 scope global eth0
valid lft forever preferred lft forever
inet 101.11.12.233/23 brd 10.14.15.255 scope global secondary eth0:1
valid lft forever preferred lft forever
#获取子网卡101.11.12.233 (eth0:1) 对应的物理网卡
[ rootelocalhost ~]# ip addr | grep -w 101.11.12.233 | awk '{print $NF}' | head -n 1 | cut -d ":" -f 1 #去掉冒号取第一列
eth0
页面更新:2024-04-16
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号