Rancher技術特性全解及容器網絡解決方案

1、前言

本文目的在於和大家一起了解一下容器網絡以及如何在容器雲管理平臺上實現扁平網絡。

內容包括:
  • 什麼是 CNI 接口;
  • 容器網絡基於 CNI 的實現—-IPsec 及 VXLAN;
  • 容器網絡基於 CNI 的實現—-直接路由訪問容器;

2、容器時代

2.1 容器時代背景簡介

自2013年 Docker 出現以來,全球已經有越來越多的企業用戶在開發測試或生產環境中採用 Docker 容器技術。

然而,如下圖所示,在企業內部將容器技術真正用於生產時,很多用戶發現面臨的最大的問題仍然是在 VM 虛擬化時代曾經面臨並已經解決的問題。

例如,如何將容器中的數據進行持久化存儲,如何選擇合適的網絡方案,跨雲和跨數據中心的部署和管理如何解決?

Rancher技術特性全解及容器網絡解決方案

業內有款開源的容器雲管理平臺—— Rancher,短短1年裡,已經供全球 4000 多個用戶部署及試用、超過 1800 萬次的下載量(注:統計來自 DockerHub 官方鏡像下載數量)。

使用場景覆蓋金融、互聯網、運營商、教育等各個領域。在本次交流中我們將基於該開源容器雲平臺進行探討,同時針對容器面臨的網絡問題的解決方案進行分享。

2.2 容器的網絡類型

2.2.1 原始容器網絡

最早的容器網絡模型,利用的是容器宿主機內部的網絡,同時其 IPAM 管理也是基於容器宿主機的,所有容器宿主機上的容器都會連接到容器宿主機內的 Linux Bridge,叫 Docker0,它默認會分配 172.17 網段中的一個 IP,因為有 Docker0 這個網橋,所以在一個容器宿主機上的容器可以實現互聯互通。

但是因為 IPAM 範圍是基於單容器宿主機的,所以在其他容器宿主機上,也會出現完全相同的IP地址。這樣一來這兩個地址肯定沒辦法直接通信。

為了解決這個問題一般採用的就是 NAT 的方法。比如說我有一個應用,它有 Web 和 Mysql,分別在不同的容器宿主機上,Web 需要去訪問 Mysql,我們會把這個 Mysql 的3306端口映射到容器宿主機上的3306這個端口,然後這個服務實際上是去訪問容器宿主機 IP 10.10.10.3 的3306端口 。同時如果想要把服務暴露出去需要做端口映射。

Rancher技術特性全解及容器網絡解決方案

下面就是主要的三種容器原始網絡模式,這些模式在企業環境基本無法採用:

  • Bridge 模式
  • HOST 模式
  • Container 模式

2.2.2 容器網絡的進化

隨著用戶對容器的網絡要求的不斷提高,容器界湧現了很多新的網絡規範,其目的也都是幫助大家解決在使用容器時的網絡問題,現在最主流就是下面這兩個:

  • Container Networking Model (CNM)
  • Container Networking Interface (CNI)

需要注意的是 CNM 和 CNI 並不是網絡實現而是網絡規範和網絡體系,CNM 和 CNI 關心的是網絡管理的問題。

這兩個模型全都是插件化的,用戶可以以插件的形式去插入具體的網絡實現。其中 CNM 由 Docker 公司自己提出,而 CNI 則是 Google 的 Kubernetes 主導。

總體上說 CNM 比較不靈活,也不難麼開放,但是確是 Docker 的原生網絡實現。而 CNI 則更具通用性,而且也十分的靈活。

目前主流的插件如:Calico、Weave、Mesos 基本上是對 CNI 和 CNM 兩種規範都提供支持。

2.3 CNI和CNM簡介

2.3.1 CNM接口:

CNM 是一個被 Docker 提出的規範。現在已經被 Cisco Contiv, Kuryr, Open Virtual Networking (OVN), Project Calico, VMware 和 Weave 這些公司和項目所採納。

Rancher技術特性全解及容器網絡解決方案

其中 Libnetwork 是 CNM 的原生實現。它為 Docker daemon和網絡驅動程序之間提供了接口。網絡控制器負責將驅動和一個網絡進行對接。

每個驅動程序負責管理它所擁有的網絡以及為該網絡提供的各種服務,例如 IPAM 等等。由多個驅動支撐的多個網絡可以同時並存。

網絡驅動可以按提供方被劃分為原生驅動(libnetwork內置的或Docker支持的)或者遠程驅動 (第三方插件)。

原生驅動包括 none, bridge, overlay 以及 MACvlan。驅動也可以被按照適用範圍被劃分為本地(單主機)的和全局的 (多主機)。

Rancher技術特性全解及容器網絡解決方案

