理解CNI網絡模型


CNI網絡模型

隨着容器技術在企業生產系統中的逐步落地,跨主機容器間的網絡互通已經成為基本要求,更高的要求包括容器固定IP地址、一個容器多個IP地址、多個子網隔離、ACL控制策略、與SDN集成等。目前主流的容器網絡模型主要有Docker公司提出的Container Network Model(CNM)模型和CoreOS公司提出的Container Network Interface(CNI)模型。

CNM模型

CNM模型主要通過Network Sandbox、Endpoint和Network這三個組件進行實現。

截屏2021-05-18 上午10.53.18

  • Network Sandbox:容器內部的網絡棧,包括網絡接口、路由 表、DNS等配置的管理。Sandbox可用Linux網絡命名空間、FreeBSD Jail等機制進行實現。一個Sandbox可以包含多個Endpoint。
  • Endpoint:用於將容器內的Sandbox與外部網絡相連的網絡接 口。可以使用veth對、Open vSwitch的內部port等技術進行實現。一個 Endpoint僅能夠加入一個Network。
  • Network:可以直接互連的Endpoint的集合。可以通過Linux網 橋、VLAN等技術進行實現。一個Network包含多個Endpoint。

CNI模型

CNI是由CoreOS公司提出的另一種容器網絡規范,讓各個容器管理平台(k8s,mesos等)都可以通過相同的接口調用各式各樣的網絡插件來為容器配置網絡。

截屏2021-05-18 上午10.57.21

CNI定義的是容器運行環境與網絡插件之間的簡單接口規范,通過 一個JSON Schema定義CNI插件提供的輸入和輸出參數。一個容器可以通過綁定多個網絡插件加入多個網絡中。

CNI規范概述

CNI提供了一種應用容器的插件化網絡解決方案,定義對容器網絡進行操作和配置的規范,通過插件的形式對CNI接口進行實現。CNI僅關注在創建容器時分配網絡資源,和在銷毀容器時刪除 網絡資源,這使得CNI規范非常輕巧、易於實現,得到了廣泛的支持。

CNI規范的一些要點:

  • CNI規范為一個容器定義一個Linux網絡命名空間
  • CNI的網絡定義存儲為JSON格式
  • 網絡定義通過STDIN輸入流傳輸到插件,這意味着宿主機上不會存儲網絡配置文件
  • 其他的配置參數通過環境變量傳遞給插件
  • CNI插件為可執行文件
  • CNI插件負責連通容器網絡,它要完成所有的工作才能使容器連入網絡
  • CNI插件負責調用IPAM插件

CNI模型只涉及兩個概念:容器和網絡

  • 容器(Container):是擁有獨立Linux網絡命名空間的環境, 例如使用Docker或rkt創建的容器。關鍵之處是容器需要擁有自己的 Linux網絡命名空間,這是加入網絡的必要條件。
  • 網絡(Network):表示可以互連的一組實體,這些實體擁有 各自獨立、唯一的IP地址,可以是容器、物理機或者其他網絡設備(比 如路由器)等。

對容器網絡的設置和操作都通過插件(Plugin)進行具體實現, CNI插件包括兩種類型:CNI Plugin和IPAM(IP Address Management) Plugin。CNI Plugin負責為容器配置網絡資源,IPAM Plugin負責對容器 的IP地址進行分配和管理。IPAM Plugin作為CNI Plugin的一部分,與 CNI Plugin一起工作。

CNI Plugin插件詳解

CNI Plugin包括3個基本接口的定義:添加(ADD)、刪除 (DELETE)、檢查(CHECK)和版本查詢(VERSION)。這些接口的具體實現要求插件提供一個可執行的程序,在容器網絡添加或刪除時進行調用,以完成具體的操作。比如添加接口的參數有Version、ContanierID、Network namespace、Network configuration、Extra arguments、Name of the interface inside the container。

網絡配置參數(Network configuration)則由一個JSON報文組成,以標准輸入(stdin)的方 式傳遞給可執行程序。下面例子定義了一個名為dbnet的網絡配置參數:

