在Cloud Foundry v2版本号中,该平台使用warden技术来实现用户应用实例执行的资源控制与隔离。

简要的介绍下warden,就是dea_ng假设须要执行用户应用实例(本文暂不考虑warden container提供staging打包环境),则发送对应请求给warden server,由warden server来创建warden container,并在warden container内部执行应用实例,而warden container的详细实现中使用cgroups等内核虚拟化技术。保证了container内进程组的资源控制与隔离。warden的架构与实现能够參考我的博文:Cloud
Foundry中warden的架构与实现

warden网络架构图


warden container的功能能够觉得与传统的虚拟机类似,不过传统的虚拟机通过Hypervisor等技术来实现资源的控制与隔离,而warden container通过虚拟化内核来达到该目的。而在网络方面,warden container技术创建出一块虚拟网卡。专门供warden container内部使用,另外为warden container内部的虚拟网卡在warden server所在的宿主机上也配对了一块虚拟网卡,充当container的外部网关。只创建出两块虚拟网卡。原则上能够保证物理上的“连通”,可是却非常难做到网络间通信的“联通”,故在物理资源以及虚拟物理资源完备的情况。warden
server在宿主机上通过iptables设计并加入了多条规则,保证整个网络的通信能够满足warden container的要求,同一时候又不影响宿主机的通信。

下面是warden server所在宿主机的物理环境、iptables所在的网络层、操作系统、用户应用层之间的关系图:

warden container网络通信方式


        在Cloud Foundry中,因为warden container用来执行用户应用实例,而应用用户实例与外界的通信在Cloud Foundry中眼下无外乎两种:
  1. 用户应用实例作为一个web server,提供HTTP訪问服务;
  2. 用户应用实例使用service服务时,建立与service instance的连接。

        当然有些Cloud Foundry平台开发人员肯定会觉得用户应用实例,能够作为一个client端,通过url訪问其它应用实例或者訪问云外的资源。在这里须要申明的是,首先Cloud Foundry集群默认相应用实例不暴露ip;其次,如果Cloud Foundry内部不存在或者不能连接一个强大的DNS server,用来解析外部资源的url。

        本文即将以上两点作为主要研究的内容。进行warden所在宿主机的网络分析。集中于iptables一块。



warden iptables配置之net.sh文件

       
        在warden的实现过程中。关于iptables的配置主要包含两个部分:
  1. 启动warden server时,调用文件warden/warden/root/linux/net.sh,制定warden server所在宿主机的部分iptables规则。
  2. 在创建warden container的时候,调用文件warden/warden/root/linux/skeleton/net.sh,制定因为warden container创建后须要加入的iptables规则(包含只创建一个warden
    container的iptables设置。以及为一个warden container做port映射时的iptables设置)。

warden server之net.sh

       

setup_filter

       

        关于warden/warden/root/linux/net.sh,能够看该shell脚本中最为关键的两个方法setup_filter以及setup_nat。

下面是setup_filter的源代码实现:

  1. function setup_filter() {
  2. teardown_filter
  3.  
  4. # Create or flush forward chain
  5. iptables -N ${filter_forward_chain} 2> /dev/null || iptables -F ${filter_forward_chain}
  6. iptables -A ${filter_forward_chain} -j DROP
  7.  
  8. # Create or flush default chain
  9. iptables -N ${filter_default_chain} 2> /dev/null || iptables -F ${filter_default_chain}
  10.  
  11. # Always allow established connections to warden containers
  12. iptables -A ${filter_default_chain} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  13.  
  14. for n in ${ALLOW_NETWORKS}; do
  15. if [ "$n" == "" ]
  16. then
  17. break
  18. fi
  19.  
  20. iptables -A ${filter_default_chain} --destination "$n" --jump RETURN
  21. done
  22.  
  23. for n in ${DENY_NETWORKS}; do
  24. if [ "$n" == "" ]
  25. then
  26. break
  27. fi
  28.  
  29. iptables -A ${filter_default_chain} --destination "$n" --jump DROP
  30. done
  31.  
  32. iptables -A ${filter_default_chain} --jump REJECT
  33.  
  34. # Accept packets related to previously established connections
  35. iptables -I INPUT -m state --state ESTABLISHED,RELATED --jump ACCEPT -m comment --comment 'related-traffic'
  36.  
  37. # Reject traffic from containers to host
  38. if [ "$ALLOW_HOST_ACCESS" != "true" ]; then
  39. iptables -A INPUT -s ${POOL_NETWORK} --jump REJECT -m comment --comment 'block-traffic-to-host'
  40. fi
  41.  
  42. # Forward outbound traffic via ${filter_forward_chain}
  43. iptables -A FORWARD -i w-+ --jump ${filter_forward_chain}
  44.  
  45. # Forward inbound traffic immediately
  46. default_interface=$(ip route show | grep default | cut -d' ' -f5 | head -1)
  47. iptables -I ${filter_forward_chain} -i $default_interface --jump ACCEPT
  48. }

