美文网首页程序员
「深入浅出」理解 Linux Network-Namespace

「深入浅出」理解 Linux Network-Namespace

作者: 聪明的奇瑞 | 来源:发表于2020-12-14 12:02 被阅读0次

    Network-Namespace 是 Linux 内核提供的用于实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,该网络空间内的防火墙、网卡、路由表、邻居表、协议栈与外部都是独立的。不管是虚拟机还是容器,当运行在独立的命名空间时,就像是一台单独的主机一样。**

    下面会通过一些例子来说明网络命名空间,以加深理解,会用到 iproute2 工具包的 ip 命令,需先自行安装,并且使用 root 权限操作。

    1. 在 Centos 下执行如下命令:
    yum install iproute2  
    
    1. 验证安装完成:
    [root@worker3 ~]# ip help
    Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }
           ip [ -force ] -batch filename
    where  OBJECT := { link | address | addrlabel | route | rule | neigh | ntable | tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm | netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila | vrf }
           OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |
                        -h[uman-readable] | -iec |
                        -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |
                        -4 | -6 | -I | -D | -B | -0 |
                        -l[oops] { maximum-addr-flush-attempts } | -br[ief] |
                        -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |
                        -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}
    

    创建网络命名空间

    ip 命令中用于操作网络命名空间的命令是 ip netns,用 help 来查看一下子命令有哪些

    [root@worker3 ~]# ip netns help
    Usage: ip netns list
           ip netns add NAME
           ip netns set NAME NETNSID
           ip [-all] netns delete [NAME]
           ip netns identify [PID]
           ip netns pids NAME
           ip [-all] netns exec [NAME] cmd ...
           ip netns monitor
           ip netns list-id
    

    常用的也就是增删查命令,先来创建一个网络空间空间 ns1

    ip netns add ns1
    

    查看当前所有的网络命名空间

    [root@worker3 ~]# ip netns list
    ns1
    

    在这有些人可能会很困惑,我主机上明明运行中好几个 docker 容器,按理说每个容器都运行在独立的网络命名空间,怎么这里没有列出来?不要着急,下面会提到。

    先来感觉一下什么叫独立的网卡,独立的路由表,要查看 ns1 命名空间的网卡,iproute2 工具提供了命令 ip netns exec ns1,跟在这个命令后面的命令都会在这个网络命名空间中执行。

    先查看一下主机的网卡和路由表

    [root@worker3 ~]# ip link
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
        link/ether 00:50:56:bb:ab:df brd ff:ff:ff:ff:ff:ff
    
    [root@worker3 ~]# ip route
    default via 10.57.4.1 dev eth0
    10.1.2.0/24 dev br0 proto kernel scope link src 10.1.2.1
    

    再看看 ns1 中的网卡和路由表

    [root@worker3 ~]# ip netns exec ns1 ip link
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        
    [root@worker3 ~]# ip netns exec ns3 ip route
    

    这样执行命令有点麻烦,也可以简单一点:

    [root@worker3 ~]#ip netns exec ns1 bash
    //这个命令后执行的命令就都是在ns1中执行了
    [root@worker3 ~]#ip link
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    [root@worker3 ~]#ip route
    

    exit 可以回到主机的默认空间。

    ip netns add的原理

    当我们在主机上执行 ip netns add ns1 后 ,实际是在 /var/run/netns 下创建了一个 ns1 的文件

    [root@worker3 ~]# ls /var/run/netns
    ns1
    

    下面的命令可以模拟 ip netns add ns2 && ip netns exec ns2 bash

    [root@worker3 ~]# touch /var/run/netns/ns2
    [root@worker3 ~]# unshare --net bash
    [root@worker3 ~]# mount --bin /proc/self/ns/net /var/run/netns/ns2
    //上面的过程实际就是执行了ip netns add ns2 && ip netns exec ns2 bash
    
    [root@worker3 ~]# ip link
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    
    [root@worker3 ~]# exit
    //退出,回到主机默认命名空间。用ip netns list查看,已经可以看到ns2
    [root@worker3 ~]# ip netns list
    ns2
    ns1
    //如果想再次进入ns2,还有一个方法:
    [root@worker3 ~]# nsenter --net=/var/run/netns/ns2
    

    从上面的示例可以看出,创建命名的 Network Namespace 其实就是创建一个文件,然后通过绑定挂载的方式将新创建的 Network Namespace 文件和进程的 /proc/self/ns/net 文件绑定。

    查看容器的网络命名空间

    接下来该回答上面的遗留问题,为什么当我在主机上 ip netns list 的时候看不到 docker 的网络命名空间?因为 ip netns list 的时候只会显示在 /var/run/netns 下的文件,而 docker 的文件默认是创建在 /var/run/docker/netns 下的。所以我们可以通过 ls /var/run/docker/netns 来显示当前的所有容器的网络命名空间,并且通过 nsenter --net=/var/run/docker/xxx 来进入容器的网络命名空间。

    [root@worker3 ~]# ls /var/run/docker/netns
    5bbd5f99d403  a2eabf9acccb  b63ec59b3d9e  d6e4ff961713  default
    [root@worker3 ~]# nsenter --net=/var/run/docker/netns/b63ec59b3d9e
    [root@worker3 ~]# ip addr
    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
    4: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
        link/ether fa:a7:8d:05:03:a6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 10.244.0.11/32 scope global eth0
           valid_lft forever preferred_lft forever
    

    如果想查看具体某个 docker 容器对应的文件,可以用:

    docker inspect $CONTAINER_ID$|grep SandboxKey
    

    注意如果是 K8S 拉起来的 docker,要拿非 hostNetwork=true 的 pause 容器来看。如果hostNetwork=true,那么下面的值为 /var/run/docker/netns/default,这是主机的默认网络命名空间。如果不是 pause 容器,那么下面的值为空,因为只有 pause 容器会创建一个新的网络命名空间,其它 container 都只是加入这个网络命名空间。

    [root@worker3 ~]# docker inspect ebd6855901ef|grep SandboxKey
                "SandboxKey": "/var/run/docker/netns/b63ec59b3d9e",
    

    还有另一个办法:

    [root@worker3 ~]# docker inspect nginx|grep Pid
                "Pid": 31817,
                "PidMode": "",
                "PidsLimit": null,
    [root@worker3 ~]# mkdir -p /var/run/netns/
    [root@worker3 ~]# ln -s /proc/31817/ns/net /var/run/netns/ns100
    [root@worker3 ~]# ip netns ls
    ns100
    ns2
    ns1
    [root@worker3 ~]# ip netns exec ns100 bash
    [root@worker3 ~]# //这时候已经在容器网络里了,比nsenter还方便
    

    这个小技巧在我们调试 Pod 的网络时非常有用,大多数时候 Pod 里面自带的工具非常少,没有 curl 没有 telnet,这时候用这个技巧先进入空器的网络空间,再执行命令就行了,因为只是切了网络命名空间,其它还在主机上,所以用的工具也全是主机的工具。

    相关文章

      网友评论

        本文标题:「深入浅出」理解 Linux Network-Namespace

        本文链接:https://www.haomeiwen.com/subject/ojlvgktx.html