天天看點

了解Kubernetes網絡之Flannel網絡

第一次 采用kube-up.sh腳本方式安裝 的Kubernetes cluster目前運作良好,master node上的元件狀态也始終是“沒毛病”:

# kubectl get cs NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health": "true"}           

不過在第二次嘗試

用kubeadm安裝和初始化Kubernetes cluster

時遇到的各種網絡問題還是讓我 “心有餘悸”。于是趁上個周末,對Kubernetes的網絡原理進行了一些針對性的學習。這裡把對Kubernetes網絡的了解記錄一下和大家一起分享。

Kubernetes支援

Flannel

Calico Weave network

等多種

cni網絡

Drivers,但由于學習過程使用的是第一個cluster的Flannel網絡,這裡的網絡原理隻針對k8s+Flannel網絡。

一、環境+提示

凡涉及到Docker、Kubernetes這類正在active dev的開源項目的文章,我都不得不提一嘴,那就是随着K8s以及flannel的演化,本文中的一些說法可能不再正确。提醒大家:閱讀此類技術文章務必結合“環境”。

這裡我們使用的環境就是我第一次建立k8s cluster的環境:

# kube-apiserver --version
Kubernetes v1.3.7

# /opt/bin/flanneld -version
0.5.5

# /opt/bin/etcd -version
etcd Version: 3.0.12
Git SHA: 2d1e2e8
Go Version: go1.6.3
Go OS/Arch: linux/amd64           

另外整個叢集搭建在

阿裡雲

上,每個ECS上的OS及kernel版本:Ubuntu 14.04.4 LTS,3.19.0-70-generic。

在我的測試環境,有兩個node:master node和一個minion node。master node參與workload的排程。是以你基本可以認為有兩個minion node即可。

二、Kubernetes Cluster中的幾個“網絡”

之前的k8s cluster采用的是預設安裝,即直接使用了配置腳本中(kubernetes/cluster/ubuntu/config-default.sh)自帶的一些參數,比如:

//摘自kubernetes/cluster/ubuntu/config-default.sh

export nodes=${nodes:-"root@master_node_ip root@minion_node_ip"} export SERVICE_CLUSTER_IP_RANGE=${SERVICE_CLUSTER_IP_RANGE:-192.168.3.0/24} export FLANNEL_NET=${FLANNEL_NET:-172.16.0.0/16}           

從這裡我們能夠識别出三個“網絡”:

  • node network:承載kubernetes叢集中各個“實體”Node(master和minion)通信的網絡;
  • service network:由kubernetes叢集中的Services所組成的“網絡”;
  • flannel network: 即Pod網絡,叢集中承載各個Pod互相通信的網絡。

node network自不必多說,node間通過你的本地區域網路(無論是實體的還是虛拟的)通信。

service network比較特殊,每個新建立的service會被配置設定一個service IP,在目前叢集中,這個IP的配置設定範圍是192.168.3.0/24。不過這個IP并不“真實”,更像一個“占位符”并且隻有入口流量,所謂的“network”也是“名不符實”的,後續我們會詳盡說明。

flannel network是我們要了解的重點,cluster中各個Pod要實作互相通信,必須走這個網絡,無論是在同一node上的Pod還是跨node的Pod。我們的cluster中,flannel net的配置設定範圍是:172.16.0.0/16。

在進一步挖掘“原理”之前,我們先來直覺認知一下service network和flannel network:

Service network(看cluster-ip一列):

# kubectl get services NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
index-api 192.168.3.168 <none> 30080/TCP 18d
kubernetes 192.168.3.1 <none> 443/TCP 94d
my-nginx 192.168.3.179 <nodes> 80/TCP 90d
nginx-kit 192.168.3.196 <nodes> 80/TCP 12d
rbd-rest-api 192.168.3.22 <none> 8080/TCP 60d           

Flannel network(看IP那列):

# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE
my-nginx-2395715568-gpljv 1/1 Running 6 91d 172.16.99.3 {master node ip}
nginx-kit-3872865736-rc8hr 2/2 Running 0 12d 172.16.57.7 {minion node ip}
... ...           

三、平坦的Flannel網絡

