运维开发网

容器CNI完全解读(一)

运维开发网 https://www.qedev.com 2020-04-09 19:18 出处:网络 作者:运维开发网整理
CNI(Container Network Interface)容器网络接口。CNI只专注解决容器网络连接和容器销毁时的资源释放,提供一套框架,所以CNI可以支持大量不同的网络模式,并且容易实现。 执行CNI需要传入一下变量 # 添加或者删除网卡 CNI_COMMAND=ADD/DEL # 容器的ID CNI_CONTAINERID=xxxxxxxxxxxxxxxxxxx # 容器网络空间主

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 <<EOF
{    "name": "calico-k8s-network",  
     "type": "calico",
     "etcd_endpoints": "http://<ETCD_IP>:<ETCD_PORT>",         "log_level": "info",
        "ipam": {        
        "type": "calico-ipam"    }, 
               "policy": {        "type": "k8s"    },    "kubernetes": {
                       "kubeconfig": "</PATH/TO/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 [email protected]

先启动一个没有网络的容器(先叫他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的二进制去挂载容器网络。

扫码领视频副本.gif

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号