Network Sandbox:容器內部的網絡棧,包含interface、路由表以及DNS等配置,可以看做基於容器網絡配置的一個隔離環境(其概念類似“network namespace”)

Endpoint:網絡接口,一端在網絡容器內,另一端在網絡內。一個 Endpoints 可以加入一個網絡。一個容器可以有多個 endpoints。

Network:一個 endpoints 的集合。該集合內的所有endpoints可以互聯互通。(其概念類似:Linux bridge、VLAN)

最後,CNM 還支持標籤(labels)。Lable 是以 key-value 對定義的元數據。用戶可以通過定義 Label 這樣的元數據來自定義 libnetwork 和驅動的行為。

2.3.2 CNI網絡接口

CNI 是由 Google 提出的一個容器網絡規範。已採納改規範的包括 Apache Mesos, Cloud Foundry, Kubernetes, Kurma 和 rkt。另外 Contiv Networking, Project Calico 和 Weave 這些項目也為 CNI 提供插件。

Rancher技術特性全解及容器網絡解決方案

CNI 的規範比較小巧。它規定了一個容器runtime和網絡插件之間簡單的契約。這個契約通過JSON的語法定義了CNI插件所需要提供的輸入和輸出。

一個容器可以被加入到被不同插件所驅動的多個網絡之中。一個網絡有自己對應的插件和唯一的名稱。

CNI 插件需要提供兩個命令:一個用來將網絡接口加入到指定網絡,另一個用來將其移除。這兩個接口分別在容器被創建和銷燬的時候被調用。

在使用 CNI 接口時容器 runtime 首先需要分配一個網絡命名空間以及一個容器ID。然後連同一些 CNI 配置參數傳給網絡驅動。接著網絡驅動會將該容器連接到網絡並將分配的 IP 地址以 JSON 的格式返回給容器 runtime。

Mesos 是最新的加入 CNI 支持的項目。Cloud Foundry 的支持也正在開發中。當前的 Mesos 網絡使用宿主機模式,也就是說容器共享了宿主機的 IP 地址。

Mesos 正在嘗試為每個容器提供一個自己的 IP 地址。這樣做的目的是使得IT人員可以自行選擇適合自己的組網方式。

目前,CNI 的功能涵蓋了 IPAM, L2 和 L3。端口映射(L4)則由容器 runtime 自己負責。CNI 也沒有規定端口映射的規則。這樣比較簡化的設計對於 Mesos 來講有些問題。端口映射是其中之一。

另外一個問題是:當 CNI 的配置被改變時,容器的行為在規範中是沒有定義的。為此,Mesos在 CNI agent 重啟的時候,會使用該容器與 CNI 關聯的配置。

3、Rancher的Overlay網絡實現

說完了網絡規範,我們下面談一下 Rancher 是怎麼利用 CNI 規範完成容器環境下的 overlay 網絡實現。眾所周知,網絡是容器雲平臺中很重要的一環,對於不同的規模、不同的安全要求,會有不同的選型。

Rancher 的默認網絡目前完成了代碼重構,完全支持 CNI 標準,同時也會支持其他第三方 CNI 插件,結合Rancher獨有的 Environment Template 功能,用戶可以在一個大集群中的每個隔離環境內,創建不同的網絡模式,以滿足各種業務場景需求,這種管理的靈活性是其他平臺沒有的。

至於 Rancher 為什麼會選擇 CNI 標準,最開始 Rancher 也是基於 CNM 進行了開發,但隨著開發的深入,我們不得不轉向了 CNI,箇中原因在本次交流中我們就不做詳細說(tu)明(cao)了,

大家如果有興趣可以參閱:


在之前的 Rancher 版本上,用戶時常抱怨 Rancher 的網絡只有 IPsec,沒有其他選擇。而容器社區的發展是十分迅猛的,各種容器網絡插件風起雲湧。

在 Rancher v1.2 之後 Rancher 全面支持了 CNI 標準,除在容器網絡中實現 IPsec 之外又實現了呼聲比較高的 VXLAN 網絡,同時增加了 CNI 插件管理機制,讓用戶可以 hacking 接入其他第三方 CNI 插件。隨後將和大家一起解讀一下 Rancher 網絡的實現。

3.1 Rancher-net CNI的IPsec實現

以最簡單最快速方式部署 Rancher 並添加 Host,以默認的 IPsec 網絡部署一個簡單的應用後,進入應用容器內部看一看網絡情況,對比一下之前的 Rancher 版本:

Rancher技術特性全解及容器網絡解決方案

最直觀的感受便是,網卡名從 eth0 到 eth0@if8 有了變化,原先網卡多 IP 的實現也去掉了,變成了單純的 IPsec 網絡 IP。

