/*
* 2020/12/15 11:58 yin
*
* namespace 是 linux 内核提供的特性,为虚拟化而生
*/
/*
* nsproxy
*/
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;
struct cgroup_namespace *cgroup_ns;
};
extern struct nsproxy init_nsproxy;
/*
* namespace
*/
机制提供了一种资源隔离的解决方案
Namespace是对全局系统资源的一种封装隔离,使得处于不同namespace的进程拥有独立的全局系统资源,
改变一个namespace中的系统资源只会影响当前namespace里的进程,对其他namespace中的进程没有影响。
cat /proc/[pid]/ns
目前Linux内核里面实现且支持的Namespace有7种
名称 定义 说明
Cgroup CLONE_NEWCGROUP Cgroup root directory ( Linux 4.6)
IPC CLONE_NEWIPC 隔离进程间通信 ( Linux 2.6.19)
Network CLONE_NEWNET 隔离网络资源 ( Linux 2.6.24)
Mount CLONE_NEWNS 隔离文件系统挂载点 ( Linux 2.4.19)
PID CLONE_NEWPID 隔离进程的ID ( Linux 2.6.24)
User CLONE_NEWUSER 隔离用户和用户组的ID (started in Linux 2.6.23 and completed in Linux 3.8)
UTS CLONE_NEWUTS (UNIX Time-sharing System) namespace提供了主机名和域名的隔离
能够使得子进程有独立的主机名和域名(hostname),这一特性在Docker容器技术中被用到,
使得docker容器在网络上被视作一个独立的节点,而不仅仅是宿主机上的一个进程。
/*
* PID Namespace
*/
在 Linux 系统中创建进程的系统调用是 clone()
int pid = clone(main_function, stack_size, SIGCHLD, NULL);
这个系统调用就会为我们创建一个新的进程,并且返回它的进程号 pid。
我们用 clone() 系统调用创建一个新进程时,就可以在参数中指定 CLONE_NEWPID 参数,比如:
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
这时,新创建的这个进程将会“看到”一个全新的进程空间,在这个进程空间里,它的 PID 是 1。
/*
* Docker
*/
Docker中利用UTS namespace原理,每个镜像可以以本身所提供的服务名称来命名镜像的hostname,且不会对宿主机产生任何影响,
由此达到主机名和域名的隔离效果。
namespace 是 linux 内核提供的特性,为虚拟化而生。随着 docker 的诞生引爆了容器技术,也把长期在后台默默奉献的 namespace 技术推到了大家的面前。
/*
* UTS Namespace
*/
UTS Namespace提供了主机名和域名的隔离,也就是struct utsname里的nodename和domainname两个字段。不同Namespace中可以拥有独立的主机名和域名。
那么为什么需要对主机名和域名进行隔离呢?因为主机名和域名可以用来代替IP地址,如果没有这一层隔离,同一主机上不同的容器的网络访问就可能出问题。
/*
* IPC Namespace
*/
IPC Namespace是对进程间通信的隔离,进程间通信常见的方法有信号量、消息队列和共享内存。
IPC Namespace主要针对的是SystemV IPC和Posix消息队列,这些IPC机制都会用到标识符,比如用标识符来区分不同的消息队列,
IPC Namespace要达到的目标是相同的标识符在不同的Namepspace中代表不同的通信介质(比如信号量、消息队列和共享内存)。
/*
* API
*/
/* 创建一个新的进程并把他放到新的namespace中 */
int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);
/* 将当前进程加放到已有的namespace中 */
int setns(int fd, int nstype);
/* 使当前进程退出指定类型的namespace,并加入到新创建的namespace(相当于创建并加入新的namespace) */
int unshare(int flags);
/* clone 和 unshare 区别 */
两者都是创建并加放新的namespace,区别是:
unshare 是使当前进程加入新的namespace
clone 是创建一个新的子进程,然后让子进程加入新的namespace,而当前进程保持不变