CNI(Container Network Interface)容器网络接口。CNI只专注解决容器网络连接和容器销毁时的资源释放,提供一套框架,所以CNI可以支持大量不同的网络模式,并且容易实现。
执行CNI需要传入一下变量
# 添加或者删除网卡
CNI_COMMAND=ADD/DEL
# 容器的ID
CNI_CONTAINERID=xxxxxxxxxxxxxxxxxxx
# 容器网络空间主机映射路径
CNI_NETNS=/proc/4390/ns/net
# CNI参数,使用分号分开,只要是POD的一些相关信息
CNI_ARGS=IgnoreUnknown=1;K8S_POD_NAMESPACE=default;K8S_POD_NAME=22-my-nginx-2523304718-7stgs;K8S_POD_INFRA_CONTAINER_ID=xxxxxxxxxxxxxxxx
# 容器内网卡的名称
CNI_IFNAME=eth0
# CNI二进制文件路径
CNI_PATH=/opt/cni/bin.
上面介绍了一层CNI网络规范,目前实现该规范的网络方案有:bridge、ipvlan、loopback、ptp和macvlan、calico等。
其中ipam主要是dhcp、host-local还有calico结合etcd完成的ipam等。
这篇先介绍使用配置,下一篇开始详细的源代码介绍
如果使用bridge则按照如下配置
$ mkdir -p /etc/cni/net.d
$ cat >/etc/cni/net.d/10-mynet.conf <<EOF
{
"cniVersion": "0.2.0",
"name": "mynet",
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.22.0.0/16",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
}
EOF
$ cat >/etc/cni/net.d/99-loopback.conf <<EOF
{
"cniVersion": "0.2.0",
"type": "loopback"
}
EOF
如果使用calico
mkdir -p /etc/cni/net.d
cat >/etc/cni/net.d/10-calico.conf <"name": "calico-k8s-network",
"type": "calico",
"etcd_endpoints": "http://:" , "log_level": "info",
"ipam": {
"type": "calico-ipam" },
"policy": { "type": "k8s" }, "kubernetes": {
"kubeconfig": "" }}
EOF
如果大家对cni感兴趣可以看源代码实现
通过
./build
CNI_PATH=`pwd`/bin
cd scripts
sudo CNI_PATH=$CNI_PATH ./docker-run.sh --rm busybox:latest ifconfig
就可以使用cni创建容器网卡了。
上面创建容器的脚步其实很简单,就是上面原理的实现
contid=$(docker run -d --net=none busybox:latest /bin/sleep 10000000)
pid=$(docker inspect -f '{{ .State.Pid }}' $contid)
netnspath=/proc/$pid/ns/net
./exec-plugins.sh add $contid $netnspath
function cleanup() {
./exec-plugins.sh del $contid $netnspath
docker kill $contid >/dev/null
}
trap cleanup EXIT
docker run --net=container:$contid $@
先启动一个没有网络的容器(先叫他sanbox),然后通过exec-plugins.sh给这个容器添加网络,最后用户可以把自己的容器添加到上面创建的那个sanbox上面。
看具体exec-plugins.sh里面
function exec_plugins() {
i=0
contid=$2
netns=$3
export CNI_COMMAND=$(echo $1 | tr '[:lower:]' '[:upper:]')
export PATH=$CNI_PATH:$PATH
export CNI_CONTAINERID=$contid
export CNI_NETNS=$netns
for netconf in $(echo $NETCONFPATH/*.conf | sort); do
name=$(jq -r '.name' <$netconf)
plugin=$(jq -r '.type' <$netconf)
export CNI_IFNAME=$(printf eth%d $i)
res=$($plugin <$netconf)
if [ $? -ne 0 ]; then
errmsg=$(echo $res | jq -r '.msg')
if [ -z "$errmsg" ]; then
errmsg=$res
fi
echo "${name} : error executing $CNI_COMMAND: $errmsg"
exit 1
elif [[ ${DEBUG} -gt 0 ]]; then
echo ${res} | jq -r .
fi
let "i=i+1"
done
}
上面的代码就是刚才上面CNI完整实现,定义一些环境变量,然后通过cni的二进制去挂载容器网络。