概述

最近在看docker相关的东西,偶然了解了一下docker网络相关的知识,因此趁机学习一把linux network namespace相关的知识,后面有时间了会慢慢的补齐。

详解

linux 网络namespace包含了六种,如下图所示: 默认情况下docker使用的是network namespace,我也先从network namespace着手来详细了解相关的知识。 network namespace在逻辑上是网络堆栈的一个副本,其有自己的路由、防火墙规则以及相关的网络设备。默认的情况下 子进程继承父进程的network namespace,每创建一个network namespace都会生成一个环回地址lo,并且network namespace 中的设备也是私有的。

示例

示例中我首先会通过docker启动一个centos的服务器来演示整个过程,毕竟这样可以很方便的还原现场。 通过Dockerfile构建一个完备的景象(说明:如果直接使用仓库中的镜像的话,会有很多功能都被阉割

1
2
3
FROM fedora:25

CMD /sbin/init

在编写好上面的文件之后,我们通过命令行来构建即可:

1
2
3
docker build -t os .
docker run -d --privileged --name os os
docker exec -it os bash

执行完上述代码之后,我们就可以以中断的方式进入centos的系统了。

创建network namespace

首先我们可以查看当前的network namespace,现实结果如下:

1
2
[root@f915072d75e8 /]# ip netns ls
[root@f915072d75e8 /]#

可以看到当前没有network namespace,接下来我们来创建一个namespace,并查看创建结果:

1
2
3
[root@59950cdb5d31 /]# ip netns add net1
[root@59950cdb5d31 /]# ip netns ls
net1

接下来我们继续看一下对应的目录下/var/run/netns下面是否新建了对应的namespace:

1
2
3
4
5
[root@59950cdb5d31 /]# ls -al /var/run/netns/
total 0
drwxr-xr-x 2 root root 60 Jul 20 17:10 .
drwxr-xr-x 15 root root 340 Jul 20 17:10 ..
-r--r--r-- 1 root root 0 Jul 20 17:10 net1

接下来我们看一下新建的这个namespace都有什么吧:

1
2
3
4
5
6
7
[root@59950cdb5d31 /]# ip netns exec net1 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1
link/tunnel6 :: brd ::

如上,我们看到除了lo之外,还有两个网络,那么这两个网络是如何来的呢?应该就是从父进程继承过来的

接下来我们看一下两个network namespace之间是如何进行通信的吧。我们只需要按照上面的步骤再添加 一个namespace即可,如下:

1
2
3
4
[root@59950cdb5d31 /]# ip netns add net0
[root@59950cdb5d31 /]# ip netns ls
net0
net1

需要注意的是新创建的namespace默认不能和主机通信,也不能和其他的namespace通信,对于这种情况,linux给 我们提供了veth pair来完成通信,如下,显示了两个namespace之间的网络拓扑:

为了完成上述网络拓扑的定制,我们需要创建一对veth pair(删除一个,另外一个会自动删除,这里是 成对出现的),具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@59950cdb5d31 /]# ip link add type veth
[root@59950cdb5d31 /]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/tunnel6 :: brd ::
4: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 3a:60:e7:2a:02:38 brd ff:ff:ff:ff:ff:ff
5: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 5a:e0:6a:c6:62:d5 brd ff:ff:ff:ff:ff:ff
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0

完成上述操作后我们可以看到已经成功添加了一堆veth:veth0、veth1,接下来我们将veth分别加入对应的namaspace中,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@59950cdb5d31 /]# ip link set veth0 netns net0
[root@59950cdb5d31 /]# ip link set veth1 netns net1
[root@59950cdb5d31 /]# ip netns exec net0 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/tunnel6 :: brd ::
4: veth0@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 3a:60:e7:2a:02:38 brd ff:ff:ff:ff:ff:ff link-netns net1
[root@59950cdb5d31 /]# ip netns exec net1 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/tunnel6 :: brd ::
5: veth1@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 5a:e0:6a:c6:62:d5 brd ff:ff:ff:ff:ff:ff link-netns net0

上面我们看到虽然已经将veth成功的加入对应的namespace中了,但是依然存在一个问题,对应的veth依然是没有ip的情况,因此我们为其指定ip:

1
2
[root@59950cdb5d31 /]# ip netns exec net0 ip addr add 192.168.1.1/24 dev veth0
[root@59950cdb5d31 /]# ip netns exec net1 ip addr add 192.168.1.1/24 dev veth1

不过,对应的veth依然是down并且没有对应的ip,如下:

1
2
3
4
5
6
7
8
9
[root@59950cdb5d31 /]# ip netns exec net1 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/tunnel6 :: brd ::
5: veth1@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 5a:e0:6a:c6:62:d5 brd ff:ff:ff:ff:ff:ff link-netns net0

最后我们分别启动两个veth,并执行ping操作即可发现两个namespace已经联通了

1
ip netns exec net0 ip link set dev veth0 up

总结

时间关系,本次小结比较仓促,后面有时间再慢慢研究linux网络相关的知识。