云原生環境網絡方案1 --- 容器網絡模型與K8S網絡模型

云原生環境網絡方案1 --- 容器網絡模型與K8S網絡模型

K8S系統將網絡方面的功能托管給了第三方插件來完成,本文將簡略描述其基本通訊原理以及常見的幾種網絡方案。

Docker網絡通訊模型

Docker容器的網絡設置有4種形式,去除None和共享Namespace之外,其實只有兩種網絡即:

  • 主機網絡

  • Bridge網絡

其中Bridge是Docker容器的默認網絡。

在任何安裝了Docker的宿主機環境上,我們都能發現系統中新增了一個名為Docker0的網橋設備。

$ brctl show
bridge name  bridge id          STP enabled  interfaces
docker0      8000.024204b14ad5  no           veth9d63d04 vethbf226b3

這個名為Docker0的網橋是默認用來給Docker容器通信用的。在容器創建過程中,默認會產生一對虛擬網口veth,一頭連在Docker0上,另外一頭連接在容器內的eth0上。如下圖:

k8s-Container-Network.png

我們查看一下這個eth0的ip地址

$ sudo docker ps
CONTAINER ID  IMAGE  COMMAND  CREATED      STATUS          PORTS               NAMES
157545493a1b nginx:latest "/docker-en.…"   26 minutes ago   Up 26 minutes   0.0.0.0:80->80/tcp        nginx_demo

$ sudo docker container inspect 157545493a1b
...
            "Gateway": "172.18.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.18.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:12:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "91397797f09b069b9472a638861e21e9c0e861c14d2374cec9184997b52a2ba1",
                    "EndpointID": "8e8230218df826a1005625a09398785833497d79af2c69b0b82db37eaa0798a2",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:03",
                    "DriverOpts": null
                }
            }

可以看到這個容器的eth0的IP地址被設置為了172.18.0.2,而網關被設置為了172.18.0.1。那這個網關的地址是誰的呢?

