Container Networking Interface 入門簡介
Container Networking Inteferface (以下簡稱 CNI)是一個由 CoreOS 所提出的一個容器網路規範並開發了一個專案 containernetworking/cni ,他的核心目標是針對容器提出一個解決方案將網路功能插件化(模組化)。
詳細的 CNI 規格說明可以參考: cni/SPEC
當啟用一個 CNI 插件,運作流程是在創建容器時,調用這個 CNI 插件並為這個容器配置網路設定,最後再啟動容器內的 Process ,最後當容器結束前 CNI 插件會將網路功能終止再清除設定。
目前這個網路模型已經廣泛的受到社群的認可,例如知名的容器集群管理平台 Kubernetes 即是支援這種 CNI 容器網路規範,目前依不同需求,或不同社群及偏好可以在 Kubernetes 上選用不同插件像是 Calico, Weave, SRIOV, Ciliuim, Canal 和 Flannel ,而上述的插件都是遵循 CNI 容器網路規範,所開發而來。
CNI 基本使用方法
既然提到容器,我們可以回到容器的最基本核心概念,Linux Network Namespace 它提供了一個獨立的網路環境,包括網卡、路由、iptables 規則等都與其他的 Network Namespace 隔離。而最基礎操作 Network Namespace 方法可以透過 netns 來創建或刪除。對於想了解 netns 如何使用的朋友,不妨參考 手把手打造仿 mininet 網路 的 Step2。
接著我們要做的步驟大致如下:
- 創建 Network Namespace
- 建立一個 network configuration
- 運行 CNI Plugins 餵入 network configuration(本例將使用 linux bridge 的 plugin)
- 測試網路互通性
在 Ubuntu 64bit 系統上實驗,在開始之前,我們先將 CNI 插件備齊
$ mkdir myCNI
$ cd myCNI
$ curl -O -L https://github.com/containernetworking/cni/releases/download/v0.5.2/cni-amd64-v0.5.2.tgz
$ tar -xzvf cni-amd64-v0.5.2.tgz
$ ls
bridge cni-amd64-v0.5.2.tgz cnitool dhcp flannel host-local ipvlan loopback macvlan noop ptp tuning
這裡面的 network plugin binary 分別有不同的網路功能,我們將在這篇用到 bridge
及 host-local
Step1. 取得 root 權限後,透過 netns
創建兩個 network namespace
$ ip netns add ns1
$ ip netns add ns2
step2. 建立一個 network configuration
cat > mybridge.conf <<"EOF"
{
"name": "mybridge",
"type": "bridge",
"bridge": "kbr0",
"isGateway": true,
"isDefaultGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.244.0.0/16",
"routes": [
{ "dst": "0.0.0.0/0" }
],
"gateway": "10.244.1.1"
}
}
EOF
這個 configuration 十分重要,它除了定義 bridge 上的設定,也定義了容器接上 bridge 所配發的 IP 及所屬的子網域。稍微指出幾個比較特別的欄位:
type
: 是用來指定其對應的 binary 檔案名稱ipam
: 又作 IP Allocation 是用來分配容器IP及切割子網域,注意到裡面又有一個type
呼叫host-local
詳細的 bridge 個欄位設定資料可以參考: https://github.com/containernetworking/plugins/tree/master/plugins/main/bridge#network-configuration-reference
Step3. 運行 CNI Plugins 餵入 network configuration
CNI_COMMAND
指定 action (目前CNI套件有ADD
及DEL
兩個command);CNI_CONTAINERID
給予 namespace name;CNI_NETNS
mount 路徑;CNI_IFNAME
創建容器內部 interface 名稱CNI_PATH
告訴 CNI plugin 的所在位置(目前剛好在myCNI
目錄裡面所以用pwd
)
$ CNI_COMMAND=ADD CNI_CONTAINERID=ns1 CNI_NETNS=/var/run/netns/ns1 CNI_IFNAME=eth3 CNI_PATH=`pwd` ./bridge <mybridge.conf
{
"ip4": {
"ip": "10.244.0.1/16",
"gateway": "10.244.1.1",
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "10.244.1.1"
},
{
"dst": "0.0.0.0/0",
"gw": "10.244.1.1"
}
]
},
"dns": {}
}$ CNI_COMMAND=ADD CNI_CONTAINERID=ns2 CNI_NETNS=/var/run/netns/ns2 CNI_IFNAME=eth3 CNI_PATH=`pwd` ./bridge <mybridge.conf
{
"ip4": {
"ip": "10.244.0.2/16",
"gateway": "10.244.1.1",
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "10.244.1.1"
},
{
"dst": "0.0.0.0/0",
"gw": "10.244.1.1"
}
]
},
"dns": {}
}
Step4. 最後可以由 ip netns exec ${name} ifconfg
來看容器所分配的 IP 進行互通測試。
$ip netns exec ns1 ifconfig
eth3 Link encap:Ethernet HWaddr 0a:58:0a:f4:00:01
inet addr:10.244.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::903f:40ff:fea6:adc4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:23 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1854 (1.8 KB) TX bytes:648 (648.0 B)$ip netns exec ns2 ifconfig
eth3 Link encap:Ethernet HWaddr 0a:58:0a:f4:00:02
inet addr:10.244.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::10e0:5aff:feca:442a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 B) TX bytes:648 (648.0 B)$ ip netns exec ns2 ping 10.244.0.1
PING 10.244.0.1 (10.244.0.1) 56(84) bytes of data.
64 bytes from 10.244.0.1: icmp_seq=1 ttl=64 time=0.360 ms
64 bytes from 10.244.0.1: icmp_seq=2 ttl=64 time=0.093 ms
64 bytes from 10.244.0.1: icmp_seq=3 ttl=64 time=0.086 ms
這篇算是個入門的操作簡介,讓大家更快瞭解 CNI 的使用,如果有在使用 Docker container 也是可以透過類似相同的手法來操作將 CNI 的 Plugin 接上,只要取得 container ID 及 network namespace 的 mount 路徑,即可做到一樣的操作方法。
未來幾篇會再介紹 CNI 怎麼跟 Docker 一起使用,以及最近我正在開發的 CNI Plugin 開發的動機與使用方法。