一、命令介绍

  ip netns 命令是用来管理 网络命名空间 的,网络命名空间可以实现 网络隔离。每个网络命名空间都提供了一个完全独立的网络协议栈,包括网络设备接口、IPV4 和 IPV6 协议栈、IP路由表、防火墙规则、端口、sockets 等。像 docker 就是利用 Linux 的网络命名空间来实现容器网络的隔离。

用法 含义
ip netns list 列出网络命名空间。此命令显示的是 "/var/run/netns" 中的所有网络命名空间。
ip netns add NAME 添加网络命名空间
ip [-all] netns delete [NAME] 删除网络命名空间
ip [-all] netns exec [NAME] cmd … 在指定的网络命名空间中执行命令
ip netns set NAME NETNSID 给网络命名空间分配id
ip netns identify [PID] 查看进程的网络命名空间
ip netns monitor 监控对网络命名空间的操作
ip netns pids NAME 查找使用此网络命名空间并将其作为主要网络命名空间的进程。此命令会从 /proc 目录中遍历。

二、示例演示

添加并列出network space,随后删除所有的network space。

root@cp:~# ip netns add test1
root@cp:~# ip netns add test2
root@cp:~# ip netns ls
test2
test1
root@cp:~# ip -all netns del
root@cp:~# ip netns ls

创建的网络命名空间是可以在 /var/run/netns 路径下看到。

root@cp:~# cd /var/run/netns/
root@cp:/var/run/netns# ls
test1  test2

使用 exec 命令在网络命名空间中执行命令,查看 test1 的网卡信息

root@cp:~# ip netns exec test1 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

网络命名空间除了网络是虚拟的以外,文件系统完全和当前系统共享,也就是说所有本地可以使用的命令都可以在网络命名空间中使用。

root@cp:~# ip netns exec test1 ls
app  backup.tar  cp1  perf.data  registry_latest.tar  test  test_0.1.tar  test-bind  ubuntu-test.tar
root@cp:~# ip netns exec test1 pwd
/root

进入网络命名空间可以用 exec 执行 bash 即可。

root@cp:~# ip netns exec test1 bash
root@cp:~# 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

–all 选项可以在所有网络命名空间中执行命令。

root@cp:~# ip -all netns exec ip a

netns: test2
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

netns: test1
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


  使用 ip netns set NAME NETNSID 给网络命名空间分配ID。该ID仅在当前网络命名空间中有效,如果指定了关键字“ auto”,则将会自动选择一个可用的nsid。内核将在某些 netlink 消息中使用此ID,如果在内核需要时未分配ID,则它将由内核自动分配。注意 ID 分配后,将无法更改。

root@cp:~# ip netns add cp
root@cp:~# ip netns 
cp
root@cp:~# ip netns set cp 6
root@cp:~# ip netns 
cp (id: 6)


使用 ip netns monitor 监控网络命名空间的添加和删除事件,只能监控添加和删除。

root@cp:~# ip netns del cp
root@cp:~# ip netns add cp

另一个终端同步反馈的

root@cp:~# ip netns monitor
delete cp
add cp


  以下两个示例以 docker 容器为例,在没做一些设置前,使用 ip netns 命令是无法管理分配给 docker 容器的网络命名空间,至于如何使用 ip netns 命令管理分配给容器的网络命名空间,下面扩展中有介绍到。在做下面示例时请先做好以下设置。

root@cp:~# docker run -itd --name test centos
7ec02643b32d1c53b39126f6d603b72a402597d938ddef35e7bdb4076763c68f
root@cp:~# ip netns list    # 查看为空
root@cp:~# 
root@cp:~# ln -s /proc/11421/ns/net /var/run/netns/test
root@cp:~# ip netns list
test (id: 0)

  使用 ip netns identify 命令查看容器 test 的网络命名空间。使用 ip netns pids 命令查找使用该网络命名空间的进程。

root@cp:~# ip netns identify 11421
test
root@cp:~# ip netns pids test
11421

三、扩展

1、网络命名空间的连接

  创建一对 veth pair 虚拟网络设备接口,然后将其分别分配给两个网络命名空间,去连接两个网络命名空间。
  注:veth-pair 是一对的虚拟网络设备接口,它都是成对出现的,所以它常常充当着一个桥梁,我们可以用它实现 “网络命名空间之间的连接”、“Docker 容器之间的连接” 、“Docker 容器和网桥间的连接” 等等。

root@cp:~# ip link add name net1 type veth peer name net2
root@cp:~# 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:a9:42:0e brd ff:ff:ff:ff:ff:ff
    inet 192.168.18.25/24 brd 192.168.18.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::c75c:21df:8db2:598e/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:2c:d7:37:17 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:2cff:fed7:3717/64 scope link 
       valid_lft forever preferred_lft forever
19: net2@net1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether e2:3c:d5:80:93:3c brd ff:ff:ff:ff:ff:ff
20: net1@net2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether f2:f1:b8:34:4a:9a brd ff:ff:ff:ff:ff:ff

将两个虚拟接口迁移到对应的网络命名空间里。

root@cp:~# ip link set net1 netns test1
root@cp:~# ip link set net2 netns test2
root@cp:~# ip -all netns exec ip a

netns: test2
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
19: net2@if20: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether e2:3c:d5:80:93:3c brd ff:ff:ff:ff:ff:ff link-netnsid 0

netns: test1
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
20: net1@if19: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether f2:f1:b8:34:4a:9a brd ff:ff:ff:ff:ff:ff link-netnsid 1

给两块网卡设置ip并启动

root@cp:~# ip netns exec test1 ip addr add local 192.168.100.1/24 dev net1
root@cp:~# ip netns exec test2 ip addr add local 192.168.100.2/24 dev net2
root@cp:~# ip netns exec test1 ifconfig net2 up
root@cp:~# ip netns exec test2 ifconfig net2 up
root@cp:~# ip -all netns exec ip a

netns: test2
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
19: net2@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether e2:3c:d5:80:93:3c brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.100.2/24 scope global net2
       valid_lft forever preferred_lft forever
    inet6 fe80::e03c:d5ff:fe80:933c/64 scope link 
       valid_lft forever preferred_lft forever

netns: test1
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
20: net1@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f2:f1:b8:34:4a:9a brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 192.168.100.1/24 scope global net1
       valid_lft forever preferred_lft forever
    inet6 fe80::f0f1:b8ff:fe34:4a9a/64 scope link 
       valid_lft forever preferred_lft forever

ping 测试通信

root@cp:~# ip netns exec test1 ping 192.168.100.2
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=0.275 ms
64 bytes from 192.168.100.2: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 192.168.100.2: icmp_seq=3 ttl=64 time=0.043 ms
^C
--- 192.168.100.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms
rtt min/avg/max/mdev = 0.043/0.121/0.275/0.109 ms

2、关于docker网络命名空间的问题

  当 docker 容器被创建出来后,你会发现使用 ip netns 命令无法看到容器对应的网络命名空间。这是因为 ip netns 命令是从 /var/run/netns 文件夹中读取内容的,而 docker 容器的网络命名空间不是在 /var/run/netns 下,而是位于 /proc/[pid]/ns/net。想要使用 ip netns 命令去管理 docker 容器的网络命名空间,就需要将它的网络命名空间显示在 /var/run/netns 目录下,那就要先找到容器的网络命名空间在哪里,然后做一个软链接即可。

首先查询容器的PID。

root@cp:~# docker inspect --format '{{.State.Pid}}' web
4775

然后创建软链接,建议指定在 /var/run/netns/ 中的名字,因为每个容器都是net。

root@cp:~# ln -s /proc/4775/ns/net /var/run/netns/web
root@cp:~# ip netns ls
web (id: 0)
test2 (id: 2)
test1 (id: 1)

此时就可以用 ip netns 命令去管理 docker 容器的网络命名空间了。

发表评论

验证码: − 5 = 4