久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Kubernetes中如何進行網絡分析Flannel

176次閱讀
沒有評論

共計 6899 個字符,預計需要花費 18 分鐘才能閱讀完成。

這期內容當中丸趣 TV 小編將會給大家帶來有關 Kubernetes 中如何進行網絡分析 Flannel,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

Flannel 是 cereos 開源的 CNI 網絡插件,下圖 flannel 官網提供的一個數據包經過封包、傳輸以及拆包的示意圖,從這個圖片中可以看出兩臺機器的 docker0 分別處于不同的段:10.1.20.1/24 和 10.1.15.1/24,如果從 Web App Frontend1 pod(10.1.15.2)去連接另一臺主機上的 Backend Service2 pod(10.1.20.3),網絡包從宿主機 192.168.0.100 發往 192.168.0.200,內層容器的數據包被封裝到宿主機的 UDP 里面,并且在外層包裝了宿主機的 IP 和 mac 地址。這就是一個經典的 overlay 網絡,因為容器的 IP 是一個內部 IP,無法從跨宿主機通信,所以容器的網絡互通,需要承載到宿主機的網絡之上。

Kubernetes 中如何進行網絡分析 Flannel

flannel 支持多種網絡模式,常用的是 vxlan、UDP、hostgw、ipip 以及 gce 和阿里云等,vxlan 和 UDP 的區別是:vxlan 是內核封包,而 UDP 是 flanneld 用戶態程序封包,所以 UDP 的方式性能會稍差;hostgw 模式是一種主機網關模式,容器到另外一個主機上容器的網關設置成所在主機的網卡地址,這個和 calico 非常相似,只不過 calico 是通過 BGP 聲明,而 hostgw 是通過中心的 etcd 分發,所以 hostgw 是直連模式,不需要通過 overlay 封包和拆包,性能比較高,但 hostgw 模式最大的缺點是必須是在一個二層網絡中,畢竟下一跳的路由需要在鄰居表中,否則無法通行。

在實際的生產環境中,最常用的還是 vxlan 模式,我們先看工作原理,然后通過源碼解析實現過程。

安裝的過程非常簡單,主要分為兩步:

第一步安裝 flannel

yum install flannel 或者通過 kubernetes 的 daemonset 方式啟動, 配置 flannel 用的 etcd 地址

第二步配置集群網絡

curl -L http://etcdurl:2379/v2/keys/flannel/network/config -XPUT -d value= {\ Network\ :\ 172.16.0.0/16\ ,\ SubnetLen\ :24,\ Backend\ :{\ Type\ :\ vxlan\ ,\ VNI\ :1}}

然后啟動每個節點的 flanned 程序。

一、工作原理

1、容器的地址如何分配

Docker 容器啟動時通過 docker0 分配 IP 地址,flannel 為每個機器分配一個 IP 段,配置在 docker0 上,容器啟動后就在本段內選擇一個未占用的 IP,那么 flannel 如何修改 docker0 網段呢?

先看一下 flannel 的啟動文件 /usr/lib/systemd/system/flanneld.service

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/flanneld
ExecStart=/usr/bin/flanneld-start $FLANNEL_OPTIONS
ExecStartPost=/opt/flannel/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker

文件里面指定了 flannel 環境變量和啟動腳本和啟動后執行腳本 ExecStartPost 設置的 mk-docker-opts.sh,這個腳本的作用是生成 /run/flannel/docker,文件內容如下:

DOCKER_OPT_BIP= --bip=10.251.81.1/24 
DOCKER_OPT_IPMASQ= --ip-masq=false 
DOCKER_OPT_MTU= --mtu=1450 
DOCKER_NETWORK_OPTIONS=  --bip=10.251.81.1/24 --ip-masq=false --mtu=1450

而這個文件又被 docker 啟動文件 /usr/lib/systemd/system/docker.service 所關聯,

[Service]
Type=notify
NotifyAccess=all
EnvironmentFile=-/run/flannel/docker
EnvironmentFile=-/etc/sysconfig/docker

這樣便可以設置 docker0 的網橋了。

在開發環境中,有三臺機器,分別分配了如下網段:

host-139.245 10.254.44.1/24

host-139.246 10.254.60.1/24

host-139.247 10.254.50.1/24

2、容器如何通信

上面介紹了為每個容器分配 IP,那么不同主機上的容器如何通信呢,我們用最常見的 vxlan 舉例,這里有三個關鍵點,一個路由,一個 arp,一個 FDB。我們按照容器發包的過程,逐一分析上面三個元素的作用,首先容器出來的數據包會經過 docker0,那么下面是直接從主機網絡出去,還是通過 vxlan 封包轉發呢?這是每個機器上面路由設定的。

 #ip route show dev flannel.1
