Docker背后的内核技术(一)——Namespace 资源隔离

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/u010039418/article/details/88800631

注:本文分析基于3.10.0-693.el7内核版本,即CentOS 7.4

背景

容器技术的产生主要依赖于Linux内核的两大技术,Namespace和Cgroup,也就是资源隔离和资源限制。这两种技术都可以单独使用,但是把它们放到一起后,实现的功能更为强大。我们今天就来了解了解Namespace技术。

Namespace种类

目前,内核中实现了6中Namespace:

Namespace 作用
UTS 隔离主机名和域名
IPC 隔离信号量、消息队列
PID 隔离进程编号
Network 隔离网络设备、协议栈、端口
Mount 隔离文件系统
User 隔离用户和用户组

体验Namespace

对于Namespace的操作,主要通过clone()、setns()和unshare()这三个系统调用来实现,也就是Namespace的创建、加入和删除操作。

A、创建
由上我们知道有六种Namespace,因此对应到clone上,也有六个标志位与此对应。

Namespace clone标志
UTS CLONE_NEWUTS
IPC CLONE_NEWIPC
PID CLONE_NEWPID
Network CLONE_NEWNET
Mount CLONE_NEWNS
User CLONE_NEWUSER

在使用clone前我们先了解一下clone函数的入参,

int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);

其中,
child_func:表示子进程运行的主函数
child_stack:子进程使用的栈空间
flags:表示使用哪些 CLONE标志位
args:可用于传入用户参数

接下来我们以UTS隔离为例,看下效果。创建namespace.c,输入以下代码。

#define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sched.h>
#include <stdio.h>

#define STACK_SIZE (1024 * 1024)
#define FLAGS SIGCHLD|CLONE_NEWUTS
static char stack[STACK_SIZE];
static char * const child_args[] = {"/bin/bash", NULL };

static int child(void *arg)
{
    execv("/bin/bash", child_args);
    return 0;
}

int main(int argc, char *argv[])
{
    pid_t pid;
    pid = clone(child, stack+STACK_SIZE, FLAGS, NULL);
    waitpid(pid, NULL, 0);

    return 0;
}

该代码运行后会新创建一个bash交互窗口,类似于在终端输入bash命令。
使用以下命令编译,

gcc namespace.c -o namespace

然后我们运行namespace,并进行修改hostname的操作,

[root@CentOS-7-4 /home/namespace]# ls
.  ..  namespace  namespace.c
[root@CentOS-7-4 /home/namespace]# hostname
CentOS-7-4
[root@CentOS-7-4 /home/namespace]# ./namespace 
[root@CentOS-7-4 /home/namespace]# hostname
CentOS-7-4
[root@CentOS-7-4 /home/namespace]# hostname newname
[root@CentOS-7-4 /home/namespace]# hostname
newname
[root@CentOS-7-4 /home/namespace]# exit
exit
[root@CentOS-7-4 /home/namespace]# hostname
CentOS-7-4

可见,通过UTS隔离后,我们进入新的终端修改主机名成功后,返回原先终端,修改的主机名并没有影响到原先的主机,因此达到了主机名的隔离效果。

我们再看下IPC的隔离效果,在上面代码的基础上,将FLAGS变量定义如下:

#define FLAGS SIGCHLD|CLONE_NEWUTS|CLONE_NEWIPC

同样进行编译,然后执行创建消息队列操作,

[root@CentOS-7-4 /home/namespace]# ./namespace 
[root@CentOS-7-4 /home/namespace]# ipcmk -Q
Message queue id: 0
[root@CentOS-7-4 /home/namespace]# ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x217cc434 0          root       644        0            0           

[root@CentOS-7-4 /home/namespace]# exit
exit
[root@CentOS-7-4 /home/namespace]# ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages 

我们在新终端创建一个消息队列,但是在host上却看不到任何消息队列,因此IPC的隔离达到了效果。

其他的隔离也都可以通过相应的标志位由clone创建,就不再一一测试了。

猜你喜欢

转载自blog.csdn.net/u010039418/article/details/88800631