DDR爱好者之家 Design By 杰米

Docker通过namespace实现了资源隔离,通过cgroups实现了资源限制,通过写时复制(copy-on-write)实现了高效的文件操作。

1.namespace资源隔离

namepsace的6项隔离:

namespace
系统调用参数
隔离内容
UTS
CLONE_NEWUTS
主机名与域名
IPC
CLONE_NEWIPC
信号量,消息队列和共享内存
PID
CLONE_NEWPID
进程编号
Network
CLONE_NEWNET
网络设备,网络栈,端口等
Mount
CLONE_NEWNS
挂载点(文件系统)
User
CLONE_NEWUSER
用户和用户组

Linux内核实现namespace的主要目的之一是实现轻量级虚拟化(容器)服务。在同一个namespace下的进程可以感知彼此的变化,而对外界进程一无所知。这样就可以让容器中的进程产生错觉,仿佛自己置身于一个独立的系统环境中,以达到独立和隔离的目的。

进行namespace API操作的4种方式

  namespace的API包括clone(),setns()以及unshare(),还有/proc下的部分文件。为了确定隔离的到底是哪6项namespace,在使用这些API时,通常需要指定以下6个参数的一个或多个,通过位或操作来实现。

CLONE_NEWUTS,CLONE_NEWIPC,CLONE_NEWPID,CLONE_NEWNET,CLONE_NEWNS,CLONE_NEWUSER.

通过clone()在创建新进程的同时创建namespace

使用clone()来创建一个独立namespace的进程是最常见的做法,也是Docker使用namespace的最基本的方法,它的调用方式如下。

NAME 
    clone, __clone2 - create a child process 
SYNOPSIS 
    /* Prototype for the glibc wrapper function */ 
    #include <sched.h> 
    int clone(int (*fn)(void *), void *child_stack, 
         int flags, void *arg, ... 
         /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ ); 

clone()实际上是fork系统调用的一种更通用的实现方式,它可以通过flags来控制使用多少功能。一共有20多种CLONE_*的flag(标志位)参数用来控制clone进程的方方面面(如是否与父进程共享虚拟内存等).

查看/proc/[pid]/ns文件

从3.8版本内核开始,用户可以在该文件下看到指向不同namespace号的文件:

 ls -l /proc/2597/ns
total 0
lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 net -> net:[4026531957]
lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 pid -> pid:[4026531836]
lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 user -> user:[4026531837]
lrwxrwxrwx 1 zhangxa zhangxa 0 Mar 2 06:42 uts -> uts:[4026531838]

如果2个进程namespace号相同,说明它们在同一个namespace下。

/proc/[pid]/ns里设置这些符号链接的另一个作用是,一旦上述链接文件被打开,那么就算该namespace下的所有进程都已经结束,这个namespace也会一直存在,后续进程也可以再加进来。在Docker中,通过文件描述符定位和加入一个存在的namespace是最基本的方式。

另外,把/proc/[pid]/ns目录文件使用--bind方式挂载起来可以直到同样的作用:

# mount --bind /proc/2454/ns/uts uts

通过setns()加入一个已经存在的namespace

上面提到,在进程都结束的情况下,也可以通过挂载的形式把namespace保留下来,保留namespace的目的是为以后有进程加入做准备。在Docker中,使用docker exec命令在已经运行着的容器中执行一个新命令,就需要用到该方法。通过setns()系统调用,进程从原先的namespace加入某个已经存在的namespace,使用方法如下。通常为了不影响进程的调用者,也为了使新加入的pid namespace生效,会在setns()函数执行后使用clone创建子进程继续执行命令,让原先的进程结束。

NAME 
    setns - reassociate thread with a namespace 
SYNOPSIS 
    #define _GNU_SOURCE       /* See feature_test_macros(7) */ 
    #include <sched.h> 
    int setns(int fd, int nstype); 
fd = open(argv[1],O_RDONLY); 
setns(fd,0); 
execvp(argv[2],&argv[2]); 

假设编译后的程序为"setns-test"
# ./setns-test ~/uts /bin/bash

至此,就可以在新加入的namespace中执行shell命令了。

通过unshare()在原先进程上进行namespace隔离

它与clone()很像,不同的是,unshare()运行在原先的进程上,不需要启动一个新进程。

NAME 
    unshare - disassociate parts of the process execution context 
SYNOPSIS 
    #include <sched.h> 
    int unshare(int flags); 

调用unshare()的主要作用就是不启动一个新进程就可以起到隔离的效果,相当跳出原先的namespace进行操作。这样,就可以在原进程进行一些需要隔离的操作。Linux自带的unshare命令,就是通过unshare()系统调用实现的。Docker目前并没有使用这个系统调用。

总结

以上就是本文关于Docker探索namespace详解的全部内容,希望对大家有所帮助,感兴趣的朋友可以继续参阅本站:浅谈Docker安全机制内核安全与容器之间的网络安全、详解Docker使用Linux iptables 和 Interfaces管理容器网络等,有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!

DDR爱好者之家 Design By 杰米
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
DDR爱好者之家 Design By 杰米

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。