10.254.50.0/24 via 10.254.50.0 onlink
10.254.60.0/24 via 10.254.60.0 onlink

可以看到每個主機上面都有到另外兩臺機器的路由,這個路由是 onlink 路由,onlink 參數表明強制此網關是“在鏈路上”的(雖然并沒有鏈路層路由),否則 linux 上面是沒法添加不同網段的路由。這樣數據包就能知道,如果是容器直接的訪問則交給 flannel.1 設備處理。

flannel.1 這個虛擬網絡設備將會對數據封包,但下面一個問題又來了,這個網關的 mac 地址是多少呢?因為這個網關是通過 onlink 設置的,flannel 會下發這個 mac 地址,查看一下 arp 表

# ip neig show dev flannel.1
10.254.50.0 lladdr ba:10:0e:7b:74:89 PERMANENT
10.254.60.0 lladdr 92:f3:c8:b2:6e:f0 PERMANENT

可以看到這個網關對應的 mac 地址,這樣內層的數據包就封裝好了

還是最后一個問題,外出的數據包的目的 IP 是多少呢?換句話說,這個封裝后的數據包應該發往那一臺機器呢?難不成每個數據包都廣播。vxlan 默認實現第一次確實是通過廣播的方式,但 flannel 再次采用一種 hack 方式直接下發了這個轉發表 FDB

# bridge fdb show dev flannel.1
92:f3:c8:b2:6e:f0 dst 10.100.139.246 self permanent
ba:10:0e:7b:74:89 dst 10.100.139.247 self permanent

這樣對應 mac 地址轉發目標 IP 便可以獲取到了。

這里還有個地方需要注意,無論是 arp 表還是 FDB 表都是 permanent,它表明寫記錄是手動維護的,傳統的 arp 獲取鄰居的方式是通過廣播獲取,如果收到對端的 arp 相應則會標記對端為 reachable,在超過 reachable 設定時間后,如果發現對端失效會標記為 stale,之后會轉入的 delay 以及 probe 進入探測的狀態,如果探測失敗會標記為 Failed 狀態。之所以介紹 arp 的基礎內容,是因為老版本的 flannel 并非使用本文上面的方式,而是采用一種臨時的 arp 方案,此時下發的 arp 表示 reachable 狀態,這就意味著,如果在 flannel 宕機超過 reachable 超時時間的話,那么這臺機器上面的容器的網絡將會中斷,我們簡單回顧試一下之前 (0.7.x) 版本的做法,容器為了為了能夠獲取到對端 arp 地址,內核會首先發送 arp 征詢,如果嘗試  

/proc/sys/net/ipv4/neigh/$NIC/ucast_solicit

此時后會向用戶空間發送 arp 征詢

/proc/sys/net/ipv4/neigh/$NIC/app_solicit

之前版本的 flannel 正是利用這個特性,設定

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

從而 flanneld 便可以獲取到內核發送到用戶空間的 L3MISS, 并且配合 etcd 返回這個 IP 地址對應的 mac 地址,設置為 reachable。從分析可以看出,如果 flanneld 程序如果退出后,容器之間的通信將會中斷,這里需要注意。Flannel 的啟動流程如下圖所示:

Kubernetes 中如何進行網絡分析 Flannel

Flannel 啟動執行 newSubnetManager,通過他創建后臺數據存儲,當前有支持兩種后端,默認是 etcd 存儲,如果 flannel 啟動指定“kube-subnet-mgr”參數則使用 kubernetes 的接口存儲數據。

具體代碼如下:

func newSubnetManager() (subnet.Manager, error) {
 if opts.kubeSubnetMgr { return kube.NewSubnetManager(opts.kubeApiUrl, opts.kubeConfigFile)
 }
 
 cfg :=  etcdv2.EtcdConfig{ Endpoints: strings.Split(opts.etcdEndpoints,  ,),
 Keyfile: opts.etcdKeyfile,
 Certfile: opts.etcdCertfile,
 CAFile: opts.etcdCAFile,
 Prefix: opts.etcdPrefix,
 Username: opts.etcdUsername,
 Password: opts.etcdPassword,
 }
 
 // Attempt to renew the lease for the subnet specified in the subnetFile
 prevSubnet := ReadCIDRFromSubnetFile(opts.subnetFile,  FLANNEL_SUBNET)
 
 return etcdv2.NewLocalManager(cfg, prevSubnet)
 }

通過 SubnetManager,結合上面介紹部署的時候配置的 etcd 的數據,可以獲得網絡配置信息,主要指 backend 和網段信息,如果是 vxlan,通過 NewManager 創建對應的網絡管理器,這里用到簡單工程模式,首先每種網絡模式管理器都會通過 init 初始化注冊,

如 vxlan

