您好,登錄后才能下訂單哦!
與 Docker 默認的網絡模型不同,Kubernetes 形成了一套自己的網絡模型,該網絡模型更加適應傳統的網絡模式,應用能夠平滑的從非容器環境遷移到 Kubernetes 環境中。
自從 Docker 容器出現,容器的網絡通信一直是眾人關注的焦點,而容器的網絡方案又可以分為兩大部分:
利用 Net Namespace 可以為 Docker 容器創建隔離的網絡環境,容器具有完全獨立的網絡棧,與宿主機隔離。也可以使 Docker 容器共享主機或者其他容器的網絡命名空間。
我們在使用docker run
創建 Docker 容器時,可以使用--network=
選項指定容器的網絡模式,Docker 有以下 4 種網絡模式:
--network=host
指定,不支持多主機;--network=bridge
指定,默認設置,不支持多主機;--network=container:NAME_or_ID
指定,即joiner 容器
,不支持多主機;--network=none
指定,不支持多主機。連接到 host 網絡的容器共享 Docker host 的網絡棧,容器的網絡配置與 host 完全一樣。
我們先查看一下主機的網絡。
[root@datanode03 ~]# 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 網絡的容器,再查看容器的網絡信息。
[root@datanode03 ~]# 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 模式有利也有弊,主要包括以下缺點:
Bridge 模式是 Docker 默認的網絡模式,也是開發者最常用的網絡模式。在這種模式下,Docker 為容器創建獨立的網絡棧,保證容器內的進行使用獨立的網絡環境,實現容器之間,容器與宿主機之間的網絡棧隔離。同時,通過宿主機上的 Docker0 網橋,容器可以與宿主機乃至外界進行網絡通信。
從上圖可以看出,容器是可以與宿主機以及外界的其他機器通信的,同一宿主機上,容器之間都是橋接在 Docker0 這個網橋上,Docker0 作為虛擬交換機使容器間互相通信。但是,由于宿主機的 IP 地址與容器 veth pair 的 IP 地址均不在同一個網段,故僅僅依靠 veth pair 和 NameSpace 的技術并不足以使宿主機以外的網絡主動發現容器的存在。Docker 采用了端口綁定的方式(通過 iptables 的 NAT),將宿主機上的端口流量轉發到容器內的端口上,這樣一來,外界就可以與容器中的進程進行通信。
Container 模式是一種特殊的網絡模式。該模式下的容器使用其他容器的網絡命名空間,網絡隔離性會處于 Bridge 模式與 Host 模式之間。也就是說,當容器與其他容器共享網絡命名空間時,這兩個容器間不存在網絡隔離,但他們與宿主機機器其他容器又存在網絡隔離。
Container 模式的容器可以通過 localhost 來與同一網絡命名空間下的其他容器通信,傳輸效率高。這種模式節約了一定數量的網絡資源,但并沒有改變容器與外界的通信方式。在 Kubernetes 體系架構下引入 Pod 概念,Kubernetes 為 Pod 創建一個基礎設施容器,同一 Pod 下的其他容器都以 Container 模式共享這個基礎設施容器的網絡命名空間,相互之間以 localhost 訪問,構成一個統一的整體。
與前幾種不同,None 模式的 Docker 容器擁有自己的 Network Namespace,但并不為 Docker 容器進行網絡配置。也就是說,該 Docker 容器沒有網卡、IP、路由等信息。需要用戶為 Docker容器添加網卡、配置 IP 等。
常見的跨主機通信方案主要有以下幾種:
主機 IP + 端口
的方式訪問容器中的服務。顯然,這種方式僅能支持網絡棧的 4 層及以上的應用,并且容器與宿主機緊耦合,很難靈活地處理問題,可擴展性不佳;容器網絡發展到現在,形成了兩大陣營:
CNM 和 CNI 是網絡規范或者網絡體系,并不是網絡實現,因此不關心容器的網絡實現方式,CNM 和 CNI 關心的只是網絡管理。
但從網絡實現角度,又可分為:
隧道方案:隧道方案在 IaaS 層的網絡中應用也比較多,它的主要缺點是隨著節點規模的增長復雜度會提升,而且出了網絡問題后跟蹤起來比較麻煩,大規模集群情況下這是需要考慮的一個問題。
路由方案:一般是基于3層或者2層實現網絡隔離和跨主機容器互通的,出了問題也很容易排查。
Calico:基于 BGP 協議的路由方案,支持很細致的 ACL 控制(Nerwork Policy),對混合云親和度比較高。
Macvlan:從邏輯和 Kernel 層來看,是隔離性和性能最優的方案。基于二層隔離,所以需要二層路由器支持,大多數云服務商不支持,所以混合云上比較難以實現。
Kubernetes 采用的是基于扁平地址空間的網絡模型,集群中的每個 Pod 都有自己的 IP 地址,Pod 之間不需要配置 NAT 就能直接通信。另外,同一個 Pod 中的容器共享 Pod 的 IP,能夠通過 localhost 通信。
這種網絡模型對應用開發者和管理員相當友好,應用可以非常方便地從傳統網絡遷移到 Kubernetes。每個 Pod 可被看作是一個個獨立的系統,而 Pod 中的容器則可被看做同一系統中的不同進程。
Pod 內容器之間的通信
當 Pod 被調度到某個節點,Pod 中的所有容器都在這個節點上運行,這些容器共享相同的本地文件系統、IPC 和網絡命名空間。
不同 Pod 之間不存在端口沖突的問題,因為每個 Pod 都有自己的 IP 地址。當某個容器使用 localhost 時,意味著使用的是容器所屬 Pod 的地址空間。
比如 Pod A 有兩個容器 container-A1 和 container-A2,container-A1 在端口 1234 上監聽,當 container-A2 連接到 localhost:1234,實際上就是在訪問 container-A1。這不會與同一個節點上的 Pod B 沖突,即使 Pod B 中的容器 container-B1 也在監聽 1234 端口。
Pod 之間的通信
Pod 的 IP 是集群可見的,即集群中的任何其他 Pod 和節點都可以通過 IP 直接與 Pod 通信,這種通信不需要借助任何的網絡地址轉換、隧道或代理技術。Pod 內部和外部使用的是同一個 IP,這也意味著標準的命名服務和發現機制,比如 DNS 可以直接使用。
Pod 與 Service 的通信
Pod 間可以直接通過 IP 地址通信,但前提是 Pod 得知道對方的 IP。在 Kubernetes 集群中, Pod 可能會頻繁的銷毀和創建,也就是說 Pod 的 IP 不是固定的。為了解決這個問題,Service 提供了訪問 Pod 的抽象層。無論后端的 Pod 如何變化,Service 都作為穩定的前端對外提供服務。同時,Service 還提供了高可用和負載均衡功能,Service 負責將請求轉發給正確的 Pod。
外部訪問
無論是 Pod 的 IP 還是 Service 的 Cluster IP,它們只能在 Kubernetes 集群中可見,對集群之外的世界,這些 IP 都是私有的。
Kubernetes 安裝方式。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml
flannel 是 CoreOS 開發的容器網絡解決方案。flannel 為每個 host 分配一個 subnet,容器從此 subnet 中分配 IP,這些 IP 可以在 host 間路由,容器間無需 NAT 和 port mapping 就可以跨主機通信。
每個 subnet 都是從一個更大的 IP 池中劃分的,flannel 會在每個主機上運行一個叫 flanneld 的 agent,其職責就是從池子中分配 subnet。為了在各個主機間共享信息,flannel 用 etcd(與 consul 類似的 key-value 分布式數據庫)存放網絡配置、已分配的 subnet、host 的 IP 等信息。
數據包如何在主機間轉發是由 backend 實現的。flannel 提供了多種 backend,有 UDP、vxlan、host-gw、aws-vpc、gce 和 alloc 路由,最常用的有 vxlan 和 host-gw。
Flannel 實質上是一種疊加網絡(Overlay Network),也就是將 TCP 數據包裝在另一種網絡包里面進行路由轉發和通信。
我們使用 kubectl apply 安裝的 flannel 默認的 backend 為 vxlan,host-gw 是 flannel 的另一個 backend,我們將前面的 vxlan backend 切換成 host-gw。
與 vxlan 不同,host-gw 不會封裝數據包,而是在主機的路由表中創建到其他主機 subnet 的路由條目,從而實現容器跨主機通信。要使用 host-gw 首先修改 flannel 的配置 flannel-config.json
:
kubectl edit cm kube-flannel-cfg -o yaml -n kube-system
找到如下字段進行修改。
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "host-gw"
}
}
host-gw 把每個主機都配置成網關,主機知道其他主機的 subnet 和轉發地址,由于 vxlan 需要對數據包進行額外的打包和拆包,性能會比 vxlan 強一些。
Kubernetes 安裝方式。
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
Calico 把每個操作系統的協議棧當做一個路由器,然后認為所有的容器是連在這個路由器上的網絡終端,在路由器之間運行標準的路由協議——BGP,然后讓他們自己去學習這個網絡拓撲該如何轉發,所以Calico 是一個純三層的虛擬網絡方案,Calico 為每個容器分配一個 IP,每個 host 都是 router,把不同 host 的容器連接起來。與 VxLAN 不同的是,Calico 不對數據包做額外封裝,不需要 NAT 和端口映射,擴展性和性能都很好。
與其他容器網絡方案相比,Calico 還有一大優勢:network policy。用戶可以動態定義 ACL 規則,控制進出容器的數據包,實現業務需求。
Network Policy
Network Policy 是 Kubernetes 的一種資源。Network Policy 通過 Label 選擇 Pod,并指定其他 Pod 或外界如何與這些 Pod 通信。
默認情況下,所有 Pod 是非隔離的,即任何來源的網絡流量都能夠訪問 Pod,沒有任何限制。當為 Pod 定義了 Network Policy,只有 Policy 允許的流量才能訪問 Pod。
不過,不是所有的 Kubernetes 網絡方案都支持 Network Policy。比如 Flannel 就不支持,Calico 是支持的。我們接下來將用 Canal 來演示 Network Policy。Canal 這個開源項目很有意思,它用 Flannel 實現 Kubernetes 集群網絡,同時又用 Calico 實現 Network Policy。
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/canal/rbac.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/canal/canal.yaml
請查看我的博文 https://blog.51cto.com/wzlinux/2112061 。
docker network create -d macvlan --subnet=172.16.86.0/24 --gateway=172.16.86.1 -o parent=enp0s9 mac_net1
macvlan 本身是 linxu kernel 模塊,其功能是允許在同一個物理網卡上配置多個 MAC 地址,即多個 interface,每個 interface 可以配置自己的 IP。macvlan 本質上是一種網卡虛擬化技術,Docker 用 macvlan 實現容器網絡就不奇怪了。
macvlan 的最大優點是性能極好,相比其他實現,macvlan 不需要創建 Linux bridge,而是直接通過以太 interface 連接到物理網絡。
macvlan 會獨占主機的網卡,也就是說一個網卡只能創建一個 macvlan 網絡:
docker network create -d macvlan -o parent=enp0s9 mac_net2
好在 macvlan 不僅可以連接到 interface(如 enp0s9),也可以連接到 sub-interface(如 enp0s9.xxx)。
VLAN 是現代網絡常用的網絡虛擬化技術,它可以將物理的二層網絡劃分成多達 4094 個邏輯網絡,這些邏輯網絡在二層上是隔離的,每個邏輯網絡(即 VLAN)由 VLAN ID 區分,VLAN ID 的取值為 1-4094。
Linux 的網卡也能支持 VLAN(apt-get install vlan),同一個 interface 可以收發多個 VLAN 的數據包,不過前提是要創建 VLAN 的 sub-interface。
比如希望 enp0s9 同時支持 VLAN10 和 VLAN20,則需創建 sub-interface enp0s9.10 和 enp0s9.20。
在交換機上,如果某個 port 只能收發單個 VLAN 的數據,該 port 為 Access 模式,如果支持多 VLAN,則為 Trunk 模式,所以接下來實驗的前提是:
enp0s9 要接在交換機的 trunk 口上。不過我們用的是 VirtualBox 虛擬機,則不需要額外配置了。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。