1、Kubenetes安裝後的網絡狀态

首先讓我們來看看:

kube-up.sh在安裝k8s叢集

時對各個K8s Node都動了什麼手腳!

a) 修改docker default配置

在ubuntu 14.04下,docker的配置都在/etc/default/docker檔案中。如果你曾經修改過該檔案,那麼kube-up.sh腳本方式安裝完kubernetes後,你會發現/etc/default/docker已經變樣了,隻剩下了一行:

master node:
DOCKER_OPTS=" -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock --bip=172.16.99.1/24 --mtu=1450"

minion node:
DOCKER_OPTS=" -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock --bip=172.16.57.1/24 --mtu=1450"           

可以看出kube-up.sh修改了Docker daemon的–bip選項,使得該node上docker daemon在該node的fannel subnet範圍以内為啟動的Docker container配置設定IP位址。

b) 在etcd中初始化flannel網絡資料

多個node上的Flanneld依賴一個

etcd cluster

來做集中配置服務,etcd保證了所有node上flanned所看到的配置是一緻的。同時每個node上的flanned監聽etcd上的資料變化,實時感覺叢集中node的變化。

我們可以通過etcdctl查詢到這些配置資料:

master node:

//flannel network配置 # etcdctl --endpoints http://127.0.0.1:{etcd listen port} get /coreos.com/network/config
{"Network":"172.16.0.0/16", "Backend": {"Type": "vxlan"}}

# etcdctl --endpoints http://127.0.0.1:{etcd listen port} ls /coreos.com/network/subnets
/coreos.com/network/subnets/172.16.99.0-24
/coreos.com/network/subnets/172.16.57.0-24 //某一node上的flanne subnet和vtep配置 # etcdctl --endpoints http://127.0.0.1:{etcd listen port} get /coreos.com/network/subnets/172.16.99.0-24
{"PublicIP":"{master node ip}","BackendType":"vxlan","BackendData":{"VtepMAC":"b6:bf:4c:81:cf:3b"}}

minion node:
# etcdctl --endpoints http://127.0.0.1:{etcd listen port} get /coreos.com/network/subnets/172.16.57.0-24
{"PublicIP":"{minion node ip}","BackendType":"vxlan","BackendData":{"VtepMAC":"d6:51:2e:80:5c:69"}}           

或用etcd 提供的rest api:

# curl -L http://127.0.0.1:{etcd listen port}/v2/keys/coreos.com/network/config
{"action":"get","node":{"key":"/coreos.com/network/config","value":"{\"Network\":\"172.16.0.0/16\", \"Backend\": {\"Type\": \"vxlan\"}}","modifiedIndex":5,"createdIndex":5}}           

c) 啟動flanneld

kube-up.sh在每個Kubernetes node上啟動了一個flanneld的程式:

# ps -ef|grep flanneld master node:
root 1151 1 0 2016 ? 00:02:34 /opt/bin/flanneld --etcd-endpoints=http://127.0.0.1:{etcd listen port} --ip-masq --iface={master node ip}

minion node:
root 11940 1 0 2016 ? 00:07:05 /opt/bin/flanneld --etcd-endpoints=http://{master node ip}:{etcd listen port} --ip-masq --iface={minion node ip}           

一旦flanneld啟動,它将從etcd中讀取配置,并請求擷取一個subnet lease(租約),有效期目前是24hrs,并且監視etcd的資料更新。flanneld一旦擷取subnet租約、配置完backend,它會将一些資訊寫入/run/flannel/subnet.env檔案。

master node:
# cat /run/flannel/subnet.env
FLANNEL_NETWORK=172.16.0.0/16
FLANNEL_SUBNET=172.16.99.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true

minion node:
# cat /run/flannel/subnet.env
FLANNEL_NETWORK=172.16.0.0/16
FLANNEL_SUBNET=172.16.57.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true           

當然flanneld的最大意義在于根據etcd中存儲的全cluster的subnet資訊,跨node傳輸flannel network中的資料包,這個後面會詳細說明。

d) 建立flannel.1 網絡裝置、更新路由資訊