這其實就引來了我們要探討的內容,雖然網絡實現還是 IPsec,但是 rancher-net 組件實際上是已經基於 CNI 標準了。最直接的證明就是看一下,rancher-net 鏡像的 Dockerfile:

Rancher技術特性全解及容器網絡解決方案

熟悉 CNI 規範的夥伴都知道 /opt/cni/bin 目錄是CNI的插件目錄,bridge 和 loopback 也是 CNI 的默認插件,這裡的 rancher-bridge 實際上和 CNI 原生的 bridge 沒有太大差別,只是在冪等性健壯性上做了增強。

而在 IPAM 也就是 IP 地址管理上,Rancher 實現了一個自己的 rancher-cni-ipam,它的實現非常簡單,就是通過訪問 rancher-metadata 來獲取系統給容器分配的 IP。

Rancher 實際上Fork了CNI的代碼並做了這些修改,https://github.com/rancher/cni。 這樣看來實際上,rancher-net 的 IPsec 和 Vxlan 網絡其實就是基於 CNI 的 bridge 基礎上實現的。

在解釋 rancher-net 怎麼和 CNI 融合之前,我們需要了解一下 CNI bridge 模式是怎麼工作的。

舉個例子,假設有兩個容器 nginx 和 mysql,每個容器都有自己的 eth0,由於每個容器都是在各自的 namespace 裡面。

所以互相之間是無法通信的,這就需要在外部構建一個 bridge 來做二層轉發,容器內的 eth0 和外部連接在容器上的虛擬網卡構建成對的veth設備,這樣容器之間就可以通信了。

其實無論是 docker 的 bridge 還是 cni 的 bridge,這部分工作原理是差不多的,如圖所示:

Rancher技術特性全解及容器網絡解決方案

那麼我們都知道 CNI 網絡在創建時需要有一個配置,這個配置用來定義CNI網絡模式,讀取哪個 CNI 插件。

在這個場景下也就是 cni bridge 的信息,這個信息 rancher 是通過 rancher-compose 傳入 metadata 來控制的。

查看 ipsec 服務的 rancher-compose.yml 可以看到,type 使用 rancher-bridge,ipam 使用 rancher-cni-ipam,bridge 網橋則複用了 docker0,有了這個配置我們甚至可以隨意定義 ipsec 網絡的 CIDR,如下圖所示:

Rancher技術特性全解及容器網絡解決方案

ipsec 服務實際上有兩個容器:一個是 ipsec 主容器,內部包含rancher-net服務和ipsec需要的charon服務;

另一個 sidekick 容器是 cni-driver,它來控制 cni bridge 的構建。

兩端主機通過 IPsec 隧道網絡通信時,數據包到達物理網卡時,需要通過 Host 內的 Iptables 規則轉發到 ipsec 容器內,這個 Iptables 規則管理則是由 network-manager 組件來完成的,https://github.com/rancher/plugin-manager。其原理如下圖所示(以 IPsec 為例):

Rancher技術特性全解及容器網絡解決方案

整體上看 cni ipsec 的實現比之前的 ipsec 精進了不少,而且也做了大量的解耦工作,不單純是走向社區的標準,之前大量的 Iptables 規則也有了很大的減少,性能上其實也有了很大提升。

3.2 Rancher-net vxlan的實現

那麼 rancher-net 的另外一個 backend vxlan 又是如何實現的呢?我們需要創建一套VXLAN網絡環境來一探究竟,默認的 Cattle 引擎網絡是 IPsec,如果修改成 VXLAN 有很多種方式,可以參考我下面使用的方式。

首先,創建一個新的 Environment Template,把 Rancher IPsec 禁用,同時開啟 Rancher VXLAN,如下圖所示:

Rancher技術特性全解及容器網絡解決方案

然後,我們創建一個新的 ENV,並使用剛才創建的模版 Cattle-VXLAN,創建完成後,添加 Host 即可使用。如下圖所示:

Rancher技術特性全解及容器網絡解決方案

以分析 IPsec 網絡實現方式來分析 VXLAN,基本上會發現其原理大致相同。同樣是基於 CNI bridge,使用 rancher 提供的 rancher-cni-bridge 、rancher-cni-ipam,網絡配置信息以 metadata 方式注入。

區別就在於 rancher-net 容器內部,rancher-net 激活的是 vxlan driver,它會生成一個 vtep1042 設備,並開啟 udp 4789 端口,這個設備基於 udp 4789 構建 vxlan overlay 的兩端通信,對於本機的容器通過 eth0 走 bridge 通信,對於其他Host的容器,則是通過路由規則轉發到 vtep1042 設備上,再通過 overlay 到對端主機,由對端主機的 bridge 轉發到相應的容器上。整個過程如圖所示:

