基於Kubeadm的Flannel分析

Flannel概述

Flannel是將多個不一樣子網(基於主機Node)經過被Flannel維護的Overlay網絡拼接成爲一張大網來實現互聯的,經過官方的一張網絡拓撲圖咱們能夠對其基本原理一目瞭然:node

值得探討的是,flannel的這個overlay網絡支持多種後端實現,除上圖中的UDP,還有VXLAN和host-gw等。此外,flannel支持經過兩種模式來維護隧道端點上FDB的信息,其中一種是經過鏈接Etcd來實現,另一種是直接對接K8S,經過K8S添加刪除Node來觸發更新。docker

Flannel部署常見問題

1. Node狀態顯示爲「NotReady」

個人K8S環境使用kubeadm來容器化運行K8S的各個組件(除kubelet直接運行在裸機上外),當我使用kubeadm join命令加入新的Minion Node到K8S集羣中後,經過kubectl get node會發現全部的node都仍是not ready狀態,這是由於尚未配置好flannel網絡。json

2. 使用kube-flannel.yml沒法建立DaemonSet

我使用的是K8S的1.6.4的版本,而後按照官方的說明,使用kube-flannel.yml來建立flannel deamon set,結果始終報錯。正確的姿式是先使用kube-flannel-rbac.yml來建立flannel的ClusterRole並受權。該yml的主要做用是建立名叫flannel的ClusterRole,而後將該ClusterRole與ServiceAccount(flannel)綁定。接下來,當咱們使用kube-flannel.yml來建立flannel daemon set的時候,該daemon set明確指定其Pod的ServiceAccount爲flannel,因而經過它啓動起來的Pod就具備了flannel ClusterRole中指定的權限。後端

3.flannel Pod狀態爲Running,網絡不通

我以前在個人Mac Pro上跑了三個VM,爲了可以訪問公網拉取鏡像,我爲每一個VM分配了一張網卡使用NAT模式,其分配到的IP地址可能重啓後發生變化。另外,爲了我本機方便管理,我爲每臺VM又分配了一張網卡使用Host-Only網絡模式,每一個網卡都有一個固定的IP地址方便SSH。而後,奇怪的事情就這樣發生了….api

緣由在與在kube-flannel.yml中,kube-flannel容器的command被指定爲:網絡

command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr"]

可見,其並無指定使用哪一張網卡做爲flanneld對外通訊的物理網卡,因而,可能因爲機器上面路由配置的差別,致使三臺機器並無一致經過Host-Only網絡模式的網卡來打通Overlay網絡。遇到這種狀況,若是幾臺機器的配置一致,能夠手動修改kube-flannel.yml文件中kube-flannel的command的值,添加參數–iface=ethX,這裏的ethX就爲咱們但願flanneld通訊使用的網卡名稱。分佈式

4.flannel啓動異常,顯示install-cni錯誤

這個現象比較坑,遇到這種狀況的第一反應就是去查看install-cni容器到底作了什麼。咱們打開kube-flannel.yml能夠看到,該容器的command字段只有簡單的一行Shell:ui

command: [ "/bin/sh", "-c", "set -e -x; cp -f /etc/kube-flannel/cni-conf.json /etc/cni/net.d/10-flannel.conf; while true; do sleep 3600; done" ]

也就是將鏡像中作好的cni-conf.json拷貝到cni的netconf目錄下。因爲容器的/etc/cni/net.d是掛載主機的對應的目錄,因此該操做主要目的是爲CNI準備flannel環境,便於啓動容器的時候正確從netconf目錄中加載到flannel,從而使用flannel網絡。spa

我發現進入主機的netconf目錄中可以看到10-flannel.conf:插件

#ls /etc/cni/net.d/10-flannel.conf
/etc/cni/net.d/10-flannel.conf
# cat /etc/cni/net.d/10-flannel.conf
cat: /etc/cni/net.d/10-flannel.conf: No such file or directory

沒法打出其內容,並且文件顯示爲紅色,說明其內容並無正確從容器中拷貝過來。

以前我懷疑該異常是由於kubelet所帶的文件系統參數爲systemd,而docker的文件系統參數爲cgroupfs所致,結果發現並不是如此。當前可以繞開該異常的workaround爲手動進入到主機的netconf目錄,建立10-flannel.conf目錄,並寫入如下數據:

{
"name": "cbr0",
 "type": "flannel",
 "delegate": {
 "isDefaultGateway": true
 }
}

5.flannel網絡啓動正常,可以建立pod,可是網絡不通

出現該現象通常會想到debug,而debug的思路固然是基於官方的那張網絡拓撲圖。好比在個人機器上,經過參看網卡IP地址有以下信息:

6: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN
link/ether 22:a0:ce:3c:bf:1f brd ff:ff:ff:ff:ff:ff
 inet 10.244.1.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet 10.244.2.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
7:cni0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1450 qdisc noqueue state DOWN qlen 1000
 link/ether 0a:58:0a:f4:01:01 brd ff:ff:ff:ff:ff:ff
inet 10.244.1.1/24 scope global cni0
valid_lft forever preferred_lft forever
inet6 fe80::4cb6:7fff:fedb:2106/64 scope link
valid_lft forever preferred_lft forever