各個node上的網絡裝置清單新增一個名為flannel.1的類型為vxlan的網絡裝置:

master node:

# ip -d link show 4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
 link/ether b6:bf:4c:81:cf:3b brd ff:ff:ff:ff:ff:ff promiscuity 0
 vxlan id 1 local {master node local ip} dev eth0 port 0 0 nolearning ageing 300

minion node:

349: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
 link/ether d6:51:2e:80:5c:69 brd ff:ff:ff:ff:ff:ff promiscuity 0
 vxlan id 1 local {minion node local ip} dev eth0 port 0 0 nolearning ageing 300           

從flannel.1的裝置資訊來看,它似乎與eth0存在着某種bind關系。這是在其他bridge、veth裝置描述資訊中所沒有的。

flannel.1裝置的ip:

master node:

flannel.1 Link encap:Ethernet HWaddr b6:bf:4c:81:cf:3b inet addr:172.16.99.0 Bcast:0.0.0.0 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:5993274 errors:0 dropped:0 overruns:0 frame:0 TX packets:5829044 errors:0 dropped:292 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1689890445 (1.6 GB) TX bytes:1144725704 (1.1 GB)

minion node:

flannel.1 Link encap:Ethernet HWaddr d6:51:2e:80:5c:69 inet addr:172.16.57.0 Bcast:0.0.0.0 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:6294640 errors:0 dropped:0 overruns:0 frame:0 TX packets:5755599 errors:0 dropped:25 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:989362527 (989.3 MB) TX bytes:1861492847 (1.8 GB)           

可以看到兩個node上的flannel.1的ip與k8s cluster為兩個node上配置設定subnet的ip範圍是對應的。

下面是兩個node上的目前路由表:

master node:

# ip route
... ...
172.16.0.0/16 dev flannel.1 proto kernel scope link src 172.16.99.0 172.16.99.0/24 dev docker0 proto kernel scope link src 172.16.99.1
... ...

minion node:

# ip route
... ...
172.16.0.0/16 dev flannel.1 172.16.57.0/24 dev docker0 proto kernel scope link src 172.16.57.1
... ...           

以上資訊将為後續資料包傳輸分析打下基礎。

e) 平坦的flannel network

從以上kubernetes和flannel network安裝之後獲得的網絡資訊,我們能看出flannel network是一個flat network。在flannel:172.16.0.0/16這個大網下,每個kubernetes node從中配置設定一個子網片段(/24):

master node:
 --bip=172.16.99.1/24

minion node:
 --bip=172.16.57.1/24

root@node1:~# etcdctl --endpoints http://127.0.0.1:{etcd listen port} ls /coreos.com/network/subnets
/coreos.com/network/subnets/172.16.99.0-24
/coreos.com/network/subnets/172.16.57.0-24           

用一張圖來诠釋可能更為直覺:

這個是不是有些像x86-64的虛拟記憶體尋址空間啊(同樣是平坦記憶體位址通路模型)!

在平坦的flannel network中,每個pod都會被配置設定唯一的ip位址,且每個k8s node的subnet各不重疊,沒有交集。不過這樣的subnet配置設定模型也有一定弊端,那就是可能存在ip浪費:一個node上有200多個flannel ip位址(xxx.xxx.xxx.xxx/24),如果僅僅啟動了幾個Pod,那麼其餘ip就處于閑置狀态。

2、Flannel網絡通信原理

這裡我們模仿flannel官方的那幅原理圖,畫了一幅與我們的實驗環境比對的圖,作為後續讨論flannel網絡通信流程的基礎:

如上圖所示,我們來看看從pod1:172.16.99.8發出的資料包是如何到達pod3:172.16.57.15的(比如:在pod1的某個container中ping -c 3 172.16.57.15)。

a) 從Pod出發

由于k8s更改了docker的DOCKER_OPTS,顯式指定了–bip,這個值與配置設定給該node上的subnet的範圍是一緻的。這樣一來,docker引擎每次建立一個Docker container,該container被配置設定到的ip都在flannel subnet範圍内。

當我們在Pod1下的某個容器内執行ping -c 3 172.16.57.15,資料包便開始了它在flannel network中的旅程。

