docker容器技術學習筆記(9、跨主機網絡)

跨主機網絡

跨主機網絡方案包括:
1、docker 原生的 overlay 和 macvlan。
2、第三方方案:常用的包括 flannel、weave 和 calico。

docker 網絡是一個非常活躍的技術領域,不斷有新的方案開發出來,那麼要問個非常重要的問題了:如此衆多的方案是如何與 docker 集成在一起的?答案是:libnetwork 以及 CNM。

libnetwork & CNM

libnetwork 是 docker 容器網絡庫,最核心的內容是其定義的 Container Network Model (CNM),這個模型對容器網絡進行了抽象,由以下三類組件組成:

  • Sandbox

Sandbox 是容器的網絡棧,包含容器的 interface、路由表和 DNS 設置。 Linux Network Namespace 是 Sandbox 的標準實現。Sandbox 可以包含來自不同 Network 的 Endpoint。

  • Endpoint

Endpoint 的作用是將 Sandbox 接入 Network。Endpoint 的典型實現是 veth pair,。一個 Endpoint 只能屬於一個網絡,也只能屬於一個 Sandbox。

  • Network

Network 包含一組 Endpoint,同一 Network 的 Endpoint 可以直接通信。Network 的實現可以是 Linux Bridge、VLAN 等。

下面是 CNM 的示例:


如圖所示兩個容器,一個容器一個 Sandbox,每個 Sandbox 都有一個 Endpoint 連接到 Network 1,第二個 Sandbox 還有一個 Endpoint 將其接入 Network 2。

libnetwork CNM 定義了 docker 容器的網絡模型,按照該模型開發出的 driver 就能與 docker daemon 協同工作,實現容器網絡。docker 原生的 driver 包括 none、bridge、overlay 和 macvlan,第三方 driver 包括 flannel、weave、calico 等。


overlay driver

爲支持容器跨主機通信,Docker 提供了 overlay driver,使用戶可以創建基於 VxLAN 的 overlay 網絡。VxLAN 可將二層數據封裝到 UDP 進行傳輸,VxLAN 提供與 VLAN 相同的以太網二層服務,但是擁有更強的擴展性和靈活性。

  • 實驗環境

在 docker 主機 host1(10.10.8.126)和 host2(10.10.8.127)上實踐各種跨主機網絡方案,在 10.10.8.125 上部署支持的組件,比如 Consul。

最簡單的方式是以容器方式運行 Consul:
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap

容器啓動後,可以通過 http://10.10.8.125:8500 訪問 Consul。

接下來修改 host1 和 host2 的 docker daemon 的配置文件/etc/systemd/system/docker.service。
--cluster-store 指定 consul 的地址。
--cluster-advertise 告知 consul 自己的連接地址。

重啓 docker daemon。
systemctl daemon-reload
systemctl restart docker.service
host1 和 host2 將自動註冊到 Consul 數據庫中。

  • 創建 overlay 網絡

在 host1 中創建 overlay 網絡 ov_net1,-d overlay 指定 driver 爲 overaly:

docker network create -d overlay ov_net1

docker network ls 查看當前網絡:

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
db19978034cb        bridge              bridge              local
bae92bff8199        host                host                local
deb4cbe62ba0        none                null                local
48b4931748ef        ov_net1             overlay             global

注意到 ov_net1 的 SCOPE 爲 global,而其他網絡爲 local。host2 上也能看到 ov_net1。這是因爲創建 ov_net1 時 host1 將 overlay 網絡信息存入了 consul,host2 從 consul 讀取到了新網絡的數據。之後 ov_net 的任何變化都會同步到 host1 和 host2。

docker network inspect 查看 ov_net1 的詳細信息:

