kubernets的網路外掛程式:flannel

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
  • docker的網路方案
  • k8s的flannel模式
    • flannel模式原理
    • flannel模式的優缺點
  • 部署及驗證

kubernets的網路,從設計上來講是“扁平、直接”的,即要求:

  • 所有容器可以不使用NAT技術就可以與其他容器通訊
  • 所有節點(物理機 虛擬機器 容器)都可以不使用NAT同容器通訊
  • 容器看到的IP地址和別的機器看到的IP是一致的

docker的網路方案

docker的網路支援如下四種:

  • none
  • host,與宿主機共用,佔用宿主機資源
  • container,使用某容器的namespace,例如k8s的同一pod內的各個容器
  • bridge,掛到橋接器docker0上,走iptables做NAT

實際上還有一種方法:先以none的方式run起來容器,然後使用pipework為容器增加一個veth網卡,該veth的另一端掛到建立的橋接器br0上;再將宿主機的物理網卡掛到該橋接器br0上:

[容器內eth0]--veth--br0--en0-->

需要注意這種方法與bridge的不同。docker0的網段是172.17.0.1/16,當bridge模式時,容器的ip地址均為此網段下的,報文是走NAT出去的。但pipework自訂網路時,br0、[eth0]均與宿主機的en0同一網段,報文走橋接器轉寄出去。

docker的網路能否滿足需求呢?

bridge模式下,不同物理機的容器ip是完全的平行空間,可能相同,不能滿足k8s扁平的要求;pipework方式能夠滿足k8s的要求,但是需要為每個容器都指定ip地址,比較囉嗦。

k8s的flannel模式

k8s本身並不提供網路方案,而是交給flannel,ovs等add-on來處理。這裡只對flannel做說明。

flannel模式原理

flannel是一種over-lay網路。簡單來說,over-lay即報文在進入實際物理網路之前,會經過一層UDP封裝,作為payload到達對端;對端拿到UDP報文後解包,得到真實的使用者報文後,再轉到真實的接收方。

以綠色線的一個具體報文來說:

1、Pod內的一個容器使用pod的網路namespace,發送報文;該網路namespace上的網卡類型為veth,其pair網卡為宿主機網路namespace空間上的veth網卡veth0。veth是一種類似管道的網路裝置,總是成對出現,報文從一端的veth網卡發送後,另一端的veth網卡會收到該報文。通常容器、虛擬機器,會建立一對veth網卡,並將其中一端加到自己的namespace中。因此,宿主機的veth0網卡會收到容器發出的報文。

2、veth0拿到後,由於目的地址10.1.20.x與veth不在同一網段,因此會將報文交給橋接器來轉寄。官方圖示為docker0,但出於網路地址規劃的原因,實際在k8s上會建立一個cni0橋接器,cni0橋接器負責本node容器的ip分配(24位元遮罩)。這裡有一個問題:各個node都有自己的cni0橋接器,怎麼保證地址不會分配重複呢?這裡就是靠flannel了,flannel會根據全域統一的etcd來為每個node分配全叢集唯一的網段,避免地址分配衝突。cnio拿到報文後,查詢本機路由,匹配的是16位元遮罩的flannel.1,因此將報文丟給flannel.1。

[root@note2 ~]# route -nKernel IP routing tableDestination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         192.168.181.254 0.0.0.0         UG    100    0        0 eno1678003210.1.0.0        0.0.0.0         255.255.0.0     U     0      0        0 flannel.110.1.15.0       0.0.0.0         255.255.255.0   U     0      0        0 cni0172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0192.168.181.0   0.0.0.0         255.255.255.0   U     100    0        0 eno16780032

3、flannel.1是個什麼類型的網卡呢?圖示的下一跳是flanneld,一個使用者態進程(當然,這個進程已經封裝在docker容器裡了),這是怎麼實現的呢?這裡需要重提一下linux上使用者態和核心態通訊的手段。一般來說,有以下幾種:

  • netlink socket
  • syscall,例如調用使用者態的read/write介面
  • IOCTL
  • procfs,例如讀取/proc目錄下的ip統計計數

還有一種手段,使用TUN/TAP介面。

