引言
在学习docker过程中进一步深度学习容器隔离技术,在docker之前Linux kernel提供了自带的容器技术namespace,本文简单介绍namespace的一些原理
Linux kernel namespace
Namespace是Linux kernel提供的资源隔离方案(Linux自带的容器技术)
系统可以为进程分配不同的namespace,并保证不同的namespace资源独立分配、不同的namespace下的进程互不干扰
Linuxkernel提供了Pid,Network,Ipc,Uts,Mount,usr等资源的隔离,每个Namespace下的这些资源对于其他Namespace是不可见的。一个进程可以同时属于多个Namespace,进程、namespace、Linux kernel关系大致如下
Pid
不同用户的进程就是通过 Pid namespace 隔离开的,且不同 namespace 中可以有相同 Pid。 有了 Pid namespace, 每个 namespace 中的 Pid 能够相互隔离。
Network
网络隔离是通过 net namespace 实现的, 每个 net namespace 有独立的 network devices, IP
addresses, IP routing tables, /proc/net 目录。
比如Docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge: docker0 连接在一起
Mnt
mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了
ipc
Container 中进程交互还是采用 linux 常见的进程间交互方法 (interprocess communication – IPC), 包
括常见的信号量、消息队列和共享内存。
container 的进程间交互实际上还是 host上 具有相同 Pid namespace 中的进程间交互,因此需要在 IPC
资源申请时加入 namespace 信息 - 每个 IPC 资源有一个唯一的 32 位 ID。
Uts
UTS(“UNIX Time-sharing System”) namespace允许每个 container 拥有独立的 hostname 和
domain name, 使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。
User
每个 container 可以有不同的 user 和 group id, 也就是说可以在 container 内部用 container 内部的用户
执行程序而非 Host 上的用户。
Linux kernel 中namespace实现方式
对于Linux kernel来说,进程或者线程都是一个task,在Linux中用来描述这个task的数据结构如下:
// 在Task 数据结构中有一个指向namespace结构体的指针nsproxystruct task_struct {.../* namespaces */struct nsproxy *nsproxy;...}
Namespace 数据结构
在该结构体中定义了指向各个类型namespace的指针,由于多个进程可以使用同一个namespace,所以nsproxy可以共享使用,count字段是该结构的引用计数
struct nsproxy {atomic_t count;struct uts_namespace *uts_ns;struct ipc_namespace *ipc_ns;struct mnt_namespace *mnt_ns;struct pid_namespace*pid_ns_for_children;struct net *net_ns;}
Linux 对 Namespace 操作方法
• clone
在创建新进程的系统调用时,可以通过 flags 参数指定需要新建的 Namespace 类型:
// CLONENEWCGROUP / CLONE_NEWIPC / CLONE_NEWNET / CLONE_NEWNS / CLONE_NEWPID /
CLONE_NEWUSER / CLONE_NEWUTS
int clone(int (_fn)(void ), void _child_stack, int flags, void _arg)
• setns
该系统调用可以让调用进程加入某个已经存在的 Namespace 中:
Int setns(int fd, int nstype)
• unshare
该系统调用可以将调用进程移动到新的 Namespace 下:
int unshare(int flags)
namespace 的日常用操作
• 查看当前系统的 namespace:
lsns –t 
• 查看某进程的 namespace:
ls -la /proc//ns/
可以看到进程号为18784的进程属于ipc、mnt、network、pid、user、uts类型的namespace