docker network inspect ov_net1 
[
    {
        "Name": "ov_net1",
        "Id": "48b4931748ef3f7b33014b8e1a17fcf9786ff0114766d659d23a5b97fa90dfa2",
        "Created": "2018-09-04T10:20:33.247929912+08:00",
        "Scope": "global",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

IPAM 是指 IP Address Management,docker 自動爲 ov_net1 分配的 IP 空間爲 10.0.0.0/24。

  • 在overlay中運行容器

運行一個 busybox 容器並連接到 ov_net1:

docker run -itd --name bbox1 --network ov_net1 busybox

查看容器的網絡配置:

docker exec  bbox1 ip r
default via 172.18.0.1 dev eth1 
10.0.0.0/24 dev eth0 scope link  src 10.0.0.2 
172.18.0.0/16 dev eth1 scope link  src 172.18.0.2 

bbox1 有兩個網絡接口 eth0 和 eth1。eth0 IP 爲 10.0.0.2,連接的是 overlay 網絡 ov_net1。eth1 IP 172.18.0.2,容器的默認路由是走 eth1,eth1 是哪兒來的呢?

其實,docker 會創建一個 bridge 網絡 “docker_gwbridge”,爲所有連接到 overlay 網絡的容器提供訪問外網的能力。

如果外網要訪問容器,可通過主機端口映射,比如:
docker run -p 80:80 -d --net ov_net1 --name web1 httpd

  • overlay 網絡跨主機通信

在 host2 中運行容器 bbox2:

docker run -itd --name bbox2 --network ov_net1 busybox 

bbox2 IP 爲 10.0.0.3,可以直接 ping bbox1,可見 overlay 網絡中的容器可以直接通信,同時 docker 也實現了 DNS 服務。

docker 會爲每個 overlay 網絡創建一個獨立的 network namespace,其中會有一個 linux bridge br0,endpoint 還是由 veth pair 實現,一端連接到容器中(即 eth0),另一端連接到 namespace 的 br0 上。

br0 除了連接所有的 endpoint,還會連接一個 vxlan 設備,用於與其他 host 建立 vxlan tunnel。容器之間的數據就是通過這個 tunnel 通信的。邏輯網絡拓撲結構如圖所示:

要查看 overlay 網絡的 namespace 可以在 host1 和 host2 上執行 ip netns(請確保在此之前執行過 ln -s /var/run/docker/netns /var/run/netns),可以看到兩個 host 上有一個相同的 namespace “1-f4af9b33c0”:

ip netns
1-f4af9b33c0

這就是 ov_net1 的 namespace,查看 namespace 中的 br0 上的設備。

ip netns exec 1-f4af9b33c0 brctl show

查看 vxlan1 設備的具體配置信息可知此 overlay 使用的 VNI(VxLAN ID)爲 256。

ip netns exec 1-f4af9b33c0 ip -d l show vxlan1
  • overlay 的網絡隔離特性

不同的 overlay 網絡是相互隔離的。創建第二個 overlay 網絡 ov_net2 並運行容器 bbox3。bbox3 分配到的 IP 是 10.0.1.2,嘗試 ping bbox1(10.0.0.2)。ping 失敗,可見不同 overlay 網絡之間是隔離的。即便是通過 docker_gwbridge 也不能通信。
如果要實現 bbox3 與 bbox1 通信,可以將 bbox3 也連接到 ov_net1。

docker network connect ov_net1 bbox3

docker 默認爲 overlay 網絡分配 24 位掩碼的子網(10.0.X.0/24),所有主機共享這個 subnet,容器啓動時會順序從此空間分配 IP。當然我們也可以通過 --subnet 指定 IP 空間。
docker network create -d overlay --subnet 10.22.1.0/24 ov_net3

macvlan 網絡

除了 overlay,docker 還開發了另一個支持跨主機容器網絡的 driver:macvlan。

macvlan 本身是 linxu kernel 模塊,其功能是允許在同一個物理網卡上配置多個 MAC 地址,即多個 interface,每個 interface 可以配置自己的 IP。macvlan 本質上是一種網卡虛擬化技術,Docker 用 macvlan 實現容器網絡就不奇怪了。

macvlan 的最大優點是性能極好,相比其他實現,macvlan 不需要創建 Linux bridge,而是直接通過以太 interface 連接到物理網絡。

  • 準備實驗環境

我們會使用 host1 和 host2 上單獨的網卡 eth0 創建 macvlan。爲保證多個 MAC 地址的網絡包都可以從 eth0 通過,我們需要打開網卡的混雜模式。
ip link set eth0 promisc on
確保 eth0 狀態 UP 並且 promisc 模式已經生效。

  • 創建 macvlan網絡
    在 host1 和 host2 中創建 macvlan 網絡 mac_net1:
# docker network create -d macvlan \
> --subnet=172.16.86.0/24 \
> --gateway=172.16.86.1 \
> -o parent=eth0 mac_net1

注意:在 host2 中也要執行相同的命令。

① -d macvlan 指定 driver 爲 macvlan。
② macvlan 網絡是 local 網絡,爲了保證跨主機能夠通信,用戶需要自己管理 IP subnet。
③ 與其他網絡不同,docker 不會爲 macvlan 創建網關,這裏的網關應該是真實存在的,否則容器無法路由。
④ -o parent 指定使用的網絡 interface。

在 host1 中運行容器 bbox1 並連接到 mac_net1。

docker run -itd --name bbox1 --ip=172.16.86.10 --network mac_net1 busybox
由於 host1 中的 mac_net1 與 host2 中的 mac_net1 本質上是獨立的,爲了避免自動分配造成 IP 衝突,我們最好通過 --ip 指定 bbox1 地址爲 172.16.86.10。

在 host2 中運行容器 bbox2,指定 IP 172.16.86.11。

docker run -itd --name bbox2 --ip=172.16.86.11 --network mac_net1 busybox
bbox2 能夠 ping 到 bbox1 的 IP 172.16.86.10,但無法解析 “bbox1” 主機名。
  • macvlan 網絡結構

macvlan 不依賴 Linux bridge,brctl show 可以確認沒有創建新的 bridge。
查看一下容器 bbox1 的網絡設備:

docker exec bbox1 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
21: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:10:56:0a brd ff:ff:ff:ff:ff:ff

除了 lo,容器只有一個 eth0,請注意 eth0 後面的 @if2,這表明該 interface 有一個對應的 interface,其全局的編號爲 2。根據 macvlan 的原理,我們有理由猜測這個 interface 就是主機的 eth0,確認如下:
ip link show eth0
2: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:16:3e:0e:f7:cd brd ff:ff:ff:ff:ff:ff

可見,容器的 eth0 就是 主機的eth0 通過 macvlan 虛擬出來的 interface。容器的 interface 直接與主機的網卡連接,這種方案使得容器無需通過 NAT 和端口映射就能與外網直接通信(只要有網關),在網絡上與其他獨立主機沒有區別。當前網絡結構如圖所示:

  • 用 sub-interface 實現多 macvlan 網絡

macvlan 會獨佔主機的網卡,也就是說一個網卡只能創建一個 macvlan 網絡。但主機的網卡數量是有限的,如何支持更多的 macvlan 網絡呢?好在 macvlan 不僅可以連接到 interface(如 eth0),也可以連接到 sub-interface(如 eth0.xxx)。

VLAN 是現代網絡常用的網絡虛擬化技術,它可以將物理的二層網絡劃分成多達 4094 個邏輯網絡,這些邏輯網絡在二層上是隔離的,每個邏輯網絡(即 VLAN)由 VLAN ID 區分,VLAN ID 的取值爲 1-4094。Linux 的網卡也能支持 VLAN(apt-get install vlan),同一個 interface 可以收發多個 VLAN 的數據包,不過前提是要創建 VLAN 的 sub-interface。

比如希望 eth0 同時支持 VLAN10 和 VLAN20,則需創建 sub-interface eth0.10 和 eth0.20。在交換機上,如果某個 port 只能收發單個 VLAN 的數據,該 port 爲 Access 模式,如果支持多 VLAN,則爲 Trunk 模式。

下面演示如何在 eth0.10 和 eth0.20 上創建 macvlan 網絡。
首先編輯 host1 和 host2 的 /etc/network/interfaces,配置 sub-interface

iface eth0 inet manual
auto eth0.10
iface eth0.10 inet manual
vlan-raw-device eth0
auto eth0.20
iface eth0.20 inet manual
vlan-raw-device eth0

然後啓用 sub-interface:
ifup eth0.10
ifup eth0.20

創建 macvlan 網絡:
docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=eth0.10 mac_net10
docker network create -d macvlan --subnet=172.16.20.0/24 --gateway=172.16.20.1 -o parent=eth0.20 mac_net20

在 host1 中運行容器:
docker run -itd --name bbox1 --ip=172.16.10.10 --network mac_net10 busybox
docker run -itd --name bbox2 --ip=172.16.20.10 --network mac_net20 busybox

在 host2 中運行容器:
docker run -itd --name bbox3 --ip=172.16.10.11 --network mac_net10 busybox
docker run -itd --name bbox4 --ip=172.16.20.11 --network mac_net20 busybox

當前網絡結構如圖所示:


驗證 macvlan 之間的連通性:
bbox1 能 ping 通 bbox3,bbox2 能 ping 通 bbox4。即:同一 macvlan 網絡能通信。

bbox1 無法 ping 通 bbox2 和 bbox4。即:不同 macvlan 網絡之間不能通信。但更準確的說法應該是:不同 macvlan 網絡不能 在二層上 通信。在三層上可以通過網關將 macvlan 連通,下面我們就啓用網關。

我們會將 Host 10.10.8.125 配置成一個虛擬路由器,設置網關並轉發 VLAN10 和 VLAN20 的流量。當然也可以使用物理路由器達到同樣的效果。首先確保操作系統 IP Forwarding 已經啓用。

# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

flannel網絡

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,最常用的有 vxlan 和 host-gw,我們將在本章討論這兩種 backend。其他 backend 請參考 https://github.com/coreos/flannel。

  • 實驗環境

etcd 部署在 10.10.8.125,host1 和 host2 上運行 flanneld,首先安裝配置 etcd。

  • 安裝配置 etcd

在10.10.8.125運行如下腳本:

ETCD_VER=v2.3.7

DOWNLOAD_URL=https://github.com/coreos/etcd/releases/download

curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz

mkdir -p /tmp/test-etcd && tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/test-etcd --strip-components=1

cp /tmp/test-etcd/etcd* /usr/local/bin/

該腳本從 github 上下載 etcd 的可執行文件並保存到 /usr/local/bin/,啓動 etcd 並打開 2379 監聽端口。

etcd -listen-client-urls http://10.10.8.125:2379 -advertise-client-urls http://10.10.8.125:2379

weave網絡

weave 是 Weaveworks 開發的容器網絡解決方案。weave 創建的虛擬網絡可以將部署在多個主機上的容器連接起來。對容器來說,weave 就像一個巨大的以太網交換機,所有容器都被接入這個交換機,容器可以直接通信,無需 NAT 和端口映射。除此之外,weave 的 DNS 模塊使容器可以通過 hostname 訪問。

Calico網絡

Calico 是一個純三層的虛擬網絡方案,Calico 爲每個容器分配一個 IP,每個 host 都是 router,把不同 host 的容器連接起來。與 VxLAN 不同的是,Calico 不對數據包做額外封裝,不需要 NAT 和端口映射,擴展性和性能都很好。

與其他容器網絡方案相比,Calico 還有一大優勢:network policy。用戶可以動態定義 ACL 規則,控制進出容器的數據包,實現業務需求。

docker網絡總結

Docker Overaly,Macvaln,Flannel,Weave 和 Calico 跨主機網絡方案。目前這個領域是百家爭鳴,而且還有新的方案不斷涌現。

我們將從如下幾個方面比較,大家可以根據不同場景選擇最合適的方案。

網絡模型
採用何種網絡模型支持 multi-host 網絡?

Distributed Store 
是否需要 etcd 或 consul 這類分佈式 key-value 數據庫存儲網絡信息?

IPMA
如何管理容器網絡的 IP?

連通與隔離
提供怎樣的網絡連通性?支持容器間哪個級別和哪個類型的隔離?

性能
性能比較。
  • 網絡模型

跨主機網絡意味着將不同主機上的容器用同一個虛擬網絡連接起來。這個虛擬網絡的拓撲結構和實現技術就是網絡模型。

Docker overlay 如名稱所示,是 overlay 網絡,建立主機間 VxLAN 隧道,原始數據包在發送端被封裝成 VxLAN 數據包,到達目的後在接收端解包。

Macvlan 網絡在二層上通過 VLAN 連接容器,在三層上依賴外部網關連接不同 macvlan。數據包直接發送,不需要封裝,屬於 underlay 網絡。

Flannel 我們討論了兩種 backend:vxlan 和 host-gw。vxlan 與 Docker overlay 類似,屬於 overlay 網絡。host-gw 將主機作爲網關,依賴三層 IP 轉發,不需要像 vxlan 那樣對包進行封裝,屬於 underlay 網絡。

Weave 是 VxLAN 實現,屬於 overlay 網絡。

各方案的網絡模型描述如下:

  • Distributed Store

Docker Overlay、Flannel 和 Calico 都需要 etcd 或 consul。Macvlan 是簡單的 local 網絡,不需要保存和共享網絡信息。Weave 自己負責在主機間交換網絡配置信息,也不需要 Distributed Store。

  • IPAM

Docker Overlay 網絡中所有主機共享同一個 subnet,容器啓動時會順序分配 IP,可以通過 --subnet 定製此 IP 空間。

Macvlan 需要用戶自己管理 subnet,爲容器分配 IP,不同 subnet 通信依賴外部網關。

Flannel 爲每個主機自動分配獨立的 subnet,用戶只需要指定一個大的 IP 池。不同 subnet 之間的路由信息也由 Flannel 自動生成和配置。

Weave 的默認配置下所有容器使用 10.32.0.0/12 subnet,如果此地址空間與現有 IP 衝突,可以通過 --ipalloc-range 分配特定的 subnet。

Calico 從 IP Pool(可定製)中爲每個主機分配自己的 subnet。

  • 連通與隔離

同一 Docker Overlay 網絡中的容器可以通信,但不同網絡之間無法通信,要實現跨網絡訪問,只有將容器加入多個網絡。與外網通信可以通過 docker_gwbridge 網絡。

Macvlan 網絡的連通或隔離完全取決於二層 VLAN 和三層路由。

不同 Flannel 網絡中的容器直接就可以通信,沒有提供隔離。與外網通信可以通過 bridge 網絡。

Weave 網絡默認配置下所有容器在一個大的 subnet 中,可以自由通信,如果要實現隔離,需要爲容器指定不同的 subnet 或 IP。與外網通信的方案是將主機加入到 weave 網絡,並把主機當作網關。

Calico 默認配置下只允許位於同一網絡中的容器之間通信,但通過其強大的 Policy 能夠實現幾乎任意場景的訪問控制。

  • 性能

性能測試是一個非常嚴謹和複雜的工程,這裏我們只嘗試從技術方案的原理上比較各方案的性能。

最樸素的判斷是:Underlay 網絡性能優於 Overlay 網絡。

Overlay 網絡利用隧道技術,將數據包封裝到 UDP 中進行傳輸。因爲涉及數據包的封裝和解封,存在額外的 CPU 和網絡開銷。雖然幾乎所有 Overlay 網絡方案底層都採用 Linux kernel 的 vxlan 模塊,這樣可以儘量減少開銷,但這個開銷與 Underlay 網絡相比還是存在的。所以 Macvlan、Flannel host-gw、Calico 的性能會優於 Docker overlay、Flannel vxlan 和 Weave。

Overlay 較 Underlay 可以支持更多的二層網段,能更好地利用已有網絡,以及有避免物理交換機 MAC 表耗盡等優勢,所以在方案選型的時候需要綜合考慮。

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