Linux namespace之:network namespace
目录:
- Linux namespace概述
- Linux namespace之:uts namespace
- Linux namespace之:mount namespace
- Linux namespace之:pid namespace
- Linux namespace之:network namespace
- Linux namespace之:user namespace
理解network namespace
network namespace用来隔离网络环境,在network namespace中,网络设备、端口、套接字、网络协议栈、路由表、防火墙规则等都是独立的。
因network namespace中具有独立的网络协议栈,因此每个network namespace中都有一个lo接口,但lo接口默认未启动,需要手动启动起来。
1 | # -n或--net选项用于创建network namespace |
让某个network namespace和root network namespace或其他network namespace之间保持通信是一个非常常见的需求,这一般通过veth虚拟设备实现。veth类型的虚拟设备由一对虚拟的eth网卡设备组成,像管道一样,一端写入的数据总会从另一端流出,从一端读取的数据一定来自另一端。
用户可以将veth的其中一端放在某个network namespace中,另一端保留在root network namespace中。这样就可以让用户创建的network namespace和宿主机通信。
例如:
1 | ##### 在第一个shell窗口 |
但现在ns1还不能和公网通信。解决这个问题也很简单,在root network namespace中开启转发并设置SNAT,在ns1中添加默认路由即可。
1 | ##### 在root network namespace中执行 |
持久化的network namespace
正常情况下,当namespace中的所有进程都退出后,namespace也会随之销毁。但有时候需要让namespace即使没有进程在其中运行也依然有效,即namespace的持久化。例如,创建了network namespace后,想要让network namespace中的网络配置一直生效。
实际上,无论是network namespace还是其他类型的namespace,当通过mount bind为某个namespace的namespace文件(/proc/$$/ns/xxx
)进行了bind挂载,这个namespace将成为持久化的namespace,即使namespace中的第一个进程或所有进程都退出了,namespace也不会立即销毁,之后还可以通过nsenter重新进入该namespace。
其实方式很简单,直接在unshare创建namespace时的对应长选项上指定一个已存在的文件即可(注:不允许在短选项上指定文件名)。
1 | unshare: |
例如,想要让network namespace持久化:
1 | # 对于network namespace持久化,通常指定/var/run/netns/NAME作为持久化文件 |
ip netns
ip netns
命令用于管理network namespace。
ip netns将network namespace与/var/run/netns/NAME相关联,将/var/run/netns下的每一个NAME作为其所管理的每一个network namespace的名称。
ip netns将/etc/netns/NAME/作为对应network namespace的全局网络配置文件的目录,查找它之后才会查找/etc/目录。
例如,如果想要为netns名为ns1的network namespace单独设置DNS,可创建/etc/netns/ns1/resolv.conf,并将DNS相关配置写入该文件,当该文件不存在时才查找/etc/resolv.conf。
ip netns创建network namespace时,同时会创建mount namespace,以便将网络相关配置文件/etc/netns/NAME/xxx挂载到对应的/etc/xxx。
ip netns add NAME
创建名为NAME的network namespace,同时会关联/var/run/netns/NAME文件,如果文件不存在,则会自动创建1
2
3$ sudo ip netns add ns2
$ ls -i /var/run/netns/ns2
4026532759 /var/run/netns/ns2ip netns list
列出/var/run/netns下的所有network namespace1
2
3
4
5# 带有id的,表示正在运行(即有进程尚未退出)的network namespace以及它的ID号
# ID会自动分配,从0开始,后面通过ip netns命令也可以自己设置ID号
$ ip netns list
ns2
ns1 (id: 0)ip netns attach NAME PID
将PID对应的network namespace关联到/var/run/netns/NAME(不存在时会自动创建),使得该network namespace就像是被ip netns创建一样,之后它将受ip netns管理1
2
3
4
5
6
7
8
9# 在第一个窗口中执行
# 使用unshare而非ip netns创建一个network namespace
$ sudo unshare -n /bin/bash
root@longshuai-vm:/home/longshuai# echo $$
5094
# 在第二个窗口中执行
# 现在这个network namespace就像是由ip netns创建一样
$ sudo ip netns attach ns3 5094ip [-all] netns delete [ NAME ]
删除/vaer/run/netns/下指定的network namespace,如果指定了–all,则删除/var/run/netns下所有的network namespace。注意,它同时会卸载mount bind的挂载点/var/run/netns/NAME并删除该文件。1
2
3
4
5
6
7
8
9
10
11$ ip netns list
ns3
ns2
ns1 (id: 0)
$ sudo ip netns del ns3
$ ls /var/run/netns
ns1 ns2
$ sudo ip --all netns del
$ ls /var/run/netnsip netns set NAME NETNSID
为/var/run/netns/NAME对应的network namespace设置ID号。1
2
3
4
5
6
7$ sudo ip netns add ns1
$ ip netns list
ns1
$ sudo ip netns set ns1 11
$ ip netns list
ns1 (id: 11)ip netns identify [PID]
根据PID,输出该PID所在的network namespace的netns name。1
2
3
4
5
6
7
8
9$ ip netns list
ns1 (id: 11)
$ sudo nsenter --net=/var/run/netns/ns1 /bin/bash
root@longshuai-vm:/home/longshuai# echo $$
5298
# 在另一个窗口中查询进程PID=5298在哪一个network namespace中
$ sudo ip netns identify 5298
ns1ip netns pids NAME
输出networ namespace中当前正在运行的所有进程PID1
2$ sudo ip netns pids ns1
5298ip [-all] netns exec [ NAME ] cmd …
在指定的network namespace中执行命令CMD。如果指定了–all选项,则CMD命令将在/var/run/netns/下的所有network namespace中都执行。1
2$ sudo ip netns exec ns1 ip link set lo up
$ sudo ip netns exec ns1 ping www.baidu.com
注:如果/etc/netns/NAME下有配置文件,执行ip netns exec命令时会自动将其bind到/etc/下对应的配置文件上。此时还需注意,systemd管理的/etc/resolv.conf是一个软链接,ip netns直接bind时会失败,将其移除后再创建普通文件类型的/etc/resolv.conf才可bind成功。
1 | $ sudo mkdir -p /etc/netns/ns1 |