Pod是Kubernetes排程的基本unit。Pod内的多個container共享一個network namespace。kubernetes在建立Pod時,首先先建立pause容器,然後再以pause的network namespace為基礎,建立pod内的其他容器(–net=container:xxx),這樣Pod内的所有容器便共享一個network namespace,這些容器間的通路直接通過localhost即可。比如Pod下A容器啟動了一個服務,監聽8080端口,那麼同一個Pod下面的另外一個B容器通過通路localhost:8080即可通路到A容器下面的那個服務。

在之前的《

了解Docker容器網絡之Linux Network Namespace

》一文中,我相信我已經講清楚了單機下Docker容器資料傳輸的路徑。在這個環節中,資料包的傳輸路徑也并無不同。

我們看一下Pod1中某Container内的路由資訊:

# docker exec ba75f81455c7 ip route default via 172.16.99.1 dev eth0
172.16.99.0/24 dev eth0 proto kernel scope link src 172.16.99.8           

目的位址172.16.57.15并不在直連網絡中,是以資料包通過default路由出去。default路由的路由器位址是172.16.99.1,也就是上面的docker0 bridge的IP位址。相當于docker0 bridge以“三層的工作模式”直接接收到來自容器的資料包(而并非從bridge的二層端口接收)。

b) docker0與flannel.1之間的包轉發

資料包到達docker0後,docker0的核心棧處理程式發現這個資料包的目的位址是172.16.57.15,并不是真的要送給自己,于是開始為該資料包找下一hop。根據master node上的路由表:

master node:

# ip route
... ...
172.16.0.0/16 dev flannel.1 proto kernel scope link src 172.16.99.0 172.16.99.0/24 dev docker0 proto kernel scope link src 172.16.99.1
... ...           

我們比對到“172.16.0.0/16”這條路由!這是一條直連路由,資料包被直接送到flannel.1裝置上。

c) flannel.1裝置以及flanneld的功用

flannel.1是否會重複docker0的套路呢:包不是發給自己,轉發資料包?會,也不會。

“會”是指flannel.1肯定要将包轉發出去,因為畢竟包不是給自己的(包目的ip是172.16.57.15, vxlan裝置ip是172.16.99.0)。

“不會”是指flannel.1不會走尋常套路去轉發包,因為它是一個vxlan類型的裝置,也稱為vtep,virtual tunnel end point。

那麼它到底是怎麼處理資料包的呢?這裡涉及一些Linux核心對vxlan處理的内容,詳細内容可參見本文末尾的參考資料。

flannel.1收到資料包後,由于自己不是目的地,也要嘗試将資料包重新發送出去。資料包沿着網絡協定棧向下流動,在二層時需要封二層以太包,填寫目的mac位址,這時一般應該發出arp:”who is 172.16.57.15″。但vxlan裝置的特殊性就在于它并沒有真正在二層發出這個arp包,因為下面的這個核心參數設定:

master node:

# cat /proc/sys/net/ipv4/neigh/flannel.1/app_solicit
3           

而是由linux kernel引發一個”L3 MISS”事件并将arp請求發到使用者空間的flanned程式。

flanned程式收到”L3 MISS”核心事件以及arp請求(who is 172.16.57.15)後,并不會向外網發送arp request,而是嘗試從etcd查找該位址比對的子網的vtep資訊。在前面章節我們曾經展示過etcd中Flannel network的配置資訊:

master node:

# etcdctl --endpoints http://127.0.0.1:{etcd listen port} ls /coreos.com/network/subnets
/coreos.com/network/subnets/172.16.99.0-24
/coreos.com/network/subnets/172.16.57.0-24 # curl -L http://127.0.0.1:{etcd listen port}/v2/keys/coreos.com/network/subnets/172.16.57.0-24
{"action":"get","node":{"key":"/coreos.com/network/subnets/172.16.57.0-24","value":"{\"PublicIP\":\"{minion node local ip}\",\"BackendType\":\"vxlan\",\"BackendData\":{\"VtepMAC\":\"d6:51:2e:80:5c:69\"}}","expiration":"2017-01-17T09:46:20.607339725Z","ttl":21496,"modifiedIndex":2275460,"createdIndex":2275460}}           