Rancher技術特性全解及容器網絡解決方案

4、Rancher的扁平網絡實現

為什麼需要扁平網絡,因為容器目前主流的提供的都是 Overlay 網絡,這個模式的好處是,靈活、容易部署、可以屏蔽網絡對應用部署的阻礙。

但是對很多用戶而言,這樣也帶來了額外的網絡開銷,網絡管理不可以控制,以及無法與現有 SDN 網絡進行對接。

在實現扁平網絡後,容器可以直接分配業務 IP,這樣訪問容器上的應用就類似訪問 VM 裡的應用一樣,可以直接通過路由直達,不需要進行 NAT 映射。但扁平網絡帶來的問題是,會消耗大量的業務段 IP 地址,同時網絡廣播也會增多。

Rancher技術特性全解及容器網絡解決方案

4.1 扁平網絡實現

在 Rancher 環境中實現扁平網絡需要使用自定義的 bridge,同時這個 bridge 與 docker0 並沒有直接關係。

我們可以給容器添加新的網橋 mybridge,並把容器通過 veth 對連接到網橋上 mybridge 上,如果要實現容器訪問宿主機的 VM 上的服務可以將虛擬機配置的IP也配置到網橋上。

進行如上配置後,容器就可以實現 IP 之間路由直接訪問。此圖中的 vboxnet bridge 可以看做是用戶環境的上聯交互機。

Rancher技術特性全解及容器網絡解決方案

在VM和物理機的混合場景,所採用的方法也很類型,這邊就不再多做解釋了。

Rancher技術特性全解及容器網絡解決方案

Rancher CNI 網絡環境實現扁平網絡的工作流如下:

Rancher技術特性全解及容器網絡解決方案

在實現容器扁平網絡的基本配置後,就需要考慮和 Rancher 的集成,Rancher 的 Network-plugin 的啟動依賴於 Metadata,而 Metadata 和 DNS server 均使用 docker0 的 bridge 網絡(IP為169.254.169.250)。

即用戶配置的扁平網絡要能夠訪問到 docker0 網絡,否則 Rancher 提供的服務發現與註冊以及其它為業務層提供的服務將不可用。目前主要方法如下圖所示:

Rancher技術特性全解及容器網絡解決方案

  1. container-1 內部有到達 169.254.169.250 的一條主機路由,即要訪問 169.254.169.250 需要先訪問 10.43.0.2;
  2. 通過 veth-cni 與 veth-doc 的鏈接,CNI bridge 下的 container-1 可以將 ARP 請求發送到 docker0 的 10.43.0.2 地址上。由於 10.1.0.2 的 ARP response 報文是被 veth-cni 放行的,於是 container-1 能夠收到來自 10.43.0.2 的 ARP response 報文。
  3. 然後 container-1 開始發送到 169.254.169.250 的 IP 請求,報文首先被送到 docker0 的 veth-doc 上,docker0 查詢路由表,將報文轉到 DNS/metadata 對應的容器。
  4. 然後IP報文原路返回,被 docker0 路由到 veth1 上往 br0 發送,由於來自 169.254.169.250 的 IP 報文都是被放行的,因此 container-1 最終能夠收到 IP。
  5. 由於屬於該 network 的所有的宿主機的 docker0 上都需要綁定 IP 地址 10.43.0.2;因此,該IP地址必須被預留,即,在 catalog 中填寫 CNI 的 netconf 配置時,不能將其放入IP地址池。
  6. 同時,為了保障該地址對應的 ARP 請求報文不被髮送出主機,從而收到其他主機上對應接口的 ARP 響應報文,需要對所有請求 10.1.0.2 地址的 ARP REQUEST 報文做限制,不允許其通過 br0 發送到宿主機網卡。

具體轉發規則對應的 ebtables 規則如下所示:

Drop All traffic from veth-cni except: IP response from 169.254.169.250 ARP response from 10.43.0.2 ebtables -t broute -A BROUTING -i veth-cni -j DROP ebtables -t broute -I BROUTING -i veth-cni -p ipv4 --ip-source 169.254.169.250 -j ACCEPT ebtables -t broute -I BROUTING -i veth-cni -p arp --arp-opcode 2 --arp-ip-src 10.43.0.2 -j ACCEPT Drop ARP request for 10.43.0.2 on eth1 ebtables -t nat -D POSTROUTING -p arp --arp-opcode 1 --arp-ip-dst 10.43.0.2 -o eth1 -j DROP


另外也可以在容器所在的主機上將 Docker0 的 bridge 和 CNI 的 bridge 做三層打通,並使用 iptables 來進行控制,目前這個方式還在測試中。



分享到:


相關文章: