云原生環(huán)境網(wǎng)絡(luò)方案1 --- 容器網(wǎng)絡(luò)模型與K8S網(wǎng)絡(luò)模型

云原生環(huán)境網(wǎng)絡(luò)方案1 --- 容器網(wǎng)絡(luò)模型與K8S網(wǎng)絡(luò)模型

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

Docker網(wǎng)絡(luò)通訊模型

Docker容器的網(wǎng)絡(luò)設(shè)置有4種形式,去除None和共享Namespace之外,其實只有兩種網(wǎng)絡(luò)即:

  • 主機(jī)網(wǎng)絡(luò)

  • Bridge網(wǎng)絡(luò)

其中Bridge是Docker容器的默認(rèn)網(wǎng)絡(luò)。

在任何安裝了Docker的宿主機(jī)環(huán)境上,我們都能發(fā)現(xiàn)系統(tǒng)中新增了一個名為Docker0的網(wǎng)橋設(shè)備。

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

這個名為Docker0的網(wǎng)橋是默認(rèn)用來給Docker容器通信用的。在容器創(chuàng)建過程中,默認(rèn)會產(chǎn)生一對虛擬網(wǎng)口veth,一頭連在Docker0上,另外一頭連接在容器內(nèi)的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地址被設(shè)置為了172.18.0.2,而網(wǎng)關(guān)被設(shè)置為了172.18.0.1。那這個網(wǎng)關(guān)的地址是誰的呢?

$ 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

在宿主機(jī)中使用ifconfig命令,我們可以看到一個名為docker0的設(shè)備其網(wǎng)絡(luò)地址為172.18.0.1,正是容器設(shè)置里的網(wǎng)關(guān)地址。在Linux環(huán)境中,可以為網(wǎng)橋配置網(wǎng)絡(luò)地址,其實質(zhì)上是一個名為Docker0的虛擬網(wǎng)卡設(shè)備插在Docker0網(wǎng)橋上,做為一個可參與路由的節(jié)點:

$ 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通的。那么他們之間的網(wǎng)絡(luò)拓?fù)淙缦聢D:

k8s-Page-2.png

此時,數(shù)據(jù)包還是只能在宿主機(jī)內(nèi)部傳輸,我們啟動的這個容器是一個nginx web服務(wù)器,從上面的容器信息輸出可以看到0.0.0.0:80->80/tcp,其實現(xiàn)上是通過NAT進(jìn)行的,從剛才的輸出可以看到,宿主機(jī)的80端口被映射到了容器的80端口上。查看一下宿主機(jī)的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網(wǎng)絡(luò)模型的設(shè)計,采用了私網(wǎng)地址+Linux 網(wǎng)橋的方法與外部外諾做解耦,流量進(jìn)入宿主機(jī)時,使用DNAT方式映射端口,容器網(wǎng)絡(luò)內(nèi)部出去則需要做SNAT借用宿主機(jī)的網(wǎng)絡(luò)地址。由于使用了大量的NAT映射,大規(guī)模網(wǎng)絡(luò)出現(xiàn)問題的情況下,定位是非常困難的。

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

K8S跨宿主機(jī)網(wǎng)絡(luò)通訊模型

上一節(jié)提到的是同一個宿主機(jī)內(nèi)部容器間的通信,本節(jié)描述跨宿主機(jī)通訊的幾種方式。

目前,跨宿主機(jī)通訊在網(wǎng)絡(luò)層面一般有兩種即:

  • 基于隧道的宿主機(jī)間通訊
  • 基于路由的宿主機(jī)間通訊

這兩種方式又被稱為overlayer和underlayer,其區(qū)別在于容器網(wǎng)絡(luò)和宿主機(jī)網(wǎng)絡(luò)是否在同一層面。

基于隧道的宿主機(jī)通訊

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

k8s-宿主機(jī)間VxLAN.png

在每臺宿主機(jī)上,會有一個VxLAN的VTEP虛擬設(shè)備flannel.1,其負(fù)責(zé)與其他VTEP設(shè)備打通,構(gòu)成2層VxLAN虛擬交換網(wǎng)絡(luò)。以上圖為例,當(dāng)宿主機(jī)2加入到網(wǎng)絡(luò)中時,宿主機(jī)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是宿主機(jī)2的VTEP設(shè)備的網(wǎng)絡(luò)地址。宿主機(jī)1上所有發(fā)往該網(wǎng)段的網(wǎng)絡(luò)包會發(fā)往VTEP設(shè)備flannel.1,然后走VxLAN隧道發(fā)往宿主機(jī)2。

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

基于路由的宿主機(jī)通訊

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

$ 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的路由功能實現(xiàn)容器的跨宿主機(jī)通信。剩下的問題就是如何保證各個宿主機(jī)上的路由表一致了。不同的插件方案使用的解決方案是不同的。例如flannel使用了etcd來存儲同步路由信息,而Calico則使用了BGP來實現(xiàn)這一點。除此以外,Calico方案也不會在宿主機(jī)上建立任何網(wǎng)橋設(shè)備,這一點與flannel有很大區(qū)別。在Calico方案組veth-pair的另一端不會被插入到任何網(wǎng)橋設(shè)備中,而只是放在宿主機(jī)的網(wǎng)絡(luò)命名空間內(nèi)。

172.18.2.2 dev cali3863f3 scope link

宿主機(jī)上會有類似以上的路由記錄,將相關(guān)數(shù)據(jù)包發(fā)送至虛擬設(shè)備cali3863f3上。

k8s-Calico.png

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

基于路由的宿主機(jī)通信要求各個宿主機(jī)在二層網(wǎng)絡(luò)層面是直連互通的,對底層網(wǎng)絡(luò)有一定的要求。

常見容器網(wǎng)絡(luò)插件

由于k8s將網(wǎng)絡(luò)這部分開放給社區(qū),目前CNI這部分的插件較多,常見的有如下幾種:

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

總結(jié)

宿主機(jī)內(nèi)部的容器間網(wǎng)絡(luò)通訊有基于網(wǎng)橋的,基于宿主機(jī)網(wǎng)絡(luò)的??缢拗鳈C(jī)容器間網(wǎng)絡(luò)通訊有Overlayer和Underlayer兩種,區(qū)別在于容器間通訊是否和宿主機(jī)間通訊屬于同一層面。

現(xiàn)有普適性最強(qiáng)的方案是Flannel,同時具備Overlayer和Underlayer的方案,為了統(tǒng)一架構(gòu),宿主機(jī)內(nèi)部通訊使用了Linux虛擬網(wǎng)橋方案。需要注意的是,F(xiàn)lannel方案不支持K8S的NetworkPolicy,需要其他CNI插件配合,比如Calico。

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

本文討論的是網(wǎng)絡(luò)層的解決方案,著眼于從網(wǎng)絡(luò)層面聯(lián)通各個容器的網(wǎng)絡(luò),至于訪問控制,熔斷,限流等內(nèi)容是在其他組件比如Service Proxy,Service Mesh,API Gateway來實現(xiàn)的,不在本文討論范圍內(nèi)。

最后,我們回顧一下K8S網(wǎng)絡(luò)模型的3原則:

  • 任意兩個容器(或者POD-共享網(wǎng)絡(luò)命名空間的一組容器)之間可以直接通訊,無需顯式NAT。
  • 宿主機(jī)與容器(POD)之間也是可以直接通訊,無需顯式NAT。
  • 容器(POD)看到自己的IP和其他人看到它的IP是一致的。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容