Kubernetes & Docker 容器網絡終極之戰(十四)

與 Docker 默認的網絡模型不同,Kubernetes 形成了一套自己的網絡模型,該網絡模型更加適應傳統的網絡模式,應用能夠平滑的從非容器環境遷移到 Kubernetes 環境中。

自從 Docker 容器出現,容器的網絡通信一直是衆人關注的焦點,而容器的網絡方案又可以分爲兩大部分:

  • 單主機的容器間通信;
  • 跨主機的容器間通信。

一、單主機 Docker 網絡通信

利用 Net Namespace 可以爲 Docker 容器創建隔離的網絡環境,容器具有完全獨立的網絡棧,與宿主機隔離。也可以使 Docker 容器共享主機或者其他容器的網絡命名空間。

我們在使用docker run創建 Docker 容器時,可以使用--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 完全一樣。

我們先查看一下主機的網絡。

[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 等方式轉發或者數據包的封裝,性能上有很大的優勢。

Kubernetes & Docker 容器網絡終極之戰(十四)

當然,Host 模式有利也有弊,主要包括以下缺點:

  • 容器沒有隔離、獨立的網絡棧:容器因與宿主機共用網絡棧而爭搶網絡資源,並且容器崩潰也可能導致主機崩潰,這再生產環境中是不允許發生的。
  • 端口資源:Docker host 上已經使用的端口就不能再用了。

1.2 Bridge 模式

Bridge 模式是 Docker 默認的網絡模式,也是開發者最常用的網絡模式。在這種模式下,Docker 爲容器創建獨立的網絡棧,保證容器內的進行使用獨立的網絡環境,實現容器之間,容器與宿主機之間的網絡棧隔離。同時,通過宿主機上的 Docker0 網橋,容器可以與宿主機乃至外界進行網絡通信。

Kubernetes & Docker 容器網絡終極之戰(十四)

從上圖可以看出,容器是可以與宿主機以及外界的其他機器通信的,同一宿主機上,容器之間都是橋接在 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 訪問,構成一個統一的整體。

Kubernetes & Docker 容器網絡終極之戰(十四)

1.4、None 模式

與前幾種不同,None 模式的 Docker 容器擁有自己的 Network Namespace,但並不爲 Docker 容器進行網絡配置。也就是說,該 Docker 容器沒有網卡、IP、路由等信息。需要用戶爲 Docker容器添加網卡、配置 IP 等。

Kubernetes & Docker 容器網絡終極之戰(十四)

二、跨主機 Docker 網絡通信分類

2.1 通信方案

常見的跨主機通信方案主要有以下幾種:

  • Host 模式:容器直接使用宿主機的網絡,這樣天生就可以支持跨主機主機通信。這種方式雖然可以解決跨主機通信問題,但應用場景很有限,容易出現端口衝突,也無法做到隔離網絡環境,一個容器崩潰很可能引起整個宿主機的崩潰;
  • 端口模式:通過綁定容器端口到宿主機端口,跨主機通信時使用主機 IP + 端口的方式訪問容器中的服務。顯然,這種方式僅能支持網絡棧的 4 層及以上的應用,並且容器與宿主機緊耦合,很難靈活地處理問題,可擴展性不佳;
  • 定義容器網絡:使用 Open vSwitch 或 Flannel 等第三方 SDN 工具,爲容器構建可以跨主機通信網絡環境。這一類方案一般要求各個主機上的 Docker0 網橋的 cidr 不同,以避免出現 IP 衝突的問題,限制容器在宿主機上可獲取的 IP 範圍。並且在容器需要對集羣外提供服務時,需要比較複雜的配置,對部署實施人員的網絡技能要求比較高。

2.2、容器網絡規範

容器網絡發展到現在,形成了兩大陣營:

  • Docker 的 CNM;
  • Google、CoreOS、Kubernetes 主導的 CNI。

CNM 和 CNI 是網絡規範或者網絡體系,並不是網絡實現,因此不關心容器的網絡實現方式,CNM 和 CNI 關心的只是網絡管理。

  • CNM(Container Network Model):CNM 的優勢在於原生,容器網絡和 Docker 容器生命週期結合緊密;缺點是被 Docker “綁架”。支持 CNM 網絡規範的容器網絡實現包括:Docker Swarm overlay、Macvlan & IP networkdrivers、Calico、Contiv、Weave等。
  • CNI(Container Network Interface):CNI 的優勢是兼容其他容器技術(rkt)以及上層的編排系統(Kubernetes&Mesos)、而且社區活躍勢頭迅猛;缺點是非 Docker 原生。支持 CNI 的網絡規範的容器網絡實現包括:Kubernetes、Weave、Macvlan、Calico、Flannel、Contiv、Mesos CNI,因爲它們都實現了 CNI 規範,用戶無論選擇哪種方案,得到的網絡模型都一樣,即每個 Pod 都有獨立的 IP,可以直接通信。區別在於不同方案的底層實現不同,有的採用基於 VxLAN 的 Overlay 實現,有的則是 Underlay,性能上有區別。再有就是是否支持 Network Policy。

2.3、網絡通信實現方案

但從網絡實現角度,又可分爲:
隧道方案:隧道方案在 IaaS 層的網絡中應用也比較多,它的主要缺點是隨着節點規模的增長複雜度會提升,而且出了網絡問題後跟蹤起來比較麻煩,大規模集羣情況下這是需要考慮的一個問題。

  • Weave:UDP 廣播,本機建立新的 BR,通過 PCAP 互通。
  • Open vSwitch(OVS):基於 VxLAN 和 GRE 協議,但是性能方面損失比較嚴重。
  • Flannel:UDP 廣播,VxLAN。
  • Racher:IPSec。

路由方案:一般是基於3層或者2層實現網絡隔離和跨主機容器互通的,出了問題也很容易排查。
Calico:基於 BGP 協議的路由方案,支持很細緻的 ACL 控制(Nerwork Policy),對混合雲親和度比較高。
Macvlan:從邏輯和 Kernel 層來看,是隔離性和性能最優的方案。基於二層隔離,所以需要二層路由器支持,大多數雲服務商不支持,所以混合雲上比較難以實現。

2.4、Kubernetes 網絡模型

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 都是私有的。

三、跨主機 Docker 網絡

3.1 Flannel 網絡方案

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 數據包裝在另一種網絡包裏面進行路由轉發和通信。

Kubernetes & Docker 容器網絡終極之戰(十四)

  1. 容器直接使用目標容器的 IP 訪問,默認通過容器內部的 eth0 發送出去;
  2. 報文通過 veth pair 被髮送到 vethXXX;
  3. vethXXX 是直接連接到 cni0,報文通過虛擬 bridge cni0 發送出去;
  4. 查找路由表,外部容器 IP 的報文都會轉發到 flannel.1 的虛擬網卡,這是一個 P2P 的虛擬網卡,然後報文就被轉發到監聽在另一端的 flanneld;
  5. flanneld 通過 etcd 維護了各個節點之間的路由表,把原來的報文 UDP 封裝一層,通過配置的 iface 發送出去;
  6. 報文通過主機之間的網絡棧找到目標主機;
  7. 報文繼續往上送,到達傳輸層,交給監聽的 flanneld 程序處理;
  8. 數據被解包,然後發送給 flannel.1 虛擬網卡;
  9. 查找路由表,發現對應容器的報文要交給 cni0;
  10. cni0 連接到自己的容器,把報文發送過去。

我們使用 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 強一些。

3.2、Calico 網絡方案

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 規則,控制進出容器的數據包,實現業務需求。

Kubernetes & Docker 容器網絡終極之戰(十四)

  1. Felix:運行在每一臺 Host 的 agent 進程,主要負責網絡接口管理和監聽、路由、ARP 管理、ACL 管理和同步、狀態上報等;
  2. Orchestrator Plugin:編排插件,並不是獨立運行的某些進程,而是設計與 k8s、OpenStack 等平臺集成的插件,如 Neutron’s ML2 plugin 用於用戶使用 Neutron API 來管理 Calico,本質是要解決模型和 API 間的兼容性問題;
  3. Etcd:Calico 模型的存儲引擎;
  4. BGP Client(BIRD):Calico 爲每一臺 Host 部署一個 BGP Client,使用 BIRD 實現,BIRD 是一個單獨的持續發展的項目,實現了衆多動態路由協議比如 BGP、OSPF、RIP 等。在 Calico 的角色是監聽 Host 上由 Felix 注入的路由信息,然後通過 BGP 協議廣播告訴剩餘 Host 節點,從而實現網絡互通;
  5. BGP Route Reflector(BIRD):在大型網絡規模中,如果僅僅使用 BGP client 形成 mesh 全網互聯的方案就會導致規模限制,因爲所有節點之間倆倆互聯,需要 N^2 個連接,爲了解決這個規模問題,可以採用 BGP 的 Router Reflector 的方法,使所有 BGP Client 僅與特定 RR 節點互聯並做路由同步,從而大大減少連接數。

Kubernetes & Docker 容器網絡終極之戰(十四)

3.3、Canal 網絡方案

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

3.4、Docker overlay 網絡方案

請查看我的博文 https://blog.51cto.com/wzlinux/2112061

3.5、Docker macvlan 網絡方案

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 網絡:

但主機的網卡數量是有限的,如何支持更多的 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 虛擬機,則不需要額外配置了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章