Cloud Foundry中warden的网络设计实现——iptable规则配置
? ? ? ?
??????? 在Cloud Foundry v2版本號(hào)中,該平臺(tái)使用warden技術(shù)來(lái)實(shí)現(xiàn)用戶應(yīng)用實(shí)例執(zhí)行的資源控制與隔離。
? ? ? ? 簡(jiǎn)要的介紹下warden,就是dea_ng假設(shè)須要執(zhí)行用戶應(yīng)用實(shí)例(本文暫不考慮warden container提供staging打包環(huán)境),則發(fā)送對(duì)應(yīng)請(qǐng)求給warden server,由warden server來(lái)創(chuàng)建warden container,并在warden container內(nèi)部執(zhí)行應(yīng)用實(shí)例,而warden container的詳細(xì)實(shí)現(xiàn)中使用cgroups等內(nèi)核虛擬化技術(shù)。保證了container內(nèi)進(jìn)程組的資源控制與隔離。warden的架構(gòu)與實(shí)現(xiàn)能夠參考我的博文:Cloud Foundry中warden的架構(gòu)與實(shí)現(xiàn)。
warden網(wǎng)絡(luò)架構(gòu)圖
? ? ? ? warden container的功能能夠覺(jué)得與傳統(tǒng)的虛擬機(jī)類(lèi)似,不過(guò)傳統(tǒng)的虛擬機(jī)通過(guò)Hypervisor等技術(shù)來(lái)實(shí)現(xiàn)資源的控制與隔離,而warden container通過(guò)虛擬化內(nèi)核來(lái)達(dá)到該目的。而在網(wǎng)絡(luò)方面,warden container技術(shù)創(chuàng)建出一塊虛擬網(wǎng)卡。專(zhuān)門(mén)供warden container內(nèi)部使用,另外為warden container內(nèi)部的虛擬網(wǎng)卡在warden server所在的宿主機(jī)上也配對(duì)了一塊虛擬網(wǎng)卡,充當(dāng)container的外部網(wǎng)關(guān)。只創(chuàng)建出兩塊虛擬網(wǎng)卡。原則上能夠保證物理上的“連通”,可是卻非常難做到網(wǎng)絡(luò)間通信的“聯(lián)通”,故在物理資源以及虛擬物理資源完備的情況。warden server在宿主機(jī)上通過(guò)iptables設(shè)計(jì)并加入了多條規(guī)則,保證整個(gè)網(wǎng)絡(luò)的通信能夠滿足warden container的要求,同一時(shí)候又不影響宿主機(jī)的通信。
? ? ? ? 下面是warden server所在宿主機(jī)的物理環(huán)境、iptables所在的網(wǎng)絡(luò)層、操作系統(tǒng)、用戶應(yīng)用層之間的關(guān)系圖:
warden container網(wǎng)絡(luò)通信方式
在Cloud Foundry中,因?yàn)閣arden container用來(lái)執(zhí)行用戶應(yīng)用實(shí)例,而應(yīng)用用戶實(shí)例與外界的通信在Cloud Foundry中眼下無(wú)外乎兩種:
本文即將以上兩點(diǎn)作為主要研究的內(nèi)容。進(jìn)行warden所在宿主機(jī)的網(wǎng)絡(luò)分析。集中于iptables一塊。
warden iptables配置之net.sh文件
在warden的實(shí)現(xiàn)過(guò)程中。關(guān)于iptables的配置主要包含兩個(gè)部分:warden server之net.sh
setup_filter
??????? 關(guān)于warden/warden/root/linux/net.sh,能夠看該shell腳本中最為關(guān)鍵的兩個(gè)方法setup_filter以及setup_nat。
下面是setup_filter的源代碼實(shí)現(xiàn):
function setup_filter() {teardown_filter# Create or flush forward chainiptables -N ${filter_forward_chain} 2> /dev/null || iptables -F ${filter_forward_chain}iptables -A ${filter_forward_chain} -j DROP# Create or flush default chainiptables -N ${filter_default_chain} 2> /dev/null || iptables -F ${filter_default_chain}# Always allow established connections to warden containersiptables -A ${filter_default_chain} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTfor n in ${ALLOW_NETWORKS}; doif [ "$n" == "" ]thenbreakfiiptables -A ${filter_default_chain} --destination "$n" --jump RETURNdonefor n in ${DENY_NETWORKS}; doif [ "$n" == "" ]thenbreakfiiptables -A ${filter_default_chain} --destination "$n" --jump DROPdoneiptables -A ${filter_default_chain} --jump REJECT# Accept packets related to previously established connectionsiptables -I INPUT -m state --state ESTABLISHED,RELATED --jump ACCEPT -m comment --comment 'related-traffic'# Reject traffic from containers to hostif [ "$ALLOW_HOST_ACCESS" != "true" ]; theniptables -A INPUT -s ${POOL_NETWORK} --jump REJECT -m comment --comment 'block-traffic-to-host'fi# Forward outbound traffic via ${filter_forward_chain}iptables -A FORWARD -i w-+ --jump ${filter_forward_chain}# Forward inbound traffic immediatelydefault_interface=$(ip route show | grep default | cut -d' ' -f5 | head -1)iptables -I ${filter_forward_chain} -i $default_interface --jump ACCEPT }? ? ? ? 下面首先逐步分析每一個(gè)部分iptables的制定的意義。隨后將各iptables個(gè)則串聯(lián)起來(lái)分析其功能。
關(guān)于iptables在內(nèi)核中的簡(jiǎn)要流程圖例如以下圖:
下面逐步分析filter_setup方法:
1. 在該net.sh文件里,teardown_filter方法所做的工作是:清除某些warden相關(guān)的iptable鏈以及規(guī)則。
隨后的即創(chuàng)建兩條鏈:filter_forward_chain以及filter_forward_chain。增加這兩條鏈先前存在的話,清楚該兩條鏈之后再創(chuàng)建。
2. 對(duì)于已經(jīng)和warden container建立完成的連接,iptables都運(yùn)行ACCEPT操作。代碼即: # Always allow established connections to warden containersiptables -A ${filter_default_chain} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT? ? ? ? 由凝視能夠發(fā)現(xiàn),該規(guī)則加入在filter_default_chain鏈中,當(dāng)匹配條件為:該數(shù)據(jù)包表示為是在已建立的連接上傳輸時(shí)。對(duì)該數(shù)據(jù)包採(cǎi)取ACCEPT操作。
該規(guī)則從功能的角度非常好理解,也就是:假如warden container內(nèi)部發(fā)起一個(gè)請(qǐng)求,向外建立一個(gè)連接,則在該連接上返回?cái)?shù)據(jù)包時(shí),始終接受這種數(shù)據(jù)包。
然而。我始終對(duì)該規(guī)則的底層實(shí)現(xiàn),抱有非常大的疑惑。
待下文分析了很多其它的warden 網(wǎng)絡(luò)背景知識(shí)之后,再進(jìn)行進(jìn)一步的闡述。
3.在filter_default_chain中。對(duì)于ALLOW_NETWORKS中的網(wǎng)絡(luò)主機(jī)地址。始終採(cǎi)取ACCEPT操作;而對(duì)于DENY_NETWORKS中的網(wǎng)絡(luò)主機(jī)地址。使用採(cǎi)取DROP操作。
在此。能夠簡(jiǎn)要說(shuō)明一下在iptables中DROP與REJECT的差別。DROP:直接採(cǎi)取丟棄數(shù)據(jù)包的操作;REJECT:對(duì)于原來(lái)的數(shù)據(jù)包採(cǎi)取丟棄措施。隨后向數(shù)據(jù)包的發(fā)送方,返回一個(gè)類(lèi)似于ICMP錯(cuò)誤的信息包。
4.之后的shell代碼為:iptables -A ${filter_default_chain} --jump REJECT,因?yàn)閕ptables中一個(gè)數(shù)<br
據(jù)包在同一個(gè)鏈中的規(guī)則匹配將從第一條開(kāi)始匹配,遇到匹配成功則運(yùn)行對(duì)應(yīng)操作,否則繼續(xù)向下運(yùn)行,因此該規(guī)則表明這條臉中之前都匹配不成的數(shù)據(jù)包。內(nèi)核會(huì)採(cǎi)取REJECT操作,將數(shù)據(jù)包丟棄。并返回一個(gè)錯(cuò)誤數(shù)據(jù)包。到此,filter_default_chain中的規(guī)則設(shè)置基本完成。
5.在INPUT鏈中加入規(guī)則,所謂INPUT鏈,即當(dāng)網(wǎng)卡發(fā)現(xiàn)接收到的網(wǎng)絡(luò)數(shù)據(jù)包的目的IP。與網(wǎng)卡的IP一致時(shí),將該數(shù)據(jù)包放入INPUT鏈運(yùn)行規(guī)則處理,此處的代碼例如以下: # Accept packets related to previously established connectionsiptables -I INPUT -m state --state ESTABLISHED,RELATED --jump ACCEPT -m comment --comment 'related-traffic'# Reject traffic from containers to hostif [ "$ALLOW_HOST_ACCESS" != "true" ]; theniptables -A INPUT -s ${POOL_NETWORK} --jump REJECT -m comment --comment 'block-traffic-to-host'fi 在INPUT鏈中設(shè)定規(guī)則。保證在warden宿主機(jī)上原先與外部建立的連接上。發(fā)送來(lái)的數(shù)據(jù)包。都將採(cǎi)取ACCEPT操作。其次通過(guò)ALLOW_HOST_ACCESS變量來(lái)確定是否同意warden container與warden server所在宿主機(jī)之間的通信,若該變量為假。則對(duì)于從POOL_NETWORKS中發(fā)送來(lái)的數(shù)據(jù)包,都採(cǎi)取REJECT操作。保證warden container內(nèi)部不能訪問(wèn)warden server所在的宿主機(jī)。
到此。對(duì)于INPUT鏈的規(guī)則制定已經(jīng)完畢。
6.制定iptables中的FORWARD鏈,所謂FOWARD
創(chuàng)建warden container之net.sh鏈。即當(dāng)網(wǎng)絡(luò)發(fā)現(xiàn)接收的網(wǎng)絡(luò)數(shù)據(jù)包的目的IP,與該網(wǎng)卡的IP不一致時(shí),則覺(jué)得須要為該數(shù)據(jù)包運(yùn)行轉(zhuǎn)發(fā)(FORWARD)操作。將該數(shù)據(jù)包放入FORWARD鏈運(yùn)行規(guī)則處理。此處的代碼例如以下: # Forward outbound traffic via ${filter_forward_chain}iptables -A FORWARD -i w-+ --jump ${filter_forward_chain}# Forward inbound traffic immediatelydefault_interface=$(ip route show | grep default | cut -d' ' -f5 | head -1)iptables -I ${filter_forward_chain} -i $default_interface --jump ACCEPT? ? ? ? 當(dāng)中第一條規(guī)則表示:對(duì)于從網(wǎng)絡(luò)設(shè)備接口名字為‘w-+’(正則表達(dá)式。也就是為warden container而虛擬出的虛擬網(wǎng)卡的設(shè)備名字)發(fā)來(lái)。同一時(shí)候又須要運(yùn)行轉(zhuǎn)發(fā)工作的數(shù)據(jù)包。將該數(shù)據(jù)包跳轉(zhuǎn)至filter_forward_chain鏈。這樣保證了,全部從warden container發(fā)出,又不是發(fā)往宿主機(jī)的網(wǎng)卡的數(shù)據(jù)包,進(jìn)入FORWARD鏈后直接進(jìn)入filter_forward_chain鏈。 而后的規(guī)則表明,在filter_forward_chain中的數(shù)據(jù)包,僅僅要是來(lái)自于default_interface。都將採(cǎi)取ACCEPT操作。也就是說(shuō)。當(dāng)發(fā)現(xiàn)filter_forward_chain中的數(shù)據(jù)包的來(lái)源于warden server所在宿主機(jī)的物理網(wǎng)卡時(shí),馬上對(duì)該數(shù)據(jù)包採(cǎi)取ACCEPT操作。
到眼下為止。這個(gè)net.sh文件里的filter_setup方法已經(jīng)分步驟分析完成,然后關(guān)于整個(gè)運(yùn)行流,讀者可能仍然會(huì)有不小的疑惑,比方什么時(shí)候。綁定filter_default_chain鏈,使得數(shù)據(jù)包進(jìn)入該鏈,等等。
稍后分析完還有一個(gè)net.sh文件之后。再統(tǒng)一闡述。
setup_nat
??????? ? ? ?? 下面簡(jiǎn)單分析setup_nat方法:
function setup_nat() {teardown_nat# Create prerouting chainiptables -t nat -N ${nat_prerouting_chain} 2> /dev/null || true# Bind chain to PREROUTING(iptables -t nat -S PREROUTING | grep -q "\-j ${nat_prerouting_chain}\b") ||iptables -t nat -A PREROUTING \--jump ${nat_prerouting_chain}# Bind chain to OUTPUT (for traffic originating from same host)(iptables -t nat -S OUTPUT | grep -q "\-j ${nat_prerouting_chain}\b") ||iptables -t nat -A OUTPUT \--out-interface "lo" \--jump ${nat_prerouting_chain}# Create postrouting chainiptables -t nat -N ${nat_postrouting_chain} 2> /dev/null || true# Bind chain to POSTROUTING(iptables -t nat -S POSTROUTING | grep -q "\-j ${nat_postrouting_chain}\b") ||iptables -t nat -A POSTROUTING \--jump ${nat_postrouting_chain}# Enable NAT for traffic coming from containers(iptables -t nat -S ${nat_postrouting_chain} | grep -q "\-j SNAT\b") ||iptables -t nat -A ${nat_postrouting_chain} \--source ${POOL_NETWORK} \--jump SNAT \--to $(external_ip) }
??????? 該部分的內(nèi)容比較easy理解:
??????? 1.首先創(chuàng)建nat_prerouting_chain 鏈,隨后將全部的PREROUTING鏈中的數(shù)據(jù)包都跳轉(zhuǎn)至nat_prerouting_chain;
??????? 2.隨后將鏈綁定在nat_prerouting_chain上,保證通過(guò)lo網(wǎng)絡(luò)設(shè)備的數(shù)據(jù)包,都跳轉(zhuǎn)到該鏈;
??????? 3.創(chuàng)建nat_postrouting_chain鏈,保證將默認(rèn)的POSTROUTING鏈中的全部數(shù)據(jù)包都跳轉(zhuǎn)至創(chuàng)建的該鏈。
??????? 4.為從warden container中發(fā)出的數(shù)據(jù)包都採(cǎi)取SNAT處理。使得數(shù)據(jù)包的源IP都替換為warden server宿主機(jī)的IP。
??????? 事實(shí)上在完畢以上這兩步之后,還運(yùn)行了下面代碼:
# Enable forwarding echo 1 > /proc/sys/net/ipv4/ip_forward??????? 加以保證轉(zhuǎn)發(fā)工作能夠有效,詳細(xì)內(nèi)容能夠查看:/proc/sys/net/ipv4/*的各部分作用。
創(chuàng)建warden container之net.sh
???????
??????? 前篇分析的是。warden server啟動(dòng)的時(shí)候,對(duì)warden server所在的宿主機(jī)進(jìn)行的iptbales設(shè)置。在整個(gè)過(guò)程中,不涉及不論什么的container。而這一章節(jié),將介紹分析warden server在啟動(dòng)某個(gè)詳細(xì)warden container的時(shí)候,再對(duì)warden server所在的宿主機(jī)設(shè)置iptables規(guī)則。
該文件地址例如以下:warden/warden/root/linux/skeleton/net.sh。
setup_filter
??????? 首先分析setup_filter方法,源代碼例如以下:
function setup_filter() {teardown_filter# Create instance chainiptables -N ${filter_instance_chain}iptables -A ${filter_instance_chain} \--goto ${filter_default_chain}# Bind instance chain to forward chainiptables -I ${filter_forward_chain} 2 \--in-interface ${network_host_iface} \--goto ${filter_instance_chain}# Create instance log chainiptables -N ${filter_instance_log_chain}iptables -A ${filter_instance_log_chain} \-p tcp -m conntrack --ctstate NEW,UNTRACKED,INVALID -j LOG --log-prefix "${filter_instance_chain} "iptables -A ${filter_instance_log_chain} \--jump RETURN }??????? 1. 該方法創(chuàng)建了關(guān)于instance的鏈。隨后,將該warden container instance鏈內(nèi)的全部數(shù)據(jù)包都跳至filter_default_chain,也就是在前一章節(jié)中提到的filter_default_chain;
??????? 2.綁定該warden container instance的FORWARD鏈至filter_foward鏈,也就是說(shuō),全部進(jìn)入filter_foward_chain的數(shù)據(jù)包,依據(jù)數(shù)據(jù)包從哪個(gè)網(wǎng)絡(luò)接口設(shè)備來(lái),進(jìn)入對(duì)應(yīng)的filter_instance_chain鏈。也就是說(shuō),從network_host_iface網(wǎng)絡(luò)設(shè)備“接收”到的數(shù)據(jù)包(network_host_iface即為network_container_iface="w-${id}-1"),都轉(zhuǎn)至filter_instance_chain。
??????? 3.創(chuàng)建log chain。
setup_nat
???????
??????? 在創(chuàng)建warden container的時(shí)候,也會(huì)設(shè)置nat,源代碼例如以下:
function setup_nat() {teardown_nat# Create instance chainiptables -t nat -N ${nat_instance_chain}# Bind instance chain to prerouting chainiptables -t nat -A ${nat_prerouting_chain} \--jump ${nat_instance_chain} }??????? 簡(jiǎn)要分析即為:創(chuàng)建對(duì)應(yīng)的nat_instance_chain,隨后將nat_prerouting_chain中的數(shù)據(jù)包都跳轉(zhuǎn)至該nat_instance_chain。
net_in之port映射實(shí)現(xiàn)
???????
??????? 使得Cloud Foundry內(nèi)warden container的用戶應(yīng)用實(shí)例能夠?yàn)橥獠刻峁﹚eb服務(wù),那么warden container和warden server所在宿主機(jī)進(jìn)行一個(gè)port映射操作,也就是warden server提供的net_in接口,真正的運(yùn)行部分。即為創(chuàng)建容器的該net.sh文件里的in參數(shù)運(yùn)行。
??????? 下面是net_in詳細(xì)操作的源代碼實(shí)現(xiàn):
"in")if [ -z "${HOST_PORT:-}" ]; thenecho "Please specify HOST_PORT..." 1>&2exit 1fiif [ -z "${CONTAINER_PORT:-}" ]; thenecho "Please specify CONTAINER_PORT..." 1>&2exit 1fiiptables -t nat -A ${nat_instance_chain} \--protocol tcp \--destination "${external_ip}" \--destination-port "${HOST_PORT}" \--jump DNAT \--to-destination "${network_container_ip}:${CONTAINER_PORT}";;??????? 可見(jiàn)該代碼塊中最為重要的部分為。創(chuàng)建DNAT規(guī)則轉(zhuǎn)換的部分。也就是,在對(duì)應(yīng)的instance規(guī)則鏈中,對(duì)于TCP數(shù)據(jù)包,假設(shè)該數(shù)據(jù)包的目的IP和目的PORT為warden server所在宿主機(jī)的IP和映射的PORT。則運(yùn)行DNAT轉(zhuǎn)換,轉(zhuǎn)換為warden container IP和warden container的port。
總結(jié)
??????
??????? 以上便是對(duì)Cloud Foundry v2中warden的網(wǎng)絡(luò)設(shè)計(jì)之iptables規(guī)則制定。做了簡(jiǎn)要的分析。然而,在這之中,有非常多的設(shè)計(jì)不過(guò)留了接口,并未真正實(shí)現(xiàn)。
另,感謝浙江大學(xué)VLIS實(shí)驗(yàn)室的實(shí)習(xí)生高相林的共同研究。
關(guān)于作者:
孫宏亮。DAOCLOUD軟件project師。
兩年來(lái)在云計(jì)算方面主要研究PaaS領(lǐng)域的相關(guān)知識(shí)與技術(shù)。
堅(jiān)信輕量級(jí)虛擬化容器的技術(shù),會(huì)給PaaS領(lǐng)域帶來(lái)深度影響,甚至決定未來(lái)PaaS技術(shù)的走向。
轉(zhuǎn)載請(qǐng)注明出處。
本文很多其它出于我本人的理解,肯定在一些地方存在不足和錯(cuò)誤。
希望本文可以對(duì)接觸warden網(wǎng)絡(luò)配置的人有些幫助,假設(shè)你對(duì)這方面感興趣。并有更好的想法和建議,也請(qǐng)聯(lián)系我。
我的郵箱:allen.sun@daocloud.io 新浪微博:@蓮子弗如清《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的Cloud Foundry中warden的网络设计实现——iptable规则配置的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 手把手Tinyxml入门,C++ VS
- 下一篇: 第十一章 块(上)