下面首先逐步分析每一个部分iptables的制定的意义。随后将各iptables个则串联起来分析其功能。

关于iptables在内核中的简要流程图例如以下图:



下面逐步分析filter_setup方法:

       1. 在该net.sh文件里,teardown_filter方法所做的工作是:清除某些warden相关的iptable链以及规则。

随后的即创建两条链:filter_forward_chain以及filter_forward_chain。增加这两条链先前存在的话,清楚该两条链之后再创建。


       2. 对于已经和warden container建立完成的连接,iptables都运行ACCEPT操作。代码即:
  1. # Always allow established connections to warden containers
  2. iptables -A ${filter_default_chain} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

由凝视能够发现,该规则加入在filter_default_chain链中,当匹配条件为:该数据包表示为是在已建立的连接上传输时。对该数据包採取ACCEPT操作。

该规则从功能的角度非常好理解,也就是:假如warden container内部发起一个请求,向外建立一个连接,则在该连接上返回数据包时,始终接受这种数据包。

然而。我始终对该规则的底层实现,抱有非常大的疑惑。

待下文分析了很多其它的warden 网络背景知识之后,再进行进一步的阐述。


       3.在filter_default_chain中。对于ALLOW_NETWORKS中的网络主机地址。始终採取ACCEPT操作;而对于DENY_NETWORKS中的网络主机地址。使用採取DROP操作。

在此。能够简要说明一下在iptables中DROP与REJECT的差别。DROP:直接採取丢弃数据包的操作;REJECT:对于原来的数据包採取丢弃措施。随后向数据包的发送方,返回一个类似于ICMP错误的信息包。


        4.之后的shell代码为:iptables -A ${filter_default_chain} --jump REJECT,因为iptables中一个数<br

据包在同一个链中的规则匹配将从第一条開始匹配,遇到匹配成功则运行对应操作,否则继续向下运行,因此该规则表明这条脸中之前都匹配不成的数据包。内核会採取REJECT操作,将数据包丢弃。并返回一个错误数据包。到此,filter_default_chain中的规则设置基本完成。

        5.在INPUT链中加入规则,所谓INPUT链,即当网卡发现接收到的网络数据包的目的IP。与网卡的IP一致时,将该数据包放入INPUT链运行规则处理,此处的代码例如以下:
  1. # Accept packets related to previously established connections
  2. iptables -I INPUT -m state --state ESTABLISHED,RELATED --jump ACCEPT -m comment --comment 'related-traffic'
  3.  
  4. # Reject traffic from containers to host
  5. if [ "$ALLOW_HOST_ACCESS" != "true" ]; then
  6. iptables -A INPUT -s ${POOL_NETWORK} --jump REJECT -m comment --comment 'block-traffic-to-host'
  7. fi
        在INPUT链中设定规则。保证在warden宿主机上原先与外部建立的连接上。发送来的数据包。都将採取ACCEPT操作。其次通过ALLOW_HOST_ACCESS变量来确定是否同意warden container与warden server所在宿主机之间的通信,若该变量为假。则对于从POOL_NETWORKS中发送来的数据包,都採取REJECT操作。保证warden container内部不能訪问warden server所在的宿主机。

到此。对于INPUT链的规则制定已经完毕。


        6.制定iptables中的FORWARD链,所谓FOWARD

创建warden container之net.sh链。即当网络发现接收的网络数据包的目的IP,与该网卡的IP不一致时,则觉得须要为该数据包运行转发(FORWARD)操作。将该数据包放入FORWARD链运行规则处理。此处的代码例如以下:
  1. # Forward outbound traffic via ${filter_forward_chain}
  2. iptables -A FORWARD -i w-+ --jump ${filter_forward_chain}
  3.  
  4. # Forward inbound traffic immediately
  5. default_interface=$(ip route show | grep default | cut -d' ' -f5 | head -1)
  6. iptables -I ${filter_forward_chain} -i $default_interface --jump ACCEPT

