1 网络虚拟化基石 network namespace
Linux的namespace的作用就是"隔离内核资源".
在Linux的世界里,文件系统挂载点、主机名、POSIX进程间通信消息队列、进程PID数字空间、IP地址、userID数字空间等全局系统资源被namespace分割,、装到一个个抽象的独立空间里。
而隔离上述系统资源的namespace分别是Mount namespce、UTS namespace、IPC namespace、PID namespace、network namespace 和user namespace。
对于进程来说,要想使用namespace里面的资源,首先要“进入”到这个namespace,而且还无法跨namespace访问资源。
Linux的namespace给里面的进程造成了两个错觉:
(1) 它是系统里的唯一进程。
(2)它独享系统的所有资源。
默认情况下,Linux进程处在和宿主机相同的namespace,即初始的根namespace里,默认享有全局系统资源
network namespace,在Linux内核2.6版本引入,作用是隔离Linux系统的设备,以及IP地址、端口、路由表、防火墙规则等网络资源。
因此,每个网络namespace里都有自己的网络设备(如IP地址、路由表、端口范围、/proc/net目录等)。
也因此,容器里的进程可以放心地绑定在端口上而不必担心冲突,使得一个主机上同时运行多个监听80端口的web服务器变成可能。
1.1 初始network namespace
network namespace 的增删改查功能已经集成到Linux的ip工具netns命令中
# 创建network namepspace
[root@boc119 ~]# ip netns add netns1
# 在/var/run/netns 路径下生成一个挂载点,
# 挂载点作用
# (1)方便namespace管理
# (2)使namespace即使没有进程运行也能继续存在
[root@boc119 ~]# cd /var/run/netns/
[root@boc119 netns]# ls
netns1
# ip netns exec 命令进入,做一些网络查询配置工作
# 如下,查询网卡信息的命令,(只有一块系统默认的本地回环设备lo)
[root@boc119 netns]# ip netns exec netns1 ip link list
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@boc119 netns]# s
# 查询及删除
[root@boc119 netns]# ip netns list
netns1
[root@boc119 netns]# ip netns delete netns
Cannot remove namespace file "/var/run/netns/netns": No such file or directory
[root@boc119 netns]# ip netns delete netns1
[root@boc119 netns]#
# 注意以上delete并不一定删除netns1只是移除了对应的挂载点,只要里面还有进程运行着,network namespace便一直存在
1.2 配置 network namespace
# 全新 network namespace 会附带创建一个本地回环地址,这个自带的lo设备状态还是DOWN的
# 因此,尝试访问本地回环地址时,网络也是不通的。
[root@boc119 netns]# ip netns exec netns1 ip link list
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@boc119 netns]#
[root@boc119 netns]# ip netns exec netns1 ping 127.0.0.1
connect: Network is unreachable
[root@boc119 netns]#
# 将设备状态设置UP,即可访问本地回环地址
[root@boc119 netns]# ip netns exec netns1 ip link set dev lo up
[root@boc119 netns]# ip netns exec netns1 ip link list
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
[root@boc119 netns]# ip netns exec netns1 ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.062 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.060 ms
^C
--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.060/0.066/0.077/0.010 ms
[root@boc119 netns]#
仅有一个本地回环设备是没法与外界通信的。如果我们想与外界(比如主机网卡)进行通信,
就需要在namespace里再创建一对虚拟的以太网卡,即所谓的veth pair。
veth pair 总是成对出现且互相连接,他就像Linux的双向管道(pipe),报文从veth pair 一端进去就会从另一端收到。
下面创建一对虚拟以太网卡veth0和veth1,然后把veth pair 的一端放到netns1 network namespace。
[root@boc119 netns]# ip link add veth0 type veth peer name veth1
[root@boc119 netns]# ip link set veth1 netns netns1
[root@boc119 netns]#
默认,他们都在主机根 network namespace中,将其中一块虚拟网卡veth1通过ip link set 命令移动到netns network namespace中
那么,veth0和veth1之间能通信吗?
还不能,因为这两块网卡刚创建出来还都是DOWN的状态,需手动设UP。
与对lo网卡设置类似,只是多一步绑定IP地址。
# veth1 绑定ip
[root@boc119 netns]# ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up
[root@boc119 netns]# ifconfig vet0 10.1.1.2/24 up
SIOCSIFADDR: No such device
vet0: ERROR while getting interface flags: No such device
vet0: ERROR while getting interface flags: No such device
SIOCSIFNETMASK: No such device
# veth0 绑定ip
[root@boc119 netns]# ifconfig veth0 10.1.1.2/24 up
[root@boc119 netns]#
由此即可ping通veth pair的任意一头了
root@boc119 netns]# ifconfig veth0 10.1.1.2/24 up
[root@boc119 netns]# ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.114 ms
64 bytes from 10.1.1.1: icmp_seq=2 ttl=64 time=0.048 ms
^C
--- 10.1.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.048/0.081/0.114/0.033 ms
[root@boc119 netns]# ip netns exec netns1 ping 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.080 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.073 ms
^C
--- 10.1.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.073/0.076/0.080/0.009 ms
[root@boc119 netns]#
[root@boc119 netns]#
另外,不同namespace之间路由表和防火墙规则等也是隔离的。
因此 netns1 无法和主机共享路由表和防火墙。
测试:
[root@boc119 netns]# ip netns exec netns1 route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 veth1
[root@boc119 netns]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 100 0 0 eth0
10.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 veth0
link-local 0.0.0.0 255.255.0.0 U 1003 0 0 eth1
172.32.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.1.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
[root@boc119 netns]#
[root@boc119 netns]# ip netns exec netns1 iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
netns1 空的路由表及iptables规则,意味着从netns1法包到因特网是徒劳的。
[root@boc119 netns]# ip netns exec netns1 ping www.baidu.com
ping: www.baidu.com: Name or service not known
[root@boc119 netns]# ping www.baidu.com
PING www.wshifen.com (103.235.46.39) 56(84) bytes of data.
64 bytes from 103.235.46.39 (103.235.46.39): icmp_seq=1 ttl=46 time=205 ms
^C
--- www.wshifen.com ping statistics ---
2 packets transmitted, 1 received, 50% packet loss, time 1001ms
rtt min/avg/max/mdev = 205.304/205.304/205.304/0.000 ms
netns1想连接因特网,有若干办法。
可以在主机根network namespace创建一个Linux网桥并绑定veth pair的一端到网桥上;
也可以通过适当的NAT(网络地址转换)规则并辅以Linux的IP转发功能(配置net.ipv4.ip_forward=1)
非root进程被分配到network namespace后只能访问和配置已经存在于该ns的设备。
root进程可以在ns里创建新的网络设备。
ns里的root进程还能把本ns的虚拟网络设备分配到其他ns。
# ip netns exec netns1 ip link set veth1 netns 1
理解:
(1) ip netns exec netns1 进入 netns1 namespace
(2)ip link set veth1 netns 1 把 netns1 network namespace 下的veth1网卡移到PID为1的进程(即init进程)所在的network namespace。
通常,init进程都在主机的根network naemspace下运行,因此上面命令就是把veth1从netns1 network namespace移动到系统根network namespace。
有两种途径索引network namespace: 名字(例如netns1)或者属于该namespace的进程PID,上文中用的就是后者。
对于 namespace的rooot用户而言,以上移动虚拟网络设备到其他network namespace,甚至主机根network namespace!这就带来潜在的安全风险。
如果用户希望屏蔽这一行为,则需要结合PID namespace和Mount namespace的隔离特性做到network namespace之间完全不可达。
1.3 network namespace API的使用
-
创建namespace的黑科技: clone系统调用
-
维持namespace存在:/proc/PID/ns 目录的奥秘
每一个Linux进程都拥有属于自己的/proc/PID/ns,这个目录下的每个文件都代表一个类型的namespace。
[root@boc119 ns]# cd /proc/27236/ns
[root@boc119 ns]# ls
ipc mnt net pid user uts
[root@boc119 ns]#
# /proc/PID/ns 这个目录下的文件在3.8 Linux内核3.8之前都是硬链接(hard link),而且只有ipc、net和uts这三个文件
# 3.8 之后,每个文件都是一个特殊的符合链接文件
# 这些文件提供了操作进程关联namespace的一种方式
[root@boc119 ns]# ls -l
total 0
lrwxrwxrwx 1 root root 0 Jul 4 16:31 ipc -> ipc:[4026532928]
lrwxrwxrwx 1 root root 0 Jul 4 16:31 mnt -> mnt:[4026532959]
lrwxrwxrwx 1 root root 0 Jul 4 16:31 net -> net:[4026532244]
lrwxrwxrwx 1 root root 0 Jul 4 16:31 pid -> pid:[4026532960]
lrwxrwxrwx 1 root root 0 Jul 4 16:31 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul 4 16:31 uts -> uts:[4026531838]
[root@boc119 ns]#
#符号链接
#用途一: 确定某两个进程是否属于同一namespace。
#如果属于同一namespace下,那么这个两个进程/proc/PID/ns 目录下对应符号链接文件的inode数字([]内的数字)是一样的。
#也可以通过stat()系统调用返回结构体的st_info字段判断。
#用途二:只要这些文件描述符保持open状态,对应namespace就会一直存在,哪怕这个namespace里的所有进程都终止运行了。
#之前版本Linux内核想要保持namespace存在,需要在其中放一个进程(不一定是运行中的)
#现在Linux内核提供黑科技允许: 只要打开文件描述符,不需要进程存在也能保持namespace存在!
怎么操作?
touch /my/net 新建一个文件
mount --bind /proc/$$/ns/net /my/net
把/proc/PID/ns目录下的文件挂载起来就能起到打开文件描述符的作用,而且这个network namespace 会一直存在,直到/proc/self/ns/net被卸载。
- 往namespace里添加进程:setns系统调用
- 帮助进程逃离namespace:unshare系统调用
小结
通过Linux的network namespace 技术可以自定义一个独立的网络栈,
简单到只有loopback设备,复杂到具备系统完整的网络能力,这就使得network namespace成为Linux网络虚拟化技术的基石。
network namespace的另一个隔离功能在于,系统管理员一旦禁用namespace中的网络设备,即使里面进程拿到了一些系统权限,也无法和外界通信。
即使network namespace 能够提供网络资源隔离的机制,用户还是会结合其他类型的namespace一起使用,以提供更好的安全隔离能力。
总结自 <<kubernetes网络权威指南>> 杜军