Kubernetes & Docker 容器網路終極之戰
與 Docker 預設的網路模型不同,Kubernetes 形成了一套自己的網路模型,該網路模型更加適應傳統的網路模式,應用能夠平滑的從非容器環境遷移到 Kubernetes 環境中。
自從 Docker 容器出現,容器的網路通訊一直是眾人關注的焦點,而容器的網路方案又可以分為兩大部分:
- 單主機的容器間通訊;
- 跨主機的容器間通訊。
一、單主機 Docker 網路通訊
利用 Net Namespace 可以為 Docker 容器建立隔離的網路環境,容器具有完全獨立的網路棧,與宿主機隔離。也可以使 Docker 容器共享主機或者其他容器的網路名稱空間。
我們在使用docker run
--network=
選項指定容器的網路模式,Docker 有以下 4 種網路模式:
- host 模式,使用
--network=host
指定,不支援多主機; - bridge 模式,使用
--network=bridge
指定,預設設定,不支援多主機; - container 模式,使用
--network=container:NAME_or_ID
指定,即joiner 容器
,不支援多主機; - none 模式,使用
--network=none
指定,不支援多主機。
1.1、host 模式
連線到 host 網路的容器共享 Docker host 的網路棧,容器的網路配置與 host 完全一樣。
我們先檢視一下主機的網路。
[[email protected] ~]# ifconfig docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:44:8d:48:70 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.203 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 fe80::2e0:70ff:fe92:4779 prefixlen 64 scopeid 0x20<link> ether 00:e0:70:92:47:79 txqueuelen 1000 (Ethernet) RX packets 46093 bytes 66816291 (63.7 MiB) RX errors 0 dropped 1 overruns 0 frame 0 TX packets 24071 bytes 1814769 (1.7 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 0 (Local Loopback) RX packets 170 bytes 107720 (105.1 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 170 bytes 107720 (105.1 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
然後建立 host 網路的容器,再檢視容器的網路資訊。
[[email protected] ~]# docker run -it --network=host busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
90e01955edcd: Pull complete
Digest: sha256:2a03a6059f21e150ae84b0973863609494aad70f0a80eaeb64bddd8d92465812
Status: Downloaded newer image for busybox:latest
/ # ifconfig
docker0 Link encap:Ethernet HWaddr 02:42:44:8D:48:70
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
enp1s0 Link encap:Ethernet HWaddr 00:E0:70:92:47:79
inet addr:192.168.1.203 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::2e0:70ff:fe92:4779/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:45850 errors:0 dropped:1 overruns:0 frame:0
TX packets:23921 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:66794758 (63.7 MiB) TX bytes:1783655 (1.7 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:170 errors:0 dropped:0 overruns:0 frame:0
TX packets:170 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:107720 (105.1 KiB) TX bytes:107720 (105.1 KiB)
在容器中可以看到 host 的所有網絡卡,並且連 hostname 也是 host 的,可以直接使用宿主機 IP 地址與外界通訊,無需額外進行 NAT 轉換。由於容器通訊時,不再需要通過 Linux Bridge 等方式轉發或者資料包的封裝,效能上有很大的優勢。
當然,Host 模式有利也有弊,主要包括以下缺點:
容器沒有隔離、獨立的網路棧:容器因與宿主機共用網路棧而爭搶網路資源,並且容器崩潰也可能導致主機崩潰,這再生產環境中是不允許發生的。
埠資源:Docker host 上已經使用的埠就不能再用了。
1.2 Bridge 模式
Bridge 模式是 Docker 預設的網路模式,也是開發者最常用的網路模式。在這種模式下,Docker 為容器建立獨立的網路棧,保證容器內的進行使用獨立的網路環境,實現容器之間,容器與宿主機之間的網路棧隔離。同時,通過宿主機上的 Docker0 網橋,容器可以與宿主機乃至外界進行網路通訊。
從上圖可以看出,容器是可以與宿主機以及外界的其他機器通訊的,同一宿主機上,容器之間都是橋接在 Docker0 這個網橋上,Docker0 作為虛擬交換機使容器間互相通訊。但是,由於宿主機的 IP 地址與容器 veth pair 的 IP 地址均不在同一個網段,故僅僅依靠 veth pair 和 NameSpace 的技術並不足以使宿主機以外的網路主動發現容器的存在。Docker 採用了埠繫結的方式(通過 iptables 的 NAT),將宿主機上的埠流量轉發到容器內的埠上,這樣一來,外界就可以與容器中的程序進行通訊。
1.3 Container 模式
Container 模式是一種特殊的網路模式。該模式下的容器使用其他容器的網路名稱空間,網路隔離性會處於 Bridge 模式與 Host 模式之間。也就是說,當容器與其他容器共享網路名稱空間時,這兩個容器間不存在網路隔離,但他們與宿主機機器其他容器又存在網路隔離。
Container 模式的容器可以通過 localhost 來與同一網路名稱空間下的其他容器通訊,傳輸效率高。這種模式節約了一定數量的網路資源,但並沒有改變容器與外界的通訊方式。在 Kubernetes 體系架構下引入 Pod 概念,Kubernetes 為 Pod 建立一個基礎設施容器,同一 Pod 下的其他容器都以 Container 模式共享這個基礎設施容器的網路名稱空間,相互之間以 localhost 訪問,構成一個統一的整體。
1.4、None 模式
與前幾種不同,None 模式的 Docker 容器擁有自己的 Network Namespace,但並不為 Docker 容器進行網路配置。也就是說,該 Docker 容器沒有網絡卡、IP、路由等資訊。需要使用者為 Docker容器新增網絡卡、配置 IP 等。