{
  "cniVersion": "0.4.0",	//cni版本號
  "name": "dbnet",	//網絡名稱,應在一個管理域內唯一
  "type": "bridge",	//CNI插件的可執行文件的名稱
  "args": "",	//其他參數
  "ipam": {	//IP地址管理的相關配置
		"type": "host-local",	//IPAM可執行文件名
    "subnet": "10.1.0.0.0/16",
    "gateway": "10.1.0.1"
	},
  "dns": {	//dns服務相關配置
    "nameservers": ["10.1.0.1"],
    "domain": ""	//本地域名
    "search": ""	//按優先級排序的域名查詢列表
    "options": ""	//傳遞給resolver的選項列表
  }
}

CNI插件應能夠支持通過環境變量和標准輸入傳入參數。可執行文 件通過網絡配置參數中的type字段標識的文件名在環境變量CNI_PATH 設定的路徑下進行查找

IPAM Plugin插件

為了減輕CNI Plugin對IP地址管理的負擔,在CNI規范中設置了一個 新的插件專門用於管理容器的IP地址(還包括網關、路由等信息),被稱為IPAM Plugin。通常由CNI Plugin在運行時自動調用IPAM Plugin完 成容器IP地址的分配。

如果成功完成了容器IP地址的分配,則IPAM插件應該通過標准輸 出(stdout)返回以下JSON報文:

{
  "cniVerison": "0.4.0",
  "ips": [
    {
      "version": "<4-or-6>",
      "address": "<ip-and-prefix-in-CIDR>"
      "gateway": "<ip-address-of-the-gateway>" //optional
    },
    //......
  ],
  "routes": [
    {
      "dst": "ip-and-prefix-in-cidr",
      "gw": "<ip-of-next-hop>"	//optional
    },
    //......
  ],
  "dns": {
    "nameservers": "<list-of-nameservers>"	//optional
    "domain": "<name-of-local-domain>"	//optional
    "search": "<list-of-search-domains>"	//optional
    "options": "<list-of-options>"	//optional
  }
}

多網絡插件

在很多情況下,一個容器需要連接多個網絡,CNI規范支持為一個 容器運行多個CNI Plugin來實現這個目標。多個網絡插件將按照網絡配置列表中的順序執行,並將前一個網絡配置的執行結果傳遞給后面的網絡配置。

下面的例子定義了兩個網絡配置參數,分別作用於兩個插件,第1 個為bridge,第2個為tuning。CNI將首先執行第1個bridge插件設置容器的網絡,然后執行第2個tuning插件:

{
  "cniVersion": "0.4.0",
  "name": "dbnet",
  "plugin": [
    {
      "type": "bridge",
      "args": {
        "labels": {
          "appVersion": "1.0"
        }
      },
      "ipam": {
        "type": "host-local",
        "subnet": "10.1.0.0/16"
        "gateway": "10.1.0.1"
      },
      "dns": {
        "nameservers": ["10.1.0.1"]
      }
    },
    {
      "type": "tuning",
      "sysctl": {
        "net.core.somaxconn": "500"
      }
    }
  ]
}

在Kubernetes中使用網絡插件

CNI插件是可執行文件,會被kubelet調用。Kubernetes目前支持兩種網絡插件的實現:

  • CNI插件:根據CNI規范實現其接口,以與插件提供者進行對接。
  • kubenet插件:使用bridge和host-local CNI插件實現一個基本的cbr0。

為了在k8s集群中使用網絡插件,需要在kubelet服務的啟動參數上設置下面兩個參數

  • --network-plugin-dir:kubelet啟動時掃描網絡插件的目錄
  • --network-plugin:網絡插件名稱,對於CNI插件為cni(無須關注--network-plugin-dir路徑),kubenet插件為kubenet。

設置為cni時,還需要兩個參數--cni-conf-dir(默認/etc/cni/net.d)和--cni-bin-dir(默認/opt/cni/bin),作用看名字就知道。

目前已有多個開源項目支持以CNI網絡插件的形式部署到Kubernetes集群中,進行Pod的網絡設置和網絡策略的設置。

