技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 网络系统 --> 在LVS上实现SNAT网关

在LVS上实现SNAT网关

浏览:1301次  出处信息

   最近研究LVS,给其增加了SNAT网关的功能,见https://github.com/jlijian3/lvs-snat,下面跟大家分享一下学习心得。


LVS简介:

   LVS是Linux Virtual Server的简写,即Linux虚拟服务器,功能是4层反向代理负载均衡。 1998年5月由章文嵩博士开源。 2004年12月25日做为netfilter模块加入官方内核2.6.10。 站点:http://www.linuxvirtualserver.org/ http://zh.linuxvirtualserver.org/


研究目的:

   使用LVS做4层反向代理负载均衡 在网关做SNAT,为内网机器提供访问外网的功能

   假设大家已经了解LVS的转发方式,这里仅叙述分析和解决问题的过程。


使用场景:

  •    反向代理使用LVS的NAT转发模式

       LVS机器有两张网卡,一张绑定外网IP,另一张绑定内网IP; 后端机器跟LVS内网IP处于同一个内网网段,每台后端机器都只有一个内网地址,他们的网关都指向LVS机器内网IP。

  •    在LVS机器上做SNAT网关

       内网机器访问外网时(比如访问www.baidu.com),数据包会经过LVS机器转发出去,如果想正常访问要做以下事情,即SNAT: 1)把数据包的源ip由内网地址改为LVS机器的外网地址,再转发出去; 2)收到外网服务器的应答时,需要把目的地址由LVS机器的外网地址改为内网机器地址,再转发到内网机器,如下图:

       lvs_snat


  • 问题:

       LVS不会帮我们做SNAT,它只做反向代理,只处理客户端请求和来自内网机器的应答数据。 一个解决方法是在LVS机器上启动iptables做SNAT,如:

    iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j SNAT --to-source 121.14.161.100

       但是如果启用iptables,即使内网机器不访问外网,也会严重影响到LVS反向代理的性能,因为每个应答数据包都有经过iptables(后来把单队列网卡升级为多队列网卡,发现iptables对LVS的性能影响很小,这里不展开分析)。

       另一个解决方法是修改LVS源代码实现SNAT网关。


    以学习研究LVS为目的,为LVS增加SNAT功能:

       幸运的是小米的同学做了这件事情,https://github.com/xiaomi-sa/dsnat。 他在LVS的FULLNAT基础上,增加了SNAT网关功能,使内网机器可以访问外网。 可惜他没有考虑跟反向代理的兼容性,NAT/FULLNAT转发方式无法正常使用,FULLNAT的配置项被修改用于SNAT的配置。

       接下来要做两件事情: 1)修复小米dsnat问题,使反向代理和SNAT可以同时使用;

       2)直接在官方内核版本NAT转发模式上添加SNAT网功能,因为小米dsnat依赖于淘宝的FULLNAT补丁,我们并不需要FULLNAT。

       1. 下载redhat 6.3内核

    wget ftp://ftp.redhat.com/pub/redhat/linux/enterprise/6Server/en/os/SRPMS/kernel-2.6.32-279.el6.src.rpm

       2. 准备代码

    rpm -ivh kernel-2.6.32-279.23.1.el6.src.rpm
    cd rpmbuild/SPECS
    rpmbuild -bp kernel.spec

       3. 获取dsnat内核补丁和lvs tools代码

    git clone git@github.com:xiaomi-sa/dsnat.git

       4. 打补丁

    cd ~/rpmbuild/BUILD/kernal-2.6.32-279.23.1.el6/linux-2.6.32-279.23.1.el6.x86_64
    #把dsnat内核补丁拷贝到当前目录
    cp ~/dsnat/dsnat-kernel-2.6.32-279.el6/dsnat-2.6.32-279.el6.xiaomi.noconfig.patch ./
    patch -p1 < dsnat-2.6.32-279.el6.xiaomi.noconfig.patch

       5. 编译安装

    make -j16
    make modules_install
    make install
    #重启
    init 6
    #grub选择新内核

       6. LVS工具安装

    #进入刚才clone的dsnat代码目录下
    cd dsnat/dsnat-kernel-2.6.32-279.el6/dsnat_tools/keepalived
    make && make install
    cd ../ipvsadm/
    make && make install

       7. 打开ipvs模块调试开关

    cd ~/rpmbuild/BUILD/kernal-2.6.32-279.23.1.el6/linux-2.6.32-279.23.1.el6.x86_64
    make menuconfig
    进入Networking support->Networking options->Netfilter->IP Virtual server support,勾选IP Virtual server debugging

       8. 打开pr_debug开关

    #LVS很多地方使用pr_debug打日志,需要编译选项加上-DDEBUG
    #修改net/netfilter/ipvs/Makefile,增加
    ifeq ($(CONFIG_IP_VS_DEBUG),y)
        EXTRA_CFLAGS += -DDEBUG
    endif

       9. 重新编译安装ipvs模块

    #进入内核代码目录,编译模块
    make M=`pwd`/net/netfilter/ipvs modules
    #卸载模块
    ipvsadm -C
    lsmod|grep ip_vs
    rmmod ip_vs_rr
    rmmod ip_vs
    #更新ko文件
    cp net/netfilter/ipvs/*.ko /lib/modules/`uname -r`/kernel/net/netfilter/ipvs
    #重启lvs

       10. 查看ipvs模块调试日志

    #修改ipvs调试日志级别,默认为0
    echo 12 > /proc/sys/net/ipv4/vs/debulg_level
    #查看日志
    dmesg|grep IPVS|less
    #如果想直接在屏幕输出
    echo 8 > /proc/sys/kernel/printk

       11. 使用tcpdump分析问题

    #查看各个网卡的数据
    tcpdump -X -n -i eth0

       12. 修复dsnat跟NAT的兼容性bug

       ipvs代码路径:net/netfilter/ipvs 在ip_vs_core.c中找到forward钩子函数ip_vs_out,内网机器访问外网的请求数据、NAT应答数据都经过此钩子函数。 dsnat的作者没有区分这两种数据包,错误的修改了NAT的应答数据包的目的地址。 解决方法:因为dsnat是通过添加一个0.0.0.0:0的service来做SNAT的,在做dsnat之前,判断svc->addr.ip和svc->port是否为0,否则走NAT应答数据处理流程。 详情见https://github.com/jlijian3/lvs-snat

       13. 修复dsnat跟FULLNAT的兼容性bug

       dsnat作者没有考虑跟FULLNAT兼容,直接修改了FULLNAT的local address配置参数,用来添加SNAT的映射地址。 而我们希望两者同时使用。接下来要做的就是恢复FULLNAT的local address的添加和使用方式。 不仅要修改ipvs代码,还有修改ipvsadm和keepalived,开发和调试比想象中的麻烦。 详情见https://github.com/jlijian3/lvs-snat

       14. 不使用FULLNAT补丁,在官方内核上实现SNAT

       小米的dsnat基于淘宝开源的FULLNAT,但是我们不需要FULLNAT转发功能,接下来从头开始,不打dsnat补丁,直接在NAT转发基础上修改,改动量很少,ipvsadm和keepalived不需要修改,但是不支持源地址白名单过滤。 详情见https://github.com/jlijian3/lvs-snat

       15. 其他问题

       SNAT网关目前只支持tcp和udp,icmp的转发还不支持,在内网ping 外网ip是ping不同的,今后有时间再增加对icmp的支持。

       16. 生成补丁

       调试测试ok,准备两份代码,修改前和修改后的

    diff -rupN linux-2.6.32-279.el6 linux-2.6.32-279.el6.snat > lvs-snat-2.6.32-279.el6.patch

       17. 基于dsnat的SNAT网关ipvsadm配置示例

    #添加一个0/0的virtul service
    ipvsadm -A -t 0.0.0.0:0 -s rr
    
    #添加一个内网源地址网段,做源地址匹配,符合该网段的才做SNAT
    ipvsadm -K  --zone 192.168.0.0/16
    
    #为192.168.0.0/24添加一个local address,即映射后的外网地址,可以加多个,轮询使用
    #注意dsnat中使用-P来添加zone的laddr,这里改为-U
    ipvsadm -U --zone 192.168.0.0/24 -z 121.14.161.100
    ipvsadm -U --zone 192.168.0.0/24 -z 121.14.161.101
    
    #删除zone的laddr由-Q改为-W
    ipvsadm -W --zone 192.168.0.0/24 -z 121.14.161.100
    
    #-P/-Q恢复为原来的功能,即为FULLNAT的service添加删除laddr

       18. 基于NAT的SNAT网关的ipvsadm配置示例

    #直接用官方的ipvsadm即可,功能简单,没有源地址网段匹配,只要不是反向代理转发的数据,就做SNAT
    
    #添加0.0.0.0:0的虚拟服务,加上-p参数
    #因为只有persistent service才能添加端口为0的服务,而我懒得修改ipvsadm代码了
    ipvsadm -A -t 0.0.0.0:0 -s rr -p 10
    
    #添加转换后的源地址,这里直接使用添加real server参数,端口为0,如下
    ipvsadm -a -t 0.0.0.0:0 -r 121.14.161.100:0 -m
    
    #内网访问外网时,源地址就会被改为121.14.161.100

    小结:

       linux内核模块开发调试跟应用程序的开发还是很不一样的,调试起来要麻烦一些,不过只要有耐心,多查点资料,还是不难搞定的。 在学习研究开源软件时,如果能为其修复一些bug,增加一些功能,对其理解会更加透彻,对今后分析解决相关问题会很有帮助。

建议继续学习:

  1. LVS hash size解决4096个并发的问题    (阅读:5430)
  2. LVS & MySQL NDB Cluster    (阅读:4053)
  3. 记一次LVS/Nginx环境下的访问控制    (阅读:3836)
  4. LVS & MySQL NDB Cluster    (阅读:3719)
  5. 网关协议学习:CGI、FastCGI、WSGI    (阅读:3657)
  6. 利用MySQL Cluster 7.0 + LVS 搭建高可用环境    (阅读:3381)
  7. linux双网卡双网关,不同IP段的设置    (阅读:3231)
  8. 怎么样让 LVS 和 realserver 工作在同一台机器上    (阅读:3153)
  9. Linux 上双网卡单网关设置方法    (阅读:2095)
  10. NAT网关安装笔记    (阅读:1893)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1