当中第一条规则表示:对于从网络设备接口名字为‘w-+’(正則表達式。也就是为warden container而虚拟出的虚拟网卡的设备名字)发来。同一时候又须要运行转发工作的数据包。将该数据包跳转至filter_forward_chain链。这样保证了,全部从warden container发出,又不是发往宿主机的网卡的数据包,进入FORWARD链后直接进入filter_forward_chain链。

 
        而后的规则表明,在filter_forward_chain中的数据包,仅仅要是来自于default_interface。都将採取ACCEPT操作。也就是说。当发现filter_forward_chain中的数据包的来源于warden server所在宿主机的物理网卡时,马上对该数据包採取ACCEPT操作。

        到眼下为止。这个net.sh文件里的filter_setup方法已经分步骤分析完成,然后关于整个运行流,读者可能仍然会有不小的疑惑,比方什么时候。绑定filter_default_chain链,使得数据包进入该链,等等。

稍后分析完还有一个net.sh文件之后。再统一阐述。


setup_nat

下面简单分析setup_nat方法:

  1. function setup_nat() {
  2.      teardown_nat
  3.  
  4.       # Create prerouting chain
  5.      iptables -t nat -N ${nat_prerouting_chain} 2> /dev/null || true
  6.  
  7.       # Bind chain to PREROUTING
  8.      (iptables -t nat -S PREROUTING | grep -q "\-j ${nat_prerouting_chain}\b") ||
  9.             iptables -t nat -A PREROUTING \
  10.             --jump ${nat_prerouting_chain}
  11.  
  12.       # Bind chain to OUTPUT (for traffic originating from same host)
  13.      (iptables -t nat -S OUTPUT | grep -q "\-j ${nat_prerouting_chain}\b") ||
  14.             iptables -t nat -A OUTPUT \
  15.             --out-interface "lo" \
  16.             --jump ${nat_prerouting_chain}
  17.  
  18.       # Create postrouting chain
  19.       iptables -t nat -N ${nat_postrouting_chain} 2> /dev/null || true
  20.       # Bind chain to POSTROUTING
  21.       (iptables -t nat -S POSTROUTING | grep -q "\-j ${nat_postrouting_chain}\b") ||
  22.             iptables -t nat -A POSTROUTING \
  23.             --jump ${nat_postrouting_chain}
  24.  
  25.       # Enable NAT for traffic coming from containers
  26.       (iptables -t nat -S ${nat_postrouting_chain} | grep -q "\-j SNAT\b") ||
  27.             iptables -t nat -A ${nat_postrouting_chain} \
  28.             --source ${POOL_NETWORK} \
  29.             --jump SNAT \
  30.             --to $(external_ip)
  31. }

该部分的内容比較easy理解:

1.首先创建nat_prerouting_chain 链,随后将全部的PREROUTING链中的数据包都跳转至nat_prerouting_chain;

2.随后将链绑定在nat_prerouting_chain上,保证通过lo网络设备的数据包,都跳转到该链;

3.创建nat_postrouting_chain链,保证将默认的POSTROUTING链中的全部数据包都跳转至创建的该链。

4.为从warden container中发出的数据包都採取SNAT处理。使得数据包的源IP都替换为warden server宿主机的IP。

事实上在完毕以上这两步之后,还运行了下面代码:

  1. # Enable forwarding
  2. echo 1 > /proc/sys/net/ipv4/ip_forward