很明顯,cni0爲10.244.1.1/24網段,說明該主機應該位於10.244.1.0/16子網內;可是咱們看flannel.1網卡,確有兩個IP地址,分別爲於兩個不一樣的」/16」子網。因此,能夠確定的是,咱們必定是在該太主機上部署了屢次kubeadm,而kubeadm reset並不會清理flannel建立的flannel.1和cni0接口,這就致使環境上遺留下了上一次部署分配到的IP地址。這些IP地址會致使IP地址衝突,子網混亂,網絡通訊異常。

解決的方法就是每次執行kubeadm reset的時候,手動執行如下命令來清楚對應的殘餘網卡信息:

ip link del cni0
ip link del flannel.1

K8S如何使用Flannel網絡

Flannel打通Overlay網絡

當使用kubeadm來部署k8s,網絡組件(如flannel)是經過Add-ons的方式來部署的。咱們使用這個yml文件來部署的flannel網絡。
我截除了關鍵的一段內容(containers spec):

containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.7.1-amd64
command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr" ]
securityContext:
privileged: true
env:
- name: POD_NAME
valueFrom:
fieldRef:
 fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
 fieldPath: metadata.namespace
 volumeMounts:
- name: run
mountPath: /run
- name: flannel-cfg
mountPath: /etc/kube-flannel/
 - name: install-cni
image: quay.io/coreos/flannel:v0.7.1-amd64
 command: [ "/bin/sh", "-c", "set -e -x; cp -f /etc/kube-flannel/cni-conf.json /etc/cni/net.d/10-flannel.conf; while true; do sleep 3600; done" ]
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
 mountPath: /etc/kube-flannel/

經過分析該yaml文件能夠知道:該pod內有兩個container,分別爲install-cni和 kube-flannel。

  • install-cni

主要負責將config-map中適用於該flannel的CNI netconf配置拷貝到主機的CNI netconf 路徑下,從而使得K8S在建立pod的時候能夠遵守標準的CNI流程掛載網卡。

  • kube-flannel

主要啓動flanneld,該command中爲flanneld的啓動指定了兩個參數: –ip-masq, –kube-subnet-mgr。第一個參數–ip-masq表明須要爲其配置SNAT;第二個參數–kube-subnet-mgr表明其使用kube類型的subnet-manager。該類型有別於使用etcd的local-subnet-mgr類型,使用kube類型後,flannel上各Node的IP子網分配均基於K8S Node的spec.podCIDR屬性。能夠參考下圖的方式來查看(該示例中,k8s爲node-1節點分配的podCIDR爲:10.244.8.0/24):

#kubectl edit node node-1

apiVersion: v1
kind: Node
 ...
name: dev-1
resourceVersion: "2452057"
selfLink: /api/v1/nodesdev-1
uid: 31f6e4c3-57b6-11e7-a0a5-00163e122a49
spec:
 externalID: dev-1
podCIDR: 10.244.8.0/24

另外,flannel的subnet-manager經過監測K8S的node變化來維護了一張路由表,這張表裏面描述了要到達某個Pod子網須要先到達哪一個EndPoint。

CNI掛載容器到隧道端點

若是說flannel爲Pod打通了一張跨node的大網,那麼CNI就是將各個終端Pod掛載到這張大網上的安裝工人。

在剛部署好flannel網絡並未在該Node上啓動任何Pod時,經過ip link咱們只可以看到flannel.1這張網卡,卻沒法看到cni0。難道是flannel網絡運行異常嗎?咱們接下來就來分析flannel的CNI實現原理,就知道答案了。

經過傳統方式來部署flannel都須要經過腳原本修改dockerd的參數,從而使得經過docker建立的容器可以掛載到指定的網橋上。可是flannel的CNI實現並無採用這種方式。經過分析CNI代碼,

咱們能夠了解flannel CNI的流程:

  • 讀取netconf配置文件,並加載/run/flannel/subnet.env環境變量信息。
  • 基於加載的信息,生成適用於其delegate的ipam和CNI bridge的netconf文件;其中指定ipam使用host-local,CNI bridge type爲bridge。
  • 調用deletgate(CNI bridge type)對應的二進制文件來掛載容器到網橋上。

這裏的環境變量文件/run/flannel/subnet.env是由flanneld生成的,裏面包含了該主機所可以使用的IP子網網段,具體內容以下:

# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.8.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true

這些數據生成ipam的配置文件的依據,另外,flannel CNI插件的代碼中,默認指定delegate爲bridge:

if !hasKey(n.Delegate, "type") {
 n.Delegate["type"] = "bridge"
}

因此,當flannel CNI插件調用delegate,本質上就是調用bridge CNI插件來將容器掛載到網橋上。分析bridge CNI 插件的過程咱們能夠看到其指定了默認網橋名稱爲cni0:

const defaultBrName = "cni0"

func loadNetConf(bytes []byte) (*NetConf, error) {
n := &NetConf{
 BrName: defaultBrName,
 }
 ...
 return n, nil
}

所以,如今咱們能夠將整個流程連起來了:flannel CNI插件首先讀取netconf配置和subnet.env信息,生成適用於bridge CNI插件的netconf文件和ipam(host-local)配置,並設置其delegate爲bridge CNI插件。而後調用走bridge CNI插件掛載容器到bridge的流程。因爲各個Pod的IP地址分配是基於host-local的Ipam,所以整個流程徹底是分佈式的,不會對API-Server形成太大的負擔。

至此,基於kubeadm的flannel分析就大體結束了,但願對您有幫助!

相關文章
相關標籤/搜索