对应到容器技术,为了隔离不同类型的资源,Linux 内核里面实现了以下几种不同类型的 namespace。
- UTS,对应的宏为 CLONE_NEWUTS,表示不同的 namespace 可以配置不同的 hostname。
- User,对应的宏为 CLONE_NEWUSER,表示不同的 namespace 可以配置不同的用户和组。
- Mount,对应的宏为 CLONE_NEWNS,表示不同的 namespace 的文件系统挂载点是隔离的
- PID,对应的宏为 CLONE_NEWPID,表示不同的 namespace 有完全独立的 pid,也即一个 namespace 的进程和另一个 namespace 的进程,pid 可以是一样的,但是代表不同的进程。
- Network,对应的宏为 CLONE_NEWNET,表示不同的 namespace 有独立的网络协议栈。
操作 namespace 的常用指令 nsenter,可以用来运行一个进程,进入指定的 namespace。例如,通过下面的命令,我们可以运行 /bin/bash,并且进入 nginx 所在容器的 namespace。
另一个命令是 unshare,它会离开当前的 namespace,创建且加入新的 namespace,然后执行参数中指定的命令。
例如,运行下面这行命令之后,pid 和 net 都进入了新的 namespace。
clone 和 unshare 的区别是,unshare 是使当前进程加入新的 namespace;clone 是创建一个新的子进程,然后让子进程加入新的 namespace,而当前进程保持不变。
在内核里面,对于任何一个进程 task_struct 来讲,里面都会有一个成员 struct nsproxy,用于保存 namespace 相关信息,里面有 struct uts_namespace、struct ipc_namespace、struct mnt_namespace、struct pid_namespace、struct net *net_ns 和 struct cgroup_namespace *cgroup_ns。
创建 namespace 的时候,我们在内核中会调用 copy_namespaces,调用顺序依次是 copy_mnt_ns、copy_utsname、copy_ipcs、copy_pid_ns、copy_cgroup_ns 和 copy_net_ns,来复制 namespace。