tun/tap驅動程式實現了虛擬網卡的功能,tun表示虛擬是點對點裝置,tap表示虛擬是乙太網路裝置,這兩種裝置針對網路包實施不同的封裝。利用tun/tap驅動,可以將tcp/ip協議棧處理好的網路分包傳給任何一個使用tun/tap驅動的進程,由進程重新處理後再發到物理鏈路中。開源項目openvpn( http://openvpn.sourceforge.net)和Vtun( http://vtun.sourceforge.net)都是利用tun/tap驅動實現的隧道封裝

具體到k8s上,flanneld封裝在flannel-git容器中,該容器與宿主機是同一網路namespace;flanneld啟動時會建立flannel.1網卡,用來接收所有發送到10.1.0.0/16網路的報文;上面第2步報文轉給flannel.1後,核心會將報文上送給flanneld。

[root@node1 ~]# docker ps92197740eeef        quay.io/coreos/flannel-git:v0.6.1-62-g6d631ba-amd64   "/opt/bin/flanneld --"   22 hours ago        Up 22 hours                             k8s_kube-flannel.135690a3_kube-flannel-ds-ze30q_kube-system_ce4936c7-dd2c-11e6-9af1-000c29906342_1faf7ca4

4、flanneld維護了一份全域的node網路資訊,根據報文目的地址查詢得到該地址對應的node資訊後,將報文封裝到udp中(新報文的目的地址為對應node的地址),再將封裝後的udp報文查詢路由後經過物理網路(eno16780032)發送給目的node。

5、對端node收到報文後,走普通的查詢路由為本機後上送使用者態流程,封裝報文交給flanneld。之後,報文解包、根據新包目的地址查路由,交給目的pod的容器。

[root@node1 ~]# netstat -anup|moreActive Internet connections (servers and established)Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    udp        0      0 0.0.0.0:8472            0.0.0.0:*   

flannel模式的優缺點

最大的缺點是,所有報文都需要走flanneld這個使用者態進程進行一次封裝後,才能出去。當網路流量較大時,flanneld將會成為瓶頸;相對來說,open vswitch可能穩定性、可靠性會更好一些。但flannel也有ovs所不具備的優點:flannel能夠通過etcd感知k8s的service變動,動態維護自己的路由表(第4步)。

部署及驗證

1、部署flannel部署比較簡單。在master上kubeadm init完成後,執行下面的命令。該yaml定義了flannel容器以及相關的配置容器。有一些材料沒有使用容器部署,相對來說複雜一點。

kubectl create -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

之後查看kube-flannel的狀態,Running則成功。此時k8s叢集只有master一台機器,再登陸到2個node上,執行kubeadm join --token={token_id} master_ip將node加入到k8s叢集中。最終在master上查看結果如下。

[root@localhost k8s]# kubectl get nodesNAME                    STATUS    AGElocalhost.localdomain   Ready     1dnode1                   Ready     23hnote2                   Ready     23h[root@localhost k8s]#[root@localhost k8s]# kubectl get pods -n kube-systemNAME                                            READY     STATUS    RESTARTS   AGEdummy-2088944543-vafe7                          1/1       Running   0          1detcd-localhost.localdomain                      1/1       Running   1          1dkube-apiserver-localhost.localdomain            1/1       Running   1          1dkube-controller-manager-localhost.localdomain   1/1       Running   0          1dkube-discovery-982812725-5j9ri                  1/1       Running   0          1dkube-dns-2247936740-gqifl                       3/3       Running   0          1dkube-flannel-ds-kfcpe                           2/2       Running   0          1dkube-flannel-ds-klmfz                           2/2       Running   7          23hkube-flannel-ds-ze30q                           2/2       Running   4          23hkube-proxy-amd64-2yx0g                          1/1       Running   0          1dkube-proxy-amd64-hcj9t                          1/1       Running   0          23hkube-proxy-amd64-vhevz                          1/1       Running   0          23hkube-scheduler-localhost.localdomain            1/1       Running   1          1d

在node上,可以看到flannel.1等網卡資訊。

2、驗證

將下面的RC儲存為alpine.yaml。

apiVersion: v1kind: ReplicationControllermetadata:  name: alpine  labels:    name: alpinespec:  replicas: 2  selector:    name: alpine  template:    metadata:      labels:        name: alpine    spec:      containers:        - image: mritd/alpine:3.4          imagePullPolicy: Always          name: alpine          command:            - "bash"            - "-c"            - "while true;do echo test;done"          ports:            - containerPort: 8080              name: alpine

並建立namespace、apply。

kubectl create namespace alpinekubectl apply -n alpine -f alpine.yml

等待一段時間後,在master上查看apply情況(-o wide可以看到更多資訊,即IP/node):

[root@localhost k8s]# kubectl get pods -n alpine -o wideNAME           READY     STATUS    RESTARTS   AGE       IP           NODEalpine-4zmey   1/1       Running   0          23h       10.244.1.2   note2alpine-55zej   1/1       Running   0          23h       10.244.2.2   node1

2個pod分別跑在2個node上(前面yml定義的replicas為2)。

登陸到其中一個node上,進入對應的容器docker exec -it {docker_id} bash,ping對端的ip地址看是否通。如果不通,可能你使用的也是CentOS作業系統,它的iptables預設會丟棄所有報文並回複icmp-host-prohibited,所以需要將flanneld監聽的8472連接埠/udp協議的報文加到INPUT鏈上,各個物理node上都要執行。當然,我覺得更好的做法是flannel自己來加這條規則。

[root@node1 ~]# iptables -I INPUT -p udp -m udp --dport 8472 -j ACCEPT[root@node1 ~]#[root@node1 ~]# iptables -L -n|moreChain INPUT (policy ACCEPT)target     prot opt source               destination         ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:8472...REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

在物理網卡上抓了個包,可以看到該UDP包的payload中黑色橫線標記的2個ip地址。

以上。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.