func init() { backend.Register( vxlan , New)

如果是 udp

 func init() { backend.Register( udp , New)
 }

其它也是類似,將構建方法都注冊到一個 map 里面,從而根據 etcd 配置的網絡模式,設定啟用對應的網絡管理器。

3、注冊網絡

RegisterNetwork,首先會創建 flannel.vxlanID 的網卡,默認 vxlanID 是 1. 然后就是向 etcd 注冊租約并且獲取相應的網段信息,這樣有個細節,老版的 flannel 每次啟動都是去獲取新的網段,新版的 flannel 會遍歷 etcd 里面已經注冊的 etcd 信息,從而獲取之前分配的網段,繼續使用。

最后通過 WriteSubnetFile 寫本地子網文件,

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

通過這個文件設定 docker 的網絡。細心的讀者可能發現這里的 MTU 并不是以太網規定的 1500,這是因為外層的 vxlan 封包還要占據 50 Byte。

當然 flannel 啟動后還需要持續的 watch etcd 里面的數據,這是當有新的 flannel 節點加入,或者變更的時候,其他 flannel 節點能夠動態更新的那三張表。主要的處理方法都在 handleSubnetEvents 里面

 func (nw *network) handleSubnetEvents(batch []subnet.Event) {
 . . .
 
 switch event.Type {// 如果是有新的網段加入(新的主機加入) case subnet.EventAdded:
 . . .// 更新路由表
if err := netlink.RouteReplace(directRoute); err != nil { log.Errorf( Error adding route to %v via %v: %v , sn, attrs.PublicIP, err)
 continue
 } 
// 添加 arp 表
log.V(2).Infof(adding subnet: %s PublicIP: %s VtepMAC: %s , sn, attrs.PublicIP, net.HardwareAddr(vxlanAttrs.VtepMAC))
 if err := nw.dev.AddARP(neighbor{IP: sn.IP, MAC: net.HardwareAddr(vxlanAttrs.VtepMAC)}); err != nil { log.Error( AddARP failed:  , err)
 continue
 }
 // 添加 FDB 表
 if err := nw.dev.AddFDB(neighbor{IP: attrs.PublicIP, MAC: net.HardwareAddr(vxlanAttrs.VtepMAC)}); err != nil { log.Error( AddFDB failed:  , err)
 
 if err := nw.dev.DelARP(neighbor{IP: event.Lease.Subnet.IP, MAC: net.HardwareAddr(vxlanAttrs.VtepMAC)}); err != nil { log.Error( DelARP failed:  , err)
 }
 
 continue
 }// 如果是刪除實踐
 case subnet.EventRemoved:
// 刪除路由
 if err := netlink.RouteDel(directRoute); err != nil { log.Errorf( Error deleting route to %v via %v: %v , sn, attrs.PublicIP, err)
 
 } else { log.V(2).Infof(removing subnet: %s PublicIP: %s VtepMAC: %s , sn, attrs.PublicIP, net.HardwareAddr(vxlanAttrs.VtepMAC))
 
 // 刪除 arp if err := nw.dev.DelARP(neighbor{IP: sn.IP, MAC: net.HardwareAddr(vxlanAttrs.VtepMAC)}); err != nil { log.Error( DelARP failed:  , err)
 }
 // 刪除 FDB
 if err := nw.dev.DelFDB(neighbor{IP: attrs.PublicIP, MAC: net.HardwareAddr(vxlanAttrs.VtepMAC)}); err != nil { log.Error( DelFDB failed:  , err)
 }
 
 if err := netlink.RouteDel(vxlanRoute); err != nil { log.Errorf( failed to delete vxlanRoute (%s -  %s): %v , vxlanRoute.Dst, vxlanRoute.Gw, err)
 }
 }
 default:
 log.Error(internal error: unknown event type:  , int(event.Type))
 }
 }
 }

這樣 flannel 里面任何主機的添加和刪除都可以被其它節點所感知到,從而更新本地內核轉發表。

上述就是丸趣 TV 小編為大家分享的 Kubernetes 中如何進行網絡分析 Flannel 了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注丸趣 TV 行業資訊頻道。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計6899字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 盖州市| 绥化市| 涞水县| 舟曲县| 镇康县| 西盟| 昌乐县| 南江县| 陇西县| 石棉县| 江安县| 滦南县| 琼结县| 天峨县| 健康| 宁乡县| 墨竹工卡县| 汉阴县| 赣榆县| 望城县| 隆林| 长阳| 兴业县| 邓州市| 洪泽县| 红桥区| 乌苏市| 通山县| 清原| 富裕县| 芒康县| 枝江市| 白河县| 富裕县| 郯城县| 扎鲁特旗| 金川县| 溆浦县| 岳池县| 昌图县| 永登县|