|作者简介
John lin
目前專注於 Kubernetes CNI 插件開發,並透過 Open vSwitch 設計容器網路於多物理節點上的虛擬網路架構
之前的文章内有提到过CNI插件
Container Networking Inteferface (以下简称 CNI)是一个由 CoreOS 所提出的一个容器网路规范并开发了一个专案 containernetworking/cni ,他的核心目标是针对容器提出一个解决方案将网路功能插件化(模组化)
当启用一个 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
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 路径,即可做到一样的操作方法。
· END ·