使用CNI插件的簡單示例

Docker有自己的CNM標准,那我們可以將CNI與Docker一起使用嗎?答案是肯定的,但這不是個完整的解決方案。CNI插件負責連接容器,因此有可能只是用Docker的容器運行時,而不調用Docker的網絡端的工作。

CNI的工作是從容器管理系統處獲取運行時信息,包括network namespace的路徑,容器ID以及network interface name,再從容器網絡的配置文件中加載網絡配置信息,再將這些信息傳遞給對應的插件,由插件進行具體的網絡配置工作,並將配置的結果再返回到容器管理系統中。

下載CNI二進制文件

# -O 參數來告訴 curl 保存為文件,使用 -L 參數來允許 curl 跟隨重定向
curl -O -L https://github.com/containernetworking/cni/releases/download/v0.4.0/cni-amd64-v0.4.0.tgz

tar -xzvf cni-amd64-v0.4.0.tgz

截屏2021-05-27 上午10.30.26

讓我們聚焦到網絡插件bridge文件,Bridge是CNI官網插件之一,它的工作是將容器依附到網橋接口上。網絡配置是通過STDIN流傳輸到插件中的,其他信息通過環境變量傳遞到插件。

首先定義一個網橋的網絡配置文件

cat > mybridge.conf <<"EOF"
{
    "cniVersion": "0.2.0",
    "name": "mybridge",
    "type": "bridge",
    "bridge": "cni_bridge0",
    "isGateway": true,
    "ipMasq": true,
    "ipam": {
        "type": "host-local",
        "subnet": "10.15.20.0/24",
        "routes": [
            { "dst": "0.0.0.0/0" },
            { "dst": "1.1.1.1/32", "gw":"10.15.20.1"}
        ]
    }
}
EOF

除了可以設置系統級別的環境變量外,我們還可以把環境變量直接傳遞給命令。

sudo CNI_COMMAND=ADD CNI_CONTAINERID=xingns CNI_NETNS=/var/run/netns/xingns CNI_IFNAME=eth12 CNI_PATH=`pwd` ./bridge < mybridge.conf
  • CNI_COMMAND = ADD:告訴CNI要添加連接
  • CNI_CONTAINER = xingns:CNI要使用xingns網絡命名空間
  • CNI_NETNS = /var/run/netns/xingns:網絡命名空間路徑
  • CNI_IFNAME = eth12:命名空間里使用的網絡接口名
  • CNI_PATH = pwd:CNI插件的可執行文件路徑

在運行命令前,我們還需要創建插件將要配置的網絡命名空間,通常容器運行時會自動創建命名空間,但由於我們是自己手動實驗,所以得自己創建。

ip netns add xingns

創建完成后,運行插件

截屏2021-05-27 上午11.00.07

執行完后返回兩部分輸出

  • 由於IPAM找不到本地存儲的保留IP分配信息文件,因此返回錯誤。如果我們對其他網絡命名空間再次運行此命令,則不會出現此錯誤了,因為該文件在我們首次運行插件時創建了。
  • 其次是返回一個JSON格式的IP配置,在本例中,網橋本身配置為10.15.20.1/24的IP,而網絡命名空間接口將會分配到10.15.20.2/24,它還設置了默認網關和我們在網絡配置JSON中定義的1.1.1.1/32路由。

截屏2021-05-27 上午11.05.10

我們現在又了一個名為cni_bridge0的網橋接口,接口IP也和我們預期的一致,注意底部有veth設備的一端。我們還啟用了ipMasq,(是否為該網絡配置出站地址轉換)如果我們查看主機的iptables,將看到如下規則...

截屏2021-05-27 上午11.07.45

在看一下網絡命名空間:

截屏2021-05-27 上午11.09.30

截屏2021-05-27 上午11.10.56

網絡配置和預期的也一致,命名空間有一個名為”eth12”的網絡接口,其IP地址為10.15.20.2/24,我們之前定義的路由也在那里。

參考:

《Kubernetes權威指南》

http://www.dasblinkenlichten.com/understanding-cni-container-networking-interface/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM