一、故障现象

KVM部署LVS(Linux Virtual Server)集群后,能够单独以HTTP方式访问RS(Real Server)的实际IP,但无法通过VIP(Virtual IP)访问。

二、故障分析过程

 

1.简化架构

 

在原部署环境中,采用的架构是LVS的DR(Direct Return)模式,如下图所示:

为了便于故障排查,我们简化为

也就是在2台宿主机上,各保留一个虚拟机,角色分别是LVS的Director(调度器)和RS。

该架构中的服务器(及虚拟机)的IP和MAC地址如下:

角色

IP

MAC

网络结构

宿主机1

x.y.z.70

a0:d3:c1:f4:66:ac

宿主机1的eth0和Director1的eth0(在宿主机1中对应为vnet0)桥接到br0

Director1

x.y.z.200

02:00:73:b6:53:c8

宿主机2

x.y.z.73

a0:d3:c1:f9:f3:fc

宿主机2的eth0和RS2的eth0(在宿主机2中对应为vnet0)桥接到br0

RS2

x.y.z.226

02:00:73:b6:53:e2

VIP

x.y.z.208

02:00:73:b6:53:c8

 

Client IP

192.243.119.145

   

2.确认Director1是否能够正确识别到RS2提供的服务

在Director1上,使用如下的命令检查

[root@Director1 ~]# ipvsadm -ln --sort

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

-> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  x.y.z.208:80 rr

❶-> x.y.z.226:80           Route   2      0         0

由以上的输出❶可以看出,Director1能够正确识别到RS2提供的服务。

3.确认Director1是否能够正确重写MAC地址

在Director1上执行以下的命令:

[root@Director1 ~]# tcpdump -vvv -nnn -e -i eth0 host 192.243.119.145

❶11:39:19.372804 84:78:ac:27:6c:41 > 02:00:73:b6:53:c8,ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 48, id 47264, offset 0, flags[DF], proto TCP (6), length 60)

192.243.119.145.51643 > x.y.z.208.80:Flags [S], cksum 0x000e (correct), seq 3639534333,win 14600, options [mss 1460,sackOK,TS val 780753501ecr 0,nop,wscale 7], length 0

❷11:39:19.372815 02:00:73:b6:53:c8 > 02:00:73:b6:53:e2,ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 48, id 47264, offset 0, flags[DF], proto TCP (6), length 60)

192.243.119.145.51643 > x.y.z.208.80:Flags [S], cksum 0x000e (correct), seq 3639534333,win 14600, options [mss 1460,sackOK,TS val 780753501ecr 0,nop,wscale 7], length 0

❸11:39:20.372079 84:78:ac:27:6c:41 > 02:00:73:b6:53:c8,ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 48, id 47265, offset 0, flags[DF], proto TCP (6), length 60)

192.243.119.145.51643 > x.y.z.208.80:Flags [S], cksum 0xfc25 (correct), seq 3639534333,win 14600, options [mss 1460,sackOK,TS val 780754501ecr 0,nop,wscale 7], length 0

❹11:39:20.372091 02:00:73:b6:53:c8> 02:00:73:b6:53:e2, ethertype IPv4 (0x0800), length 74: (tos 0x0,ttl 48, id 47265, offset 0, flags [DF], proto TCP (6), length 60)

192.243.119.145.51643 > x.y.z.208.80:Flags [S], cksum 0xfc25 (correct), seq 3639534333,win 14600, options [mss 1460,sackOK,TS val 780754501ecr 0,nop,wscale 7], length 0

---以下略去客户端第3、4、5次重传数据

从❷所示的以太网帧中,我们能够看到❶所示的以太网帧目的MAC地址被Director1重写成了RS2的MAC地址,同时源MAC地址被Director1重写成了Director1本身的MAC地址。

从❸和❹所示的以太网帧中,我们能够看到Client(192.243.119.145)在1s后(❸中的TSval 780754501比❶中的TSval 780753501大1000ms,TCPSequence相同)(注:TS val表示发送方的时间戳,单位是ms)进行了SYN包重传,说明Client和RS2没有正常建立TCP连接。此时,Director1仍然正确重写了MAC地址。

4.确认宿主机1是否能够正确转发虚拟机Director1重写后的帧

在宿主机上执行以下命令:

[root@HOST1 ~]# tcpdump -vvv -nnn -e -i br0 host 192.243.119.145

❶11:39:19.430993 84:78:ac:27:6c:41 > 02:00:73:b6:53:c8,ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 48, id 47264, offset 0, flags[DF], proto TCP (6), length 60)

192.243.119.145.51643 > x.y.z.208.80:Flags [S], cksum 0x000e (correct), seq 3639534333,win 14600, options [mss 1460,sackOK,TS val 780753501ecr 0,nop,wscale 7], length 0

❷11:39:20.430238 84:78:ac:27:6c:41 > 02:00:73:b6:53:c8,ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 48, id 47265, offset 0, flags[DF], proto TCP (6), length 60)

192.243.119.145.51643 > x.y.z.208.80:Flags [S], cksum 0xfc25 (correct), seq 3639534333,win 14600, options [mss 1460,sackOK,TS val 780754501ecr 0,nop,wscale 7], length 0

---以下略去客户端第3、4、5次重传数据

从❶和❷所示的以太网帧中,我们能够看到宿主机1未转发虚拟机Director1重写后的以太网帧(其中❷是❶的Client重传,我们没有观察到❶和❷的MAC地址被重写的情况)。

很明显,问题出在宿主机1上,它没有转发Director1重写后的以太网帧。

我们来看看为什么会发生这个问题。

5.检查宿主机1上虚拟机Director1的网络配置

在宿主机1上执行以下命令:

[root@HOST1 ~]# virsh dumpxml r2-10105

<interfacetype='bridge'>

<mac address='02:00:73:b6:53:c8'/>

<source bridge='br0'/>

<target dev='vnet0'/>

<modeltype='virtio'/>

❶<filterref filter='clean-traffic'>

❷<parameter name='IP' value='x.y.z.200'/>

</filterref>

<aliasname='net0'/>

<address type='pci'domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>

</interface>

从❶和❷中,我们看到Director1被引用了一个名为'clean-traffic'的过滤策略,同时给变量IP赋值为Director1的IP地址x.y.z.200。

在宿主机1上执行以下命令:

[root@HOST1 ~]# virsh nwfilter-dumpxml clean-traffic

<filter name='clean-traffic' chain='root'>

<uuid>8c2059f9-d00f-4d1d-b96e-69e7d2b41c0f</uuid>

<filterreffilter='no-mac-spoofing'/>

❸<filterreffilter='no-ip-spoofing'/>

<rule action='accept'direction='out' priority='-650'>

<macprotocolid='ipv4'/>

</rule>

<filterreffilter='allow-incoming-ipv4'/>

<filterreffilter='no-arp-spoofing'/>

<rule action='accept'direction='inout' priority='-500'>

<macprotocolid='arp'/>

</rule>

<filterreffilter='no-other-l2-traffic'/>

<filterreffilter='qemu-announce-self'/>

</filter>

[root@HOST1 ~]# virsh nwfilter-dumpxml no-ip-spoofing

<filter name='no-ip-spoofing' chain='ipv4-ip' priority='-710'>

<uuid>bf7be725-1486-410f-8a8b-42c82b952261</uuid>

<rule action='return'direction='out' priority='100'>

<ip srcipaddr='0.0.0.0'protocol='udp'/>

</rule>

<rule action='return'direction='out' priority='500'>

❹<ipsrcipaddr='$IP'/>

</rule>

❺<rule action='drop' direction='out' priority='1000'/>

</filter>

从❸、❹、❺中,我们看到在宿主机1中把Director1的发出的数据包的源地址限定为x.y.z.200,任何从Director1发出的数据包,如果源IP为其他,则被过滤掉(drop)。

注意:

 在LVS的DR模式部署中,Director会重写来自客户端的以太网帧的源MAC地址和目的MAC地址,但会保留源IP地址和目的IP地址,因此Director发出的数据包得源IP地址并不是在这个虚拟机上配置的IP地址,也就是进行了IP的伪装(spoofing)。恰好被宿主机1上对它限制给过滤了。

三、故障解决方法

 

根据以上的分析,我们知道,为了能够在KVM集群中配置DR模式的LVS集群,我们必须禁用’no-ip-spoofing’的过滤策略。

方法是:

1)执行:

virsh edit r2-10105

2)删除以下内容:

<filterref filter='clean-traffic'>

<parameter name='IP'value='x.y.z.200'/>

</filterref>

3)重启虚拟机。

4)我们采用以下的步骤抓包验证。

[root@HOST1 ~]#  tcpdump -i br0 -s 0 host 192.243.119.145 -vvv-nnn -s 0 -e

tcpdump: listening on br0, link-type EN10MB (Ethernet), capture size65535 bytes

❶16:39:37.842828 84:78:ac:27:6c:41 > 02:00:73:b6:53:c8,ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 48, id 59437, offset 0, flags[DF], proto TCP (6), length 60)

192.243.119.145.48377 > x.y.z.208.80:Flags [S], cksum 0x8721 (correct), seq 2886813932, win 14600, options [mss1460,sackOK,TS val 885170369 ecr 0,nop,wscale 7], length 0

❷16:39:37.842990 02:00:73:b6:53:c8 > 02:00:73:b6:53:e2,ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 48, id 59437, offset 0, flags[DF], proto TCP (6), length 60)

192.243.119.145.48377 > x.y.z.208.80:Flags [S], cksum 0x8721 (correct), seq 2886813932, win 14600, options [mss1460,sackOK,TS val 885170369 ecr 0,nop,wscale 7], length 0

---以下略去其他正常数据通信

从❶和❷所示的以太网帧中,我们能够看到宿主机1转发了虚拟机Director1重写后的以太网帧。因此,这个问题得以完美解决。

四、再探原理

 

通过这个故障案例,我们对KVM的网络过滤策略有了更深的理解。那么,这些过滤策略到底是如何在系统里面生效的呢?

通过在宿主机上配置iptables、ebtables,宿主机能够对虚拟机进行网络限制。其中,iptables实现对四层TCP、UDP端口的网络流量过滤;ebtables对二层MAC地址、三层IP地址进行过滤。如下是在宿主机1上对虚拟机进行MAC地址限定、源IP限定的规则:

[root@HOST1 ~]# ebtables -t nat --list

Bridge table: nat

Bridge chain: PREROUTING, entries: 1, policy: ACCEPT

-i vnet0 -j libvirt-I-vnet0 #宿主机vnet0入流量走libvirt-I-vnet0策略

Bridge chain: OUTPUT, entries: 0, policy: ACCEPT

Bridge chain: POSTROUTING, entries: 1, policy: ACCEPT

-o vnet0 -j libvirt-O-vnet0 #宿主机vnet0出流量走libvirt-O-vnet0策略

Bridge chain: libvirt-I-vnet0, entries: 9, policy: ACCEPT

-j I-vnet0-mac

-p IPv4 -j I-vnet0-ipv4-ip

-p IPv4 -j ACCEPT

-p ARP -j I-vnet0-arp-mac

-p ARP -j I-vnet0-arp-ip

-p ARP -j ACCEPT

-p 0x8035 -j I-vnet0-rarp

-p 0x835 -j ACCEPT

-j DROP

Bridge chain: libvirt-O-vnet0, entries: 4, policy: ACCEPT

-p IPv4 -j O-vnet0-ipv4

-p ARP -j ACCEPT

-p 0x8035 -j O-vnet0-rarp

-j DROP

Bridge chain: I-vnet0-mac, entries: 1, policy: ACCEPT

-s 2:0:73:b6:53:c8 -j RETURN #限定源MAC地址

-j DROP

Bridge chain: I-vnet0-ipv4-ip, entries: 3, policy: ACCEPT

-p IPv4 --ip-src 0.0.0.0 --ip-proto udp -j RETURN

-p IPv4 --ip-src x.y.z.200 -j RETURN #限定源IP地址

-j DROP

Bridge chain: O-vnet0-ipv4, entries: 1, policy: ACCEPT

-j ACCEPT

五、总结

 

在KVM环境中部署LVS集群时,要特别注意宿主机上iptables、ebtables对虚拟机的影响。因为此时,虚拟机并不是使用用户态的的应用程序进行代理,而是使用了网络地址转换(NAT模式)、MAC地址重写(DR模式)等“非常规”方法。

通过这个案例,我们同时可以知道,在遇到未知可能涉及到网络方便的问题时,使用网络分析技术可以提供有效的信息来帮助我们定位和排除问题。

阅读原文

KVM部署LVS集群故障案例一则的更多相关文章

  1. 基于Ambari Server部署HDP集群实战案例

    基于Ambari Server部署HDP集群实战案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.部署Ambari Server端 博主推荐阅读: https://www.c ...

  2. ElasticSearch集群故障案例分析: 警惕通配符查询

    最近ElasticSearch集群出现了 https://elasticsearch.cn/article/171 文章中描述的情况,现在转载全文警示下自己. 许多有RDBMS/SQL背景的开发者,在 ...

  3. LVS集群简介及使用

    什么是集群 一组通过高速网络互联的计算组,并以单一系统的模式加以管理 将很多服务器集中在一起,提供一种服务,在客户端看来就象是只有一个服务器 可以在付出较低成本的情况下获得在性能,可靠性,灵活性方面的 ...

  4. LVS集群

    集群: 将许多小的,性能较低的服务器做成一个大的性能高的超级服务器 集群分为负载均衡集群,高可用集群,高性能运算集群 LVS体系结构与工作原理描述 LVS集群负载均衡器接受服务的所有入站客户端计算机请 ...

  5. 4 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之Lvs为Mysql-slave做负载均衡

    preface Mysql+drbd+heart能够实现Mysql的高可用了,master出现故障的时候能够快速切换.在现在的业务情况下,读操作多,写操作少的情况下,一台DB server明显扛不住, ...

  6. 部署K8S集群

    1.Kubernetes 1.1.概念 kubernetes(通常称为k8s)用于自动部署.扩展和管理容器化应用程序的开源系统.它旨在提供“跨主机集群的自动部署.扩展以及运行应用程序容器的平台”.支持 ...

  7. LVS集群和Keepalived高可用实战

    第四十章LVS集群和Keepalived高可用实战 一.ARP协议 1.概念 地址解析协议,即ARP(AddressResolutionProtocol),是根据IP地址获取物理MAC地址的一个TCP ...

  8. window下使用Redis Cluster部署Redis集群

    日常的项目很多时候都需要用到缓存.redis算是一个比较好的选择.一般情况下做一个主从就可以满足一些比较小的项目需要.在一些并发量比较大的项目可能就需要用到集群了,redis在Windows下做集群可 ...

  9. Linux系统(四)负载均衡LVS集群之NAT模式

    序言 提到LVS,就从章文嵩博士开始吧,反正也不知道如何下笔来写这一篇.章大博士,读博时候创建这个lvs软件项目,但是他提倡开源精神,在用户的建议和反馈中,这个花了他两周时间开发的开源软件不断得到改建 ...

随机推荐

  1. COGS 08-备用交换机 题解——S.B.S.

    8. 备用交换机 ★★   输入文件:gd.in   输出文件:gd.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] n个城市之间有通讯网络,每个城市都有通讯交换机,直 ...

  2. HBase系统架构及数据结构(转)

    原文链接:Hbase系统架构及数据结构 HBase中的表一般有这样的特点: 1 大:一个表可以有上亿行,上百万列 2 面向列:面向列(族)的存储和权限控制,列(族)独立检索. 3 稀疏:对于为空(nu ...

  3. UTC 转本地时间

    String dateStr = "Wed Dec 10 00:00:00 UTC 0800 2014"; //Wed Dec 10 00:00:00 UTC 0800 2014 ...

  4. HTML-获取/修改html页面标题

    作为一个标准的HTML文档,网页标题(title)是必不可少的属性.随着浏览器的发展,我们又多了一种访问和修改文档的方式:DOM.所以我们获取网页标题的方式大致可分为以下两种: 通过document对 ...

  5. SVG Viewer 3.0安装发现SVG Viewer License.txt无法介入写入,安装失败

    这几天研究SVG,发现"SVG Viewer 3.0安装发现SVG Viewer License.txt无法介入写入,安装失败"这个问题,晚上没找到解答的答案,后来被我们项目经理搞 ...

  6. python中各类时间的计算

    python获取当前系统时间: nowTime=time.localtime() 获取当前系统日期: nowDate=datetime.datetime(nowTime[0],nowTime[1],n ...

  7. 用thinkphp连接mysql数据库

    一.设置mysql数据库的参数 thinkphp\Application\Home\Conf\config.php <?php return array( //'配置项'=>'配置值' ' ...

  8. Java打包生成exe(使用exe4j和inno setup)

    Java打包生成exe 生成jar 先使用eclipse生成可执行的jar[可执行的jar包含内容更全面,包括指定主类的.mf] Exe4j的使用 一定要可执行jar进行打包. Project typ ...

  9. 重置 radio 和 checkbox 的样式

    代码: <!doctype html> <html> <head> <meta charset="utf-8"> <title ...

  10. js slice 参数为负值

    示例代码 <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF- ...