手工体验docker 是怎么管理网络的-docker 直接使用CNI插件(2)

本文介绍了CNI(Container Network Interface)在网络管理中的作用,通过Docker容器展示了如何利用CNI插件进行网络配置,包括创建netns、配置bridge网络,并通过CRI(Container Runtime Interface)模拟了Kubernetes中容器网络的创建过程。重点讨论了CNI如何标准化不同容器平台的网络适配,以及CNI插件如何管理容器网络。
摘要由CSDN通过智能技术生成

1. CNI 简介

不管是 docker 还是 kubernetes,不管是在现在还是在未来,在网络方面都不会一个完美的、终极的、普适性的解决方案,不同的用户和企业因为各种原因会使用不同的网络方案。目前存在网络方案 flannel、calico、openvswitch、weave、ipvlan 还有我司的kube-ovn等,而且以后一定会有其他的网络方案,这些方案接口和使用方法都不相同,而不同的容器平台都需要网络功能,它们之间的适配如果没有统一的标准,会有很大的工作量和重复劳动。

我们不可能为了一个新的网络方案,重新修改kubelet的代码,所以CNI 就是这样一个标准,它旨在为容器平台提供网络的标准化。我们会从docker 出发,利用已经开源的cni 插件,体验cni 如何管理docker 的网络配置。

2. 先创建一个普通的netns,给它做些网络配置(一会儿用来测试下网络的联通与否)

  1. 先下载下cni 的插件二进制文件,这里使用0.4.0版本。

    [root@VM-0-15-centos cni]#curl -OJL https://github.com/containernetworking/cni/releases/download/v0.4.0/cni-amd64-v0.4.0.tgz
    [root@VM-0-15-centos cni]#tar -xzvf cni-amd64-v0.4.0.tgz
    [root@VM-0-15-centos cni]# ll
    总用量 70756
    -rwxr-xr-x 1 root root  5924584 1月  14 2017 bridge
    -rw-r--r-- 1 root root 16066400 3月   2 21:59 cni-amd64-v0.4.0.tgz
    -rwxr-xr-x 1 root root  3614840 1月  14 2017 cnitool
    -rwxr-xr-x 1 root root 10354296 1月  14 2017 dhcp
    -rwxr-xr-x 1 root root  3684624 1月  14 2017 flannel
    -rwxr-xr-x 1 root root  4008016 1月  14 2017 host-local
    -rwxr-xr-x 1 root root  5308904 1月  14 2017 ipvlan
    -rwxr-xr-x 1 root root  5033704 1月  14 2017 loopback
    -rwxr-xr-x 1 root root  5334832 1月  14 2017 macvlan
    -rwxr-xr-x 1 root root  3400872 1月  14 2017 noop
    -rwxr-xr-x 1 root root  5910424 1月  14 2017 ptp
    -rwxr-xr-x 1 root root  3791288 1月  14 2017 tuning
    
  2. 创建一个bridge 设备

    ip l a br0 type bridge
    ip l s br0 up 
    
  3. 创建一个普通的netns

    [root@VM-0-15-centos lmxia]# ip netns list
    lmxia
    
  4. 新增CNI的配置文件:

    cat > mybridge.conf <<"EOF"
    {
        "cniVersion": "0.2.0",
        "name": "mybridge",
        "type": "bridge",
        "bridge": "cni_bridge0",
        "isGateway": true,
        "ipMasq": true,
        "hairpinMode":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
    
  5. 把它放在cni 的默认目录下

    [root@VM-0-15-centos lmxia]# mkdir -p /etc/cni/net.d
    [root@VM-0-15-centos lmxia]# mv mybridge.conf /etc/cni/net.d
    
  6. 利用bridge 插件给这个netns 设置虚拟设备队和它的网络参数,可以看到bridge 插件返回了我们给这个lmxia 这个netns 下的eth12 这个网卡设置的网络参数。

    [root@VM-0-15-centos netns]# cd ~/lmxia
    [root@VM-0-15-centos lmxia]# ls
    bridge  cni  cni-amd64-v0.4.0.tgz  cnitool  dhcp  flannel  go1.15.2.linux-amd64.tar.gz  host-local  ipvlan  loopback  macvlan  noop  ptp  tuning
    [root@VM-0-15-centos lmxia]# CNI_COMMAND=ADD CNI_CONTAINERID=1234567890 CNI_NETNS=/var/run/netns/lmxia CNI_IFNAME=eth12 CNI_PATH=`pwd` ./bridge < /etc/cni/net.d/mybridge.conf
    2020/09/28 10:44:33 Error retriving last reserved ip: Failed to retrieve last reserved ip: open /var/lib/cni/networks/mybridge/last_reserved_ip: no such file or directory
    {
        "ip4": {
            "ip": "10.15.20.2/24",
            "gateway": "10.15.20.1",
            "routes": [
                {
                    "dst": "0.0.0.0/0"
                },
                {
                    "dst": "1.1.1.1/32",
                    "gw": "10.15.20.1"
                }
            ]
        },
        "dns": {}
    
    1. 接着看下是不是在主机的network namespace 下是不是有了veth pair 的另一端?我们发现,br0 这个网桥的确已经master了这个pair 的另一端veth82e59ec2。且网卡配置,和路由设置都很OK。
    [root@VM-0-15-centos ~]# brctl show br0
    bridge name	bridge id		STP enabled	interfaces
    br0		8000.0a580a0f1401	no	veth82e59ec2
    [root@VM-0-15-centos ~]# ip netns exec lmxia ip a
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    3: eth12@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
        link/ether 0a:58:0a:0f:14:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 10.15.20.2/24 scope global eth12
           valid_lft forever preferred_lft forever
        inet6 fe80::241f:52ff:fe0d:f5b8/64 scope link
           valid_lft forever preferred_lft forever
    [root@VM-0-15-centos ~]# ip netns exec lmxia route -n
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
    0.0.0.0         10.15.20.1      0.0.0.0         UG    0      0        0 eth12
    1.1.1.1         10.15.20.1      255.255.255.255 UGH   0      0        0 eth12
    10.15.20.0      0.0.0.0         255.255.255.0   U     0      0        0 eth12
    

3. 创建一个pause 容器,其网络为none。

在上一步,我们看到bridge 这个插件,需要传入容器的id 和 netns。

  1. 我先创建一个pause 容器,给它设置下network namespace。
    [root@VM-0-15-centos ~]# contid=$(docker run -d --net=none busybox:latest /bin/sleep 10000000)
    [root@VM-0-15-centos ~]# echo $contid
    f21731d52dbe402a39c6b20d7a84fa4490327f51efc3d70e0b088b928a7aff95
    [root@VM-0-15-centos ~]# pid=$(docker inspect -f '{{ .State.Pid }}' $contid)
    [root@VM-0-15-centos ~]# echo $pid
    19394
    [root@VM-0-15-centos ~]# netnspath=/proc/$pid/ns/net
    
  2. 一个小插曲,这时虽然我们已经创建出了新的network namespace,却不能通过ip netns list 命令看到。这是因为默认docker把创建的网络命名空间链接文件隐藏起来了,导致ip netns命令无法读取,给分析网络原理和排查问题带来了麻烦。我们做一个简单的link 就可以。
    	[root@VM-0-15-centos lmxia]# ln -s /proc/$pid/ns/net /var/run/netns/pause1
    	[root@VM-0-15-centos lmxia]# ip netns list
    	pause1 (id: 3)
    	lmxia (id: 2)
    	ns2 (id: 1)
    	ns1 (id: 0)
    	[root@VM-0-15-centos lmxia]# ip netns exec pause1 ip a
    	1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    	3: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
        link/ether 0a:58:0a:0f:14:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 10.15.20.3/24 scope global eth0
           valid_lft forever preferred_lft forever
    

4. 创建一个容器,加入到pause 容器的网络命名空间中

  1. 这一步就是临门一脚了,我们可以看到,由于当前容器和pause 容器同属一个network namespace 因此,这个容器的网络配置和上边的pause容器完全相同。
    [root@VM-0-15-centos lmxia]# docker run --net=container:$contid --rm busybox:latest ifconfig
    eth0      Link encap:Ethernet  HWaddr 0A:58:0A:0F:14:03
              inet addr:10.15.20.3  Bcast:0.0.0.0  Mask:255.255.255.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:8 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0
              RX bytes:656 (656.0 B)  TX bytes:0 (0.0 B)
    
    lo        Link encap:Local Loopback
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
  2. ping 下看看,我们在当前这个pause 容器里ping 下 第一步配置的地址,我们可以看到,是没问题的。如果你ping 不通,可以上下是不是iptables 的forward 链给drop掉了。
    [root@VM-0-15-centos lmxia]# docker exec -it f21731d52dbe ping 10.15.20.2
    PING 10.15.20.2 (10.15.20.2): 56 data bytes
    64 bytes from 10.15.20.2: seq=0 ttl=64 time=0.133 ms
    ^C
    --- 10.15.20.2 ping statistics ---
    1 packets transmitted, 1 packets received, 0% packet loss
    round-trip min/avg/max = 0.133/0.133/0.133 ms
    

5. 总结

我们用docker 的方式,结合CNI插件,演示了kubernetes 如何利用CNI插件去管理容器网络的过程。那么在容器的创建过程中,是什么承担了,我们敲命令的过程呢?是CRI。

kubernetes 使用了 CNI 网络插件之后,工作过程是这样的:

  • kubelet 的CRI 先创建 pause 容器生成对应的 network namespace
    调用网络 driver(因为配置的是 CNI,所以会调用 CNI 相关代码)
  • CNI driver 根据配置调用具体的 cni 插件
  • cni 插件给 pause 容器配置正确的网络
  • pod 中其他的容器都是用 pause 的网络

和我们手工的操作过程如出一辙。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值