flanneld從etcd中找到了答案:

subnet: 172.16.57.0/24
public ip: {minion node local ip}
VtepMAC: d6:51:2e:80:5c:69           

我們檢視minion node上的資訊,發現minion node上的flannel.1 裝置mac就是d6:51:2e:80:5c:69:

minion node:

#ip -d link show 349: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
 link/ether d6:51:2e:80:5c:69 brd ff:ff:ff:ff:ff:ff promiscuity 0
 vxlan id 1 local 10.46.181.146 dev eth0 port 0 0 nolearning ageing 300           

接下來,flanned将查詢到的資訊放入master node host的arp cache表中:

master node:

#ip n |grep 172.16.57.15 172.16.57.15 dev flannel.1 lladdr d6:51:2e:80:5c:69 REACHABLE           

flanneld完成這項工作後,linux kernel就可以在arp table中找到 172.16.57.15對應的mac位址并封裝二層以太包了。

到目前為止,已經呈現在大家眼前的封包如下圖:

不過這個封包還不能在實體網絡上傳輸,因為它實際上隻是vxlan tunnel上的packet。

d) kernel的vxlan封包

我們需要将上述的packet從master node傳輸到minion node,需要将上述packet再次封包。這個任務在backend為vxlan的flannel network中由linux kernel來完成。

flannel.1為vxlan裝置,linux kernel可以自動識别,并将上面的packet進行vxlan封包處理。在這個封包過程中,kernel需要知道該資料包究竟發到哪個node上去。kernel需要檢視node上的fdb(forwarding database)以獲得上面對端vtep裝置(已經從arp table中查到其mac位址:d6:51:2e:80:5c:69)所在的node位址。如果fdb中沒有這個資訊,那麼kernel會向使用者空間的flanned程式發起”L2 MISS”事件。flanneld收到該事件後,會查詢etcd,擷取該vtep裝置對應的node的”Public IP“,并将資訊注冊到fdb中。

這樣Kernel就可以順利查詢到該資訊并封包了:

master node:

# bridge fdb show dev flannel.1|grep d6:51:2e:80:5c:69
d6:51:2e:80:5c:69 dst {minion node local ip} self permanent           

由于目标ip是minion node,查找路由表,包應該從master node的eth0發出,這樣src ip和src mac位址也就确定了。封好的包示意圖如下:

e) kernel的vxlan拆包

minion node上的eth0接收到上述vxlan包,kernel将識别出這是一個vxlan包,于是拆包後将flannel.1 packet轉給minion node上的vtep(flannel.1)。minion node上的flannel.1再将這個資料包轉到minion node上的docker0,繼而由docker0傳輸到Pod3的某個容器裡。

3、Pod内到外部網絡

我們在Pod中除了可以與pod network中的其他pod通信外,還可以通路外部網絡,比如:

master node:
# docker exec ba75f81455c7 ping -c 3 baidu.com
PING baidu.com (180.149.132.47): 56 data bytes
64 bytes from 180.149.132.47: icmp_seq=0 ttl=54 time=3.586 ms
64 bytes from 180.149.132.47: icmp_seq=1 ttl=54 time=3.752 ms
64 bytes from 180.149.132.47: icmp_seq=2 ttl=54 time=3.722 ms
--- baidu.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 3.586/3.687/3.752/0.072 ms           

這個通信與vxlan就沒有什麼關系了,主要是通過docker引擎在iptables的POSTROUTING chain中設定的MASQUERADE規則:

mastre node:

#iptables -t nat -nL
... ...
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.16.99.0/24 0.0.0.0/0
... ...           

docker将容器的pod network位址僞裝為node ip出去,包回來時再snat回容器的pod network位址,這樣網絡就通了。

四、”不真實”的Service網絡

每當我們在k8s cluster中建立一個service,k8s cluster就會在–service-cluster-ip-range的範圍内為service配置設定一個cluster-ip,比如本文開始時提到的:

