Cgroup和Namespace在测试中的使用(下)
閱讀本文約花費: 7 (分鐘)
Namespace介绍
使用Namespace又叫做命名空间,可以让每个进程组具有独立的PID、IPC和网络空间等,也就是说这些系统资源不再是全局性的,而是属于特定的Namespace,每个Namespace里面的资源对其他Namespace都是透明的,从而达到资源的隔离效果。
目前namespace的种类如下分类 系统调用参数Mount namespaces CLONE_NEWNSUTS namespaces CLONE_NEWUTSIPC namespaces CLONE_NEWIPCPID namespaces CLONE_NEWPIDNetwork namespaces CLONE_NEWNETUser namespaces CLONE_NEWUSER
可以查看自己的系统支持哪些namespace# ls -lai /proc/1/nstotal 0418834 dr-x–x–x 2 root root 0 Jul 30 22:58 .1301 dr-xr-xr-x 9 root root 0 Jul 25 22:46 ..418853 lrwxrwxrwx 1 root root 0 Jul 30 22:58 ipc -> ipc:[4026531839]418856 lrwxrwxrwx 1 root root 0 Jul 30 22:58 mnt -> mnt:[4026531840]418851 lrwxrwxrwx 1 root root 0 Jul 30 22:58 net -> net:[4026531957]418854 lrwxrwxrwx 1 root root 0 Jul 30 22:58 pid -> pid:[4026531836]418855 lrwxrwxrwx 1 root root 0 Jul 30 22:58 user -> user:[4026531837]418852 lrwxrwxrwx 1 root root 0 Jul 30 22:58 uts -> uts:[4026531838]
各namespace的功能简述如下:
- IPC namespaces
在一个 IPC 命名空间里面创建的 IPC 对象对该命名空间内的所有进程可见,但是对其他命名空间不可见。这样就使得不同命名空间之间的进程不能直接通信,就像是在不同的系统里一样。 - MNT namespaces
MNT namespace是处理挂载点的,可以使不同容器拥有不同的挂载的文件系统和 root 目录。在一个MNT namespace 挂载的文件系统只能被同一个 namespace 里的进程所见。 - UTS namespaces
UTS namespace提供了主机名和域名的隔离,这样每个容器就可以拥有了独立的主机名和域名,在网络上可以被视作一个独立的节点而非宿主机上的一个进程 - User namespaces
User namespace是最新的子用户空间,它允许你创建独立于其他namespace之外的用户。这是通过GID和UID映射实现的。 - PID namespaces
一个PID Namespace为进程提供了一个独立的PID环境,PID Namespace内的PID将从1开始,在Namespace内调用fork,vfork或clone都将产生一个在该Namespace内独立的PID。新创建的Namespace里的第一个进程在该Namespace内的PID将为1,就像一个独立的系统里的init进程一样 - Network namespaces
主要提供了关于网络资源的隔离,包括网络设备、IPv4和IPv6协议栈、IP路由表、防火墙、/proc/net目录、/sys/class/net目录、端口(socket)等等。一个物理的网络设备最多存在在一个network namespace中,你可以通过创建veth pair(虚拟网络设备对:有两端,类似管道,如果数据从一端传入另一端也能接收到,反之亦然)在不同的network namespace间创建通道,以此达到通信的目的。
一般来说,由于创建namespace需要通过调用系统函数实现,如用clone函数创建一个独立namespace的进程int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);
所以使用上并不平易近人,而Network namespaces可以通过命令配置,且使用的场景较多,故下面详细介绍Network namespaces
Network namespaces简单实战
增加一个network namespace的命令如下ip netns add <network namespace name>
如增加一个名叫mltest的network namespace# ip netns add mltest
查看一下# ip netns listmltest
也可以删除# ip netns delete mltest
现在在这个namespace中做下ip addr,发现已默认创建一个回环设备(loopback interface:lo),通用的net namespace下的操作命令为ip netns exec [comand]
# ip netns exec mltest ip addr1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group defaultlink/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
这里创建一个网络设备对, 为虚拟设备,用于2个namespace之间的网络通信,可以看到多出了2个设备veth0,veth1# ip link add veth0 type veth peer name veth1# ip link list1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group defaultlink/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000link/ether 00:0c:29:72:bb:19 brd ff:ff:ff:ff:ff:ff3: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 46:76:1b:6d:c4:b2 brd ff:ff:ff:ff:ff:ff4: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 7e:da:61:d5:f8:bb brd ff:ff:ff:ff:ff:ff
然后将其中一个分配给刚才的namespace,然后在2个namespache下面各有一个虚拟设备ip link set veth0 netns mltest# ip link list1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group defaultlink/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000link/ether 00:0c:29:72:bb:19 brd ff:ff:ff:ff:ff:ff3: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 46:76:1b:6d:c4:b2 brd ff:ff:ff:ff:ff:ff
# ip netns exec mltest ip link list1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group defaultlink/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:004: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 7e:da:61:d5:f8:bb brd ff:ff:ff:ff:ff:ff
给这2个网络设备用ipconfig命令分配ip# ip netns exec mltest ifconfig veth0 10.1.10.1/24 up# ifconfig veth1 10.1.10.2/24 up
然后namespace mltest的配置基本完成了,在本机已有相同服务的情况下,在namespace里起同样端口的服务也不会有问题
在每块网卡上都能建相同服务netstat -lan|grep 50007tcp 0 0 192.168.231.131:50007 0.0.0.0:* LISTENtcp 0 0 10.1.10.2:50007 0.0.0.0:* LISTEN# ip netns exec mltest ./tcp_server.py &[3] 19502
在namespace中也能创建相同服务# ip netns exec mltest netstat -lanActive Internet connections (servers and established)Proto Recv-Q Send-Q Local Address Foreign Address Statetcp 0 0 10.1.10.1:50007 0.0.0.0:* LISTEN
本机直接访问毫无压力,显示的是从veth1访问的veth0# telnet 10.1.10.1 50007Trying 10.1.10.1…Connected to 10.1.10.1.Connected by (‘10.1.10.2’, 43755)
但是这里只配置了一对网络设备,多个namespace互相访问或者能够对外访问,就需要利用用网桥或NAT了,需要额外配置
通过网络隔离可以解决例如单机模拟多机部署,多实例同一端口不冲突这样的场景; 由于具有隔离性,某一namespace的route和iptables配置并不影响其他namespace里的应用,做异常测试也很适合。玩法很多,有用来做单机自环测试和openvpn多处理的,
国外有人在net namespace基础上做出一个轻量的了网络模拟器CORE
Namespace参考资料
ntroduction to linux namespaces这个系列写的很棒
总结
粗略的介绍了Cgroup和Namespace的基本概念和使用,可使用的场景很多,本文只是抛砖引玉,希望对大家有所启发
via https://www.cnblogs.com/opama/archive/2004/01/13/4712143.html