$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        inet6 fe80::42:4ff:feb1:4ad5  prefixlen 64  scopeid 0x20<link>
        ether 02:42:04:b1:4a:d5  txqueuelen 0  (Ethernet)
        RX packets 494147  bytes 23247538 (23.2 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 886037  bytes 1319084427 (1.3 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

在宿主機中使用ifconfig命令,我們可以看到一個名為docker0的設備其網絡地址為172.18.0.1,正是容器設置里的網關地址。在Linux環境中,可以為網橋配置網絡地址,其實質上是一個名為Docker0的虛擬網卡設備插在Docker0網橋上,做為一個可參與路由的節點:

$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.1.1      0.0.0.0         UG    0      0        0 ens160
172.17.1.0      0.0.0.0         255.255.255.0   U     0      0        0 ens160
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

如果此時,我再啟動另外一個容器,這個容器的eth0的地址為172.18.0.3,那這兩個容器中,相互是可以ping通的。那么他們之間的網絡拓撲如下圖:

k8s-Page-2.png

此時,數據包還是只能在宿主機內部傳輸,我們啟動的這個容器是一個nginx web服務器,從上面的容器信息輸出可以看到0.0.0.0:80->80/tcp,其實現上是通過NAT進行的,從剛才的輸出可以看到,宿主機的80端口被映射到了容器的80端口上。查看一下宿主機的NAT表,我們可以看到這個映射:

$ sudo iptables -L -n -t nat
...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination              
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.18.0.2           172.18.0.2           tcp dpt:80

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.18.0.2:80

可以看到,Docker網絡模型的設計,采用了私網地址+Linux 網橋的方法與外部外諾做解耦,流量進入宿主機時,使用DNAT方式映射端口,容器網絡內部出去則需要做SNAT借用宿主機的網絡地址。由于使用了大量的NAT映射,大規模網絡出現問題的情況下,定位是非常困難的。

另外一種使用主機網絡的方案,和直接跑一個程序在宿主機上是完全一致的,本文不做贅述,Docker的視角實際上只著眼于宿主機內部的網絡通訊,跨宿主機通訊的場景實際上并沒有考慮的。這樣的考量應當是對多宿主機組成的容器云進行調度和編排的方案需要考慮的,比如K8S。

K8S跨宿主機網絡通訊模型

上一節提到的是同一個宿主機內部容器間的通信,本節描述跨宿主機通訊的幾種方式。

目前,跨宿主機通訊在網絡層面一般有兩種即:

  • 基于隧道的宿主機間通訊
  • 基于路由的宿主機間通訊

這兩種方式又被稱為overlayer和underlayer,其區別在于容器網絡和宿主機網絡是否在同一層面。

基于隧道的宿主機通訊

其中基于隧道的宿主機間通訊可能有多種類型,目前最常見的是基于VxLAN的隧道,這也是虛擬化網絡的常規方案。以flannel的VxLAN方案為例。

k8s-宿主機間VxLAN.png

在每臺宿主機上,會有一個VxLAN的VTEP虛擬設備flannel.1,其負責與其他VTEP設備打通,構成2層VxLAN虛擬交換網絡。以上圖為例,當宿主機2加入到網絡中時,宿主機1上會有如下路由信息:


$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
...
172.18.1.0      172.18.1.0       255.255.255.0   UG    0      0        0 flannel.1

其中172.18.1.0是宿主機2的VTEP設備的網絡地址。宿主機1上所有發往該網段的網絡包會發往VTEP設備flannel.1,然后走VxLAN隧道發往宿主機2。

flannel的隧道方案除了VxLAN以外還有一種基于存UDP的早期方案,由于性能問題,目前已被廢棄。

基于路由的宿主機通訊

上述基于隧道的宿主機間通訊,由于多了兩次拆解包的過程,性能會有所下降。據有關數據表明,網絡傳輸效率下降約20%-30%。除了這種通訊方式之外,還有一種基于路由的跨宿主機通信方式。例如除了上節提到的基于VxLAN隧道的方案外,flannel還有一種基于host-gateway的3層路由方案。其原理比較簡單,即將各個宿主機網絡進行子網劃分,并在每臺宿主機上設置相同的路由,類似以下:

$ ip route
...
172.18.0.0/24 via 172.17.1.41 dev ens160
172.18.1.0/24 via 172.17.1.42 dev ens160

利用Linux的路由功能實現容器的跨宿主機通信。剩下的問題就是如何保證各個宿主機上的路由表一致了。不同的插件方案使用的解決方案是不同的。例如flannel使用了etcd來存儲同步路由信息,而Calico則使用了BGP來實現這一點。除此以外,Calico方案也不會在宿主機上建立任何網橋設備,這一點與flannel有很大區別。在Calico方案組veth-pair的另一端不會被插入到任何網橋設備中,而只是放在宿主機的網絡命名空間內。

172.18.2.2 dev cali3863f3 scope link

宿主機上會有類似以上的路由記錄,將相關數據包發送至虛擬設備cali3863f3上。

k8s-Calico.png

與flannel方案相比,由于沒了虛擬網橋連接同一宿主機內各個容器,Calico方案需要在宿主機的路由表中添加多得多的路由表項。

基于路由的宿主機通信要求各個宿主機在二層網絡層面是直連互通的,對底層網絡有一定的要求。

常見容器網絡插件

由于k8s將網絡這部分開放給社區,目前CNI這部分的插件較多,常見的有如下幾種:

  • Flannel,目前最普遍的實現,同時支持overlayer(UDP,VxLAN)和underlayer(Host-gw)的網絡后端實現。
  • Calico,基于BGP的underlayer方案,功能豐富,對底層網絡有一定要求。
  • Cilium,基于eBPF和XDP的高性能Overlayer方案
  • Kube-Route,采用BGP提供網絡直連,集成基于LVS的負載均衡能力
  • WeaveNet,采用UDP封裝實現的L2 Overlayer方案,支持用戶態(慢,可加密)和內核態(快,無加密)兩種實現

總結

宿主機內部的容器間網絡通訊有基于網橋的,基于宿主機網絡的。跨宿主機容器間網絡通訊有Overlayer和Underlayer兩種,區別在于容器間通訊是否和宿主機間通訊屬于同一層面。

現有普適性最強的方案是Flannel,同時具備Overlayer和Underlayer的方案,為了統一架構,宿主機內部通訊使用了Linux虛擬網橋方案。需要注意的是,Flannel方案不支持K8S的NetworkPolicy,需要其他CNI插件配合,比如Calico。

Calico方案是目前比較成熟的Underlayer方案,其采用了BGP來同步多宿主機的路由表。

本文討論的是網絡層的解決方案,著眼于從網絡層面聯通各個容器的網絡,至于訪問控制,熔斷,限流等內容是在其他組件比如Service Proxy,Service Mesh,API Gateway來實現的,不在本文討論范圍內。

最后,我們回顧一下K8S網絡模型的3原則:

  • 任意兩個容器(或者POD-共享網絡命名空間的一組容器)之間可以直接通訊,無需顯式NAT。
  • 宿主機與容器(POD)之間也是可以直接通訊,無需顯式NAT。
  • 容器(POD)看到自己的IP和其他人看到它的IP是一致的。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容

  • CNI CNI(Container Network Interface,容器網絡接口)是 Google 和 Cor...
    小夢嘮娛樂閱讀 492評論 0 0
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學已經沒多少時間了。班主任說已經安排了三個家長分享經驗。 放學鈴聲...
    飄雪兒5閱讀 7,538評論 16 22
  • 今天感恩節哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會,身份的轉變要...
    迷月閃星情閱讀 10,588評論 0 11
  • 可愛進取,孤獨成精。努力飛翔,天堂翱翔。戰爭美好,孤獨進取。膽大飛翔,成就輝煌。努力進取,遙望,和諧家園。可愛游走...
    趙原野閱讀 2,748評論 1 1
  • 在妖界我有個名頭叫胡百曉,無論是何事,只要找到胡百曉即可有解決的辦法。因為是只狐貍大家以訛傳訛叫我“傾城百曉”,...
    貓九0110閱讀 3,294評論 7 3