加以保证转发工作能够有效,详细内容能够查看:/proc/sys/net/ipv4/*的各部分作用

创建warden container之net.sh

前篇分析的是。warden server启动的时候,对warden server所在的宿主机进行的iptbales设置。在整个过程中,不涉及不论什么的container。而这一章节,将介绍分析warden server在启动某个详细warden container的时候,再对warden server所在的宿主机设置iptables规则。

该文件地址例如以下:warden/warden/root/linux/skeleton/net.sh

setup_filter

首先分析setup_filter方法,源代码例如以下:

  1. function setup_filter() {
  2.        teardown_filter
  3.  
  4.        # Create instance chain
  5.        iptables -N ${filter_instance_chain}
  6.        iptables -A ${filter_instance_chain} \
  7.            --goto ${filter_default_chain}
  8.  
  9.        # Bind instance chain to forward chain
  10.        iptables -I ${filter_forward_chain} 2 \
  11.            --in-interface ${network_host_iface} \
  12.            --goto ${filter_instance_chain}
  13.  
  14.        # Create instance log chain
  15.        iptables -N ${filter_instance_log_chain}
  16.        iptables -A ${filter_instance_log_chain} \
  17.            -p tcp -m conntrack --ctstate NEW,UNTRACKED,INVALID -j LOG --log-prefix "${filter_instance_chain} "
  18.  
  19.        iptables -A ${filter_instance_log_chain} \
  20.            --jump RETURN
  21. }

1. 该方法创建了关于instance的链。随后,将该warden container instance链内的全部数据包都跳至filter_default_chain,也就是在前一章节中提到的filter_default_chain;

2.绑定该warden container instance的FORWARD链至filter_foward链,也就是说,全部进入filter_foward_chain的数据包,依据数据包从哪个网络接口设备来,进入对应的filter_instance_chain链。也就是说,从network_host_iface网络设备“接收”到的数据包(network_host_iface即为network_container_iface="w-${id}-1"),都转至filter_instance_chain。

3.创建log chain。

setup_nat

在创建warden container的时候,也会设置nat,源代码例如以下:

  1. function setup_nat() {
  2.       teardown_nat
  3.       # Create instance chain
  4.       iptables -t nat -N ${nat_instance_chain}
  5.       # Bind instance chain to prerouting chain
  6.       iptables -t nat -A ${nat_prerouting_chain} \
  7.              --jump ${nat_instance_chain}
  8. }

简要分析即为:创建对应的nat_instance_chain,随后将nat_prerouting_chain中的数据包都跳转至该nat_instance_chain。

net_in之port映射实现

使得Cloud Foundry内warden container的用户应用实例能够为外部提供web服务,那么warden container和warden server所在宿主机进行一个port映射操作,也就是warden server提供的net_in接口,真正的运行部分。即为创建容器的该net.sh文件里的in參数运行。

下面是net_in详细操作的源代码实现:

  1. "in")
  2.        if [ -z "${HOST_PORT:-}" ]; then
  3.            echo "Please specify HOST_PORT..." 1>&2
  4.            exit 1
  5.        fi
  6.        if [ -z "${CONTAINER_PORT:-}" ]; then
  7.            echo "Please specify CONTAINER_PORT..." 1>&2
  8.            exit 1
  9.        fi
  10.        iptables -t nat -A ${nat_instance_chain} \
  11.            --protocol tcp \
  12.            --destination "${external_ip}" \
  13.            --destination-port "${HOST_PORT}" \
  14.            --jump DNAT \
  15.            --to-destination "${network_container_ip}:${CONTAINER_PORT}"
  16.         ;;

可见该代码块中最为重要的部分为。创建DNAT规则转换的部分。也就是,在对应的instance规则链中,对于TCP数据包,假设该数据包的目的IP和目的PORT为warden server所在宿主机的IP和映射的PORT。则运行DNAT转换,转换为warden container IP和warden container的port。

总结

以上便是对Cloud Foundry v2中warden的网络设计之iptables规则制定。做了简要的分析。然而,在这之中,有非常多的设计不过留了接口,并未真正实现。

另,感谢浙江大学VLIS实验室的实习生高相林的共同研究。

关于作者:

孙宏亮。DAOCLOUD软件project师。

两年来在云计算方面主要研究PaaS领域的相关知识与技术。

坚信轻量级虚拟化容器的技术,会给PaaS领域带来深度影响,甚至决定未来PaaS技术的走向。

转载请注明出处。

本文很多其它出于我本人的理解,肯定在一些地方存在不足和错误。

希望本文可以对接触warden网络配置的人有些帮助,假设你对这方面感兴趣。并有更好的想法和建议,也请联系我。

我的邮箱:allen.sun@daocloud.io
新浪微博:@莲子弗如清

Cloud Foundry中warden的网络设计实现——iptable规则配置的更多相关文章

  1. Cloud Foundry中DEA启动应用实例时环境变量的使用

    在Cloud Foundry v2中,当应用用户须要启动应用的实例时.用户通过cf CLI向cloud controller发送请求,而cloud controller通过NATS向DEA转发启动请求 ...

  2. Cloud Foundry中 JasperReports service集成

    Cloud Foundry作为业界第一个开源的PaaS解决方案,正越来越多的被业界接受和认可.随着PaaS的发展,Cloud Foundry顺应潮流,充分发挥开源项目的特点,到目前为止,已经支持了大批 ...

  3. Cloud Foundry中通用service的集成

    目前,CloudFoundry已经集成了很多第三方的中间件服务,并且提供了用户添加自定义服务的接口.随着Cloud Foundry的发展,开发者势必会将更多的服务集成进Cloud Foundry,以供 ...

  4. Cloud Foundry中vmc tunnel与caldecott原理

    在Cloud Foundry中,用户可以vmc create-service创建一个service instance,但是常规情况下,用户不能手动地进一步对service instance进行设计.以 ...

  5. Cloud Foundry中gorouter对StickySession的支持

    Cloud Foundry作为业界出众的PaaS平台,在应用的可扩展性方面做得很优秀. 详细来讲,在一个应用须要横向伸展的时候,Cloud Foundry能够轻松地帮助用户做好伸展工作,也就是创建出一 ...

  6. Cloud Foundry中DEA与warden通信完毕应用port监听

    在Cloud Foundry v2版本号中,DEA为一个用户应用执行的控制模块,而应用的真正执行都是依附于warden. 更详细的来说,是DEA接收到Cloud Controller的请求:DEA发送 ...

  7. Cloud Foundry warden container 安全性探讨

    本文将从Cloud Foundry中warden container的几个方面探讨warden container的安全性. 1. warden container互訪 1.1.  互訪原理· 在Cl ...

  8. Cloud Foundry技术全貌及核心组件分析

    原文链接:http://www.programmer.com.cn/14472/ 历经一年多的发展,Cloud Foundry的架构设计和实现有了众多改进和优化.为了便于大家了解和深入研究首个开源Pa ...

  9. Cloud Foundry技术资料汇总

    来自:http://cnblog.cloudfoundry.com/2012/05/ 本文是Cloud Foundry的一个简单上手指南和资料汇总,内容将根据产品的发布定期更新. Cloud Foun ...

随机推荐

  1. Node.js初学

    Node.js 初学~ 其技术上最大的卖点是非阻塞的I/O和基于事件的异步处理机制. 后端没有什么深入研究,一直对其不是很了解. 透过一个例子看 非阻塞 与 通常的 阻塞 var text = rea ...

  2. zoj 1184

    硬币称重,经典,1.若被判平,左右所有硬币必正常:2.若判轻或判重,对应硬币被判轻-1.重记数+1:3.只有球只被判轻或判重,且次数跟天平不平衡次数相等,该球才能是坏的,否则必然是好的.且>0的 ...

  3. 判断联网wifi

    UIApplication *app = [UIApplication sharedApplication]; NSArray *children = [[[app valueForKeyPath:@ ...

  4. linux cmd: ps

    每天一个linux命令(41):ps命令 http://www.cnblogs.com/peida/archive/2012/12/19/2824418.html Linux中的ps命令是Proces ...

  5. 在raw_input()中使用中文提示,在CMD下中文乱码问题解决。。。

    错误的程序及结果: 解决1: guess = int(raw_input('请输入一个整数:'.decode('utf-8').encode('gbk'))) 解决2: guess = int(raw ...

  6. [LeetCode]题解(python):127-Word Ladder

    题目来源: https://leetcode.com/problems/word-ladder/ 题意分析: 和上一题目类似,给定一个beginWord和一个endWord,以及一个字典list.这题 ...

  7. ASP.NET MVC5 学习笔记-4 OWIN和Katana

    1. Owin OWIN全名:Open Web Interface for .NET. 它是一个说明,而非一个框架,该声明用来实现Web服务器和框架的松耦合.它提供了模块化.轻量级和便携的设计.类似N ...

  8. selenium 学习笔记 ---新手学习记录(6) 问题总结(java)

    1.查看网页的cookie信息 //查看cookie 登录后的cookie Set<Cookie> setcoke= driver.manage().getCookies(); for(C ...

  9. FPGA工程中用C语言对文件进行处理_生成mif文件

    本博客中有用verilog处理文件数据的代码,本博文采用C 处理文件中的数据. 有时候要生成一个mif文件—— altera memory  initial file.本次工程中我得到的是一个大型的数 ...

  10. DataList嵌套绑定例子

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DataList控件.asp ...