# kubectl get services NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
index-api 192.168.3.168 <none> 30080/TCP 18d
kubernetes 192.168.3.1 <none> 443/TCP 94d
my-nginx 192.168.3.179 <nodes> 80/TCP 90d
nginx-kit 192.168.3.196 <nodes> 80/TCP 12d
rbd-rest-api 192.168.3.22 <none> 8080/TCP 60d           

這個cluster-ip隻是一個虛拟的ip,并不真實綁定某個實體網絡裝置或虛拟網絡裝置,僅僅存在于iptables的規則中:

Chain PREROUTING (policy ACCEPT)
target prot opt source destination
KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */

# iptables -t nat -nL|grep 192.168.3
Chain KUBE-SERVICES (2 references)
target prot opt source destination
KUBE-SVC-XGLOHA7QRQ3V22RZ tcp -- 0.0.0.0/0 192.168.3.182 /* kube-system/kubernetes-dashboard: cluster IP */ tcp dpt:80
KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- 0.0.0.0/0 192.168.3.1 /* default/kubernetes:https cluster IP */ tcp dpt:443
KUBE-SVC-AU252PRZZQGOERSG tcp -- 0.0.0.0/0 192.168.3.22 /* default/rbd-rest-api: cluster IP */ tcp dpt:8080
KUBE-SVC-TCOU7JCQXEZGVUNU udp -- 0.0.0.0/0 192.168.3.10 /* kube-system/kube-dns:dns cluster IP */ udp dpt:53
KUBE-SVC-BEPXDJBUHFCSYIC3 tcp -- 0.0.0.0/0 192.168.3.179 /* default/my-nginx: cluster IP */ tcp dpt:80
KUBE-SVC-UQG6736T32JE3S7H tcp -- 0.0.0.0/0 192.168.3.196 /* default/nginx-kit: cluster IP */ tcp dpt:80
KUBE-SVC-ERIFXISQEP7F7OF4 tcp -- 0.0.0.0/0 192.168.3.10 /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:53
... ...           

可以看到在PREROUTING環節,k8s設定了一個target: KUBE-SERVICES。而KUBE-SERVICES下面又設定了許多target,一旦destination和dstport比對,就會沿着chain進行處理。

比如:當我們在pod網絡curl 192.168.3.22 8080時,比對到下面的KUBE-SVC-AU252PRZZQGOERSG target:

KUBE-SVC-AU252PRZZQGOERSG tcp -- 0.0.0.0/0 192.168.3.22 /* default/rbd-rest-api: cluster IP */ tcp dpt:8080           

沿着target,我們看到”KUBE-SVC-AU252PRZZQGOERSG”對應的内容如下:

Chain KUBE-SVC-AU252PRZZQGOERSG (1 references)
target prot opt source destination
KUBE-SEP-I6L4LR53UYF7FORX all -- 0.0.0.0/0 0.0.0.0/0 /* default/rbd-rest-api: */ statistic mode random probability 0.50000000000
KUBE-SEP-LBWOKUH4CUTN7XKH all -- 0.0.0.0/0 0.0.0.0/0 /* default/rbd-rest-api: */

Chain KUBE-SEP-I6L4LR53UYF7FORX (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 172.16.99.6 0.0.0.0/0 /* default/rbd-rest-api: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/rbd-rest-api: */ tcp to:172.16.99.6:8080

Chain KUBE-SEP-LBWOKUH4CUTN7XKH (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 172.16.99.7 0.0.0.0/0 /* default/rbd-rest-api: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/rbd-rest-api: */ tcp to:172.16.99.7:8080

Chain KUBE-MARK-MASQ (17 references)
target prot opt source destination
MARK all -- 0.0.0.0/0 0.0.0.0/0 MARK or 0x4000           

請求被按5:5開的比例分發(起到負載均衡的作用)到KUBE-SEP-I6L4LR53UYF7FORX 和KUBE-SEP-LBWOKUH4CUTN7XKH,而這兩個chain的處理方式都是一樣的,那就是先做mark,然後做dnat,将service ip改為pod network中的Pod IP,進而請求被實際傳輸到某個service下面的pod中處理了。

五、參考資料

http://www.w2bc.com/article/208449

本文轉自開源中國-理

解Kubernetes網絡之Flannel網絡