Linux Namespace
Linux Namespace
Linux Namespace是一种隔离机制,它将全局系统资源包装起来,使得PID、IPC、Network、Mount、UTS、User、CGroup不再是全局性的,而是属于特定的Namespace。每个Namespace下的资源对于其他Namespace都是不可见的。
一个进程可以属于多个Namespace。
Namespace种类
| namespace 名称 | 系统调用参数 | 含义 | kernel版本 |
|---|---|---|---|
| Mount | CLONE_NEWNS | 隔离一组进程看到的文件系统的挂载点,不同的命名空间可以具有不同的文件系统结构 | 2.4.19 |
| PID | CLONE_NEWPID | 隔离进程编号,PID 命名空间的主要好处之一是容器可以在主机之间迁移,同时为容器内的进程保留相同的进程 ID。PID 命名空间还允许每个容器拥有自己的 init (PID 1),即“所有进程的祖先”,管理各种系统初始化任务并在它们终止时回收孤立的子进程。 | 2.6.14 |
| Network | CLONE_NEWNET | 隔离网络设备,堆栈,端口等 | 2.6.29 |
| IPC | CLONE_NEWIPC | 隔离进程间通信系统 IPC, POSIX 消息队列 | 2.6.19 |
| UTS | CLONE_NEWUTS | 隔离节点名和域名 | 2.6.19 |
| User | CLONE_NEWUSER | 隔离用户和组ID | 3.8 |
| Cgroup | CLONE_NEWCGROUP | 隔离Cgroup 根目录,可以防止信息泄露而导致cgroup目录路径外部进程可见;隔离后,Cgroup路径名是独立的,容器迁移时,防止cgroup路径名与目标系统上的路径名发生冲突;将cgroup文件系统完全隔离开,可以防止容器进程无法访问主机的cgroup目录 | 4.6 |
每种namespace各有自己管理的部分,对于现在 Linux 上的任意进程而言,它一定是每种 namespace 的一个实例 (就是每个进程都得归属于某个ns,ns中可以只有一个进程,也可以由多个进程共有)
隔离cgroup说明:假设一个场景,有一个cgroup目录/cg/1,它归USER ID 9000所有,有一个进程X也归USER ID 9000所有,该进程的命名空间位于cgroup目录/cg/1/2。在没有cgroup命名空间的情况下,因为cgroup目录/cg/1由UID 9000拥有(可写)并且进程X也由UID 9000所有,进程X则既能修改/cg/1的文件,也能修改/cg/1/2的文件。通过cgroup namespace,可以防止进程X修改/cg/1的中的文件,因为它看不到该目录。这样可以防止进程X逃逸其ancestor cgroup的限制。
Linux 提供了以下主要的系统调用用于管理namespace:
- clone():如果是纯粹只使用clone(),则会创建一个新进程;但如果我们传递一个或多个 CLONE_NEW* 标志参数给clone(),则会根据每个标志创建对应的新namespace 并且将子进程添加为其成员,达到隔离效果。
- setns():允许进程加入一个已存在的 namespace 中。
- unshare():允许进程(或线程)取消其执行上下文中,与其他进程(或线程)共享部分的关联,通俗点来说,也就是可以利用此系统调用来让当前的进程(或线程)移动至一个新的namespace中。
隔离IPC
IPC 全称 Inter-Process Communication,是进程间通信的一种方式,IPC有管道、共享内存、信号量、消息队列、信号、套接字。
- 查看主机信号量

- 主机上创建信号量
ipcmk -S 10
ipcs

- 创建一个新的IPC Namespace,然后查看ns中的信号量
unshare –ipc

隔离UTS
UTS(Unix Timesharing System)命名空间包含了运行内核的名称、版本、底层体系结构类型等信息
unshare –uts
hostname
hostname test
hostname
查看ns中的hostname和主机上的name
分别为test和edunode1
隔离User
隔离user namespace
unshare –user
可以通过-r参数,把新的namespace中的root用户映射成宿主机上的用户,例如,把ns中的用户映射为宿主机的root
unshare –user -r root
隔离PID
unshare –pid
观察主机上的进程
观察PID namespace中的进程
隔离Network
- 创建netns
ip netns add ns1
ip netns list
- 查看ns1中的网络,通过ip netns exec执行在ns中执行响应命令
ip netns exec ns1 ip addr

- 测试网络连通性
ip netns exec ns1 ping 10.6.8.113

通过veth pair与宿主机、其他ns进行网络通信
- 创建veth pair
ip link add veth0 type veth peer name veth1

将veth0或者veth1移动到ns1中
ip link set veth1 netns ns1
配置ip
ip netns exec ns1 ifconfig veth1 192.168.10.100/24
ifconfig veth0 192.168.10.101/24
- 将网卡启动
ip netns exec ns1 ifconfig veth1 up

ifconfig veth0

- 测试
ip netns exec ns1 ping 192.168.10.101
同理,可将veth peer分别放在两个netns中进行联通
通过bridge中转
实际使用中,不可能每2个不同的ns都进行一次veth pair配置,这时就需要Linux Bridge来做转发,将veth pair中的一个veth peer绑定到ns中,另一端绑定到bridge上。
- 创建两个netns,和两对veth pair
ip netns add ns0
ip netns add ns1
ip link add veth0 type veth peer name br-veth0
ip link add veth1 type veth peer name br-veth1
- 创建bridge,并启动网桥
brctl addbr br0
ip link set br0 up
- 将veth pair中的一端分别加入到ns中,另一端放到bridge上
将veth0放入ns0中,并配置ip
ip link set veth0 netns ns0
ip netns exec ns0 ifconfig veth0 192.168.10.100/24 up
ip netns exec ns0 ip link set lo up
将br-veth0绑定到网桥br0上,并启动br-veth0
brctl addif br0 br-veth0
ip link set br-veth0 up
将veth1放入ns1中,并配置ip,启动lo
ip link set veth1 netns ns1
ip netns exec ns1 ifconfig veth1 192.168.10.101/24 up
ip netns exec ns1 ip link set lo up
将br-veth1绑定到网桥br0上,并启动br-veth1
brctl addif br0 br-veth1
ip link set br-veth1 up
通过brctl show查看网桥
- 连通性测试
ip netns exec ns0 ping 192.168.10.101
