Linux内核Namespace隔离测试code

linux的机制有点类似于数据库中的,可以为不同的进程提供各自的命名空间,命名空间互相隔离,进程跑在自己的中资源互相隔离。多种类型的资源隔离可以让我们从文件系统开始,到进程通信、网络通信、用户权限管理、主机管理,一步步地实现各方面资源的隔离

是什么?

linux的机制有点类似于数据库中的,可以为不同的进程提供各自的命名空间,命名空间互相隔离进程跑在自己的中资源互相隔离

嵌入式进阶教程分门别类整理好了,看的时候十分方便,由于内容较多,这里就截取一部分图吧。

需要的朋友私信【内核】即可领取。

内核学习地址:Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂

使用了的机制,将进程隔离在某个中,而在某一个命名空间内的进程可以感知到其他进程的存在,但是对空间外部的进程一无所知。以一种轻量级的方式实现了虚拟化技术。

提供了多种资源的隔离:

clone(…flag…)

所隔离的资源

根目录

IPC

V IPC,POSIX 消息队列

网络设备、协议栈、端口等

Mount

挂载点

PID

进程 ID

User

用户和组 ID

UTS

主机名和域名

多种类型的资源隔离可以让我们从文件系统开始,到进程通信、网络通信、用户权限管理、主机管理,一步步地实现各方面资源的隔离,使进程运行在一个虚拟化的环境中。本文讨论的实现针对Linux内核3.8及其以后的版本。

下面我们针对六种命名空间的API做一些实例讲解,亲身体验隔离的实现底层机制。

2 实战

关于的系统调用主要有三个:

结合一段代码来介绍几个

#define _GNU_SOURCE#include #include #include #include #include #include  #define STACK_SIZE (1024 * 1024)static char container_stack[STACK_SIZE]; char* const container_args[] = {    "/bin/bash",    NULL}; int container_main(void* arg){    printf("Container - inside the container!n");    execv(container_args[0], container_args);     printf("Something's wrong!n");    return 1;} int main(){    printf("Parent - start a container!n");    int container_pid = clone(container_main, container_stack+STACK_SIZE, SIGCHLD, NULL);    waitpid(container_pid, NULL, 0);    printf("Parent - container stopped!n");    return 0;}

2.1 UTS

#define _GNU_SOURCE#include #include #include #include #include #include  #define STACK_SIZE (1024 * 1024)static char container_stack[STACK_SIZE]; char* const container_args[] = {    "/bin/bash",    NULL}; int container_main(void* arg){    printf("Container - inside the container!n");    sethostname("container",10);     execv(container_args[0], container_args);     printf("Something's wrong!n");    return 1;} int main(){    printf("Parent - start a container!n");    int container_pid = clone(container_main, container_stack+STACK_SIZE, SIGCHLD | CLONE_NEWUTS, NULL);    waitpid(container_pid, NULL, 0);    printf("Parent - container stopped!n");    return 0;}

已经变了

[root@iZbp1d4tisi44j6vxze02fZ tmp]# vi c1.c[root@iZbp1d4tisi44j6vxze02fZ tmp]# gcc c1.c[root@iZbp1d4tisi44j6vxze02fZ tmp]# ./a.outParent - start a container!Container - inside the container![root@container tmp]# hostnamecontainer[root@container tmp]# uname -ncontainer[root@container tmp]# exitexitParent - container stopped![root@iZbp1d4tisi44j6vxze02fZ tmp]#

2.2 UTS

IPC全称 Inter- ,是Unix/Linux下进程间通信的一种方式,IPC有共享内存、信号量、消息队列等方法。所以,为了隔离,我们也需要把IPC给隔离开来,这样,只有在同一个下的进程才能相互通信。

如果你熟悉IPC的原理的话,你会知道,IPC需要有一个全局的ID,即然是全局的,那么就意味着我们的需要对这个ID隔离linux消息队列使用场景,不能让别的的进程看到。

#define _GNU_SOURCE#include #include #include #include #include #include  #define STACK_SIZE (1024 * 1024)static char container_stack[STACK_SIZE]; char* const container_args[] = {    "/bin/bash",    NULL}; int container_main(void* arg){    printf("Container - inside the container!n");    sethostname("container",10);     execv(container_args[0], container_args);     printf("Something's wrong!n");    return 1;} int main(){    printf("Parent - start a container!n");    int container_pid = clone(container_main, container_stack+STACK_SIZE,                               SIGCHLD | CLONE_NEWUTS | CLONE_NEWIPC, NULL);    waitpid(container_pid, NULL, 0);    printf("Parent - container stopped!n");    return 0;}

ipcs用法 ipcs -a 默认的输出信息 打印出当前系统中所有的进程间通信方式的信息 ipcs -m 打印出使用共享内存进行进程间通信的信息 ipcs -q 打印出使用消息队列进行进程间通信的信息 ipcs -s 打印出使用信号进行进程间通信的信息

创建查询ipcs

[root@iZbp1d4tisi44j6vxze02fZ tmp]# ipcmk -QMessage queue id: 0[root@iZbp1d4tisi44j6vxze02fZ tmp]# ipcs -q------ Message Queues --------key        msqid      owner      perms      used-bytes   messages0x3b786aa7 0          root       644        0            0

查看所有ipcs

[root@iZbp1d4tisi44j6vxze02fZ tmp]# ipcs -a------ Message Queues --------key        msqid      owner      perms      used-bytes   messages0x3b786aa7 0          root       644        0            0------ Shared Memory Segments --------key        shmid      owner      perms      bytes      nattch     status0x00000000 65536      root       600        524288     2          dest0x00000000 229377     root       600        524288     2          dest0x00000000 7143426    root       600        16777216   2          dest0x00802c81 400392195  mingjie.gm 600        56         60x00000000 491524     root       600        524288     2          dest0x00000000 212926469  mingjie.gm 640        2928640    1640x00000000 212959238  mingjie.gm 640        1677721600 820x00000000 884743     root       600        524288     2          dest0x00000000 212992008  mingjie.gm 640        13848576   820xb4ce0a78 213024777  mingjie.gm 640        12288      820x00803069 388169738  mingjie.gm 600        56         6#define _GNU_SOURCE------ Semaphore Arrays --------key        semid      owner      perms      nsems0x671cfa8c 6422528    mingjie.gm 640        1520x671cfa8d 6455297    mingjie.gm 640        1520x671cfa8e 6488066    mingjie.gm 640        152

执行程序

[root@iZbp1d4tisi44j6vxze02fZ tmp]# gcc c2.c -o ipc[root@iZbp1d4tisi44j6vxze02fZ tmp]# ./ipcParent - start a container!Container - inside the container![root@container tmp]#[root@container tmp]# ipcs -a------ Message Queues --------key        msqid      owner      perms      used-bytes   messages------ Shared Memory Segments --------key        shmid      owner      perms      bytes      nattch     status------ Semaphore Arrays --------key        semid      owner      perms      nsems

IPC已经被隔离了!

2.3 PID

#define _GNU_SOURCE#include #include #include #include #include #include  #define STACK_SIZE (1024 * 1024)static char container_stack[STACK_SIZE]; char* const container_args[] = {    "/bin/bash",    NULL}; int container_main(void* arg){    printf("Container [%5d] - inside the container!n", getpid());    sethostname("container",10);     execv(container_args[0], container_args);     printf("Something's wrong!n");    return 1;} int main(){    printf("Parent - start a container!n");    int container_pid = clone(container_main, container_stack+STACK_SIZE,                               SIGCHLD | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID                              , NULL);    waitpid(container_pid, NULL, 0);    printf("Parent - container stopped!n");    return 0;}

运行结果如下(我们可以看到,子进程的pid是1了):

[root@iZbp1d4tisi44j6vxze02fZ tmp]# gcc c3.c -o pid[root@iZbp1d4tisi44j6vxze02fZ tmp]# ./pidParent - start a container!Container [    1] - inside the container![root@container tmp]# echo $

你可能会问,PID为1有个毛用啊?我们知道,在传统的UNIX系统中,PID为1的进程是init,地位非常特殊。他作为所有进程的父进程,有很多特权(比如:屏蔽信号等),另外,其还会检查所有进程的状态,我们知道,如果某个子进程脱离了父进程(父进程没有wait它),那么init就会负责回收资源并结束这个子进程。所以,要做到进程空间的隔离,首先要创建出PID为1的进程,最好就像那样,把子进程的PID在容器内变成1。

但是,我们会发现linux消息队列使用场景,在子进程的shell里输入ps,top等命令,我们还是可以看得到所有进程。说明并没有完全隔离。这是因为,像ps, top这些命令会去读/proc文件系统,所以,因为/proc文件系统在父进程和子进程都是一样的,所以这些命令显示的东西都是一样的。

所以,我们还需要对文件系统进行隔离。

2.4 Mount

下面的例程中,我们在启用了mount 并在子进程中重新mount了/proc文件系统。

#define _GNU_SOURCE#include #include #include #include #include #include  #define STACK_SIZE (1024 * 1024)static char container_stack[STACK_SIZE]; char* const container_args[] = {    "/bin/bash",    NULL}; int container_main(void* arg){    printf("Container [%5d] - inside the container!n", getpid());    sethostname("container",10);     /* 重新mount proc文件系统到 /proc下 */    system("mount -t proc proc /proc");    execv(container_args[0], container_args);     printf("Something's wrong!n");    return 1;} int main(){    printf("Parent [%5d] - start a container!n", getpid());    int container_pid = clone(container_main, container_stack+STACK_SIZE,                               SIGCHLD | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS                              , NULL);    waitpid(container_pid, NULL, 0);    printf("Parent - container stopped!n");    return 0;}

运行结果如下:

[root@iZbp1d4tisi44j6vxze02fZ tmp]# gcc c4.c[root@iZbp1d4tisi44j6vxze02fZ tmp]# ./a.outParent [16901] - start a container!Container [    1] - inside the container![root@container tmp]# ps -elfF S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD4 S root         1     0  0  80   0 - 29185 do_wai 20:04 pts/3    00:00:00 /bin/bash0 R root        35     1  0  80   0 - 38833 -      20:05 pts/3    00:00:00 ps -elf

在通过创建mount 后,父进程会把自己的文件结构复制给子进程中。而子进程中新的中的所有mount操作都只影响自身的文件系统,而不对外界产生任何影响。这样可以做到比较严格地隔离。

上面的代码是在子进程中重新mount了一次,否则还是会看到父进程的proc目录!

2.5 User

User 主要是用了的参数。使用了这个参数后,内部看到的UID和GID已经与外部不同了,默认显示为65534。那是因为容器找不到其真正的UID所以,设置上了最大的UID(其设置定义在/proc/sys//)。

要把容器中的uid和真实系统的uid给映射在一起,需要修改 /proc// 和 /proc// 这两个文件。这两个文件的格式为: ID–ns ID–ns

其中:

$ cat /proc/2465/uid_map         0       1000          1

再比如下面的示例:表示把内部从0开始的uid映射到外部从0开始的uid,其最大范围是无符号32位整形

$ cat /proc/$/uid_map         0          0          4294967295

User 是以普通用户运行,但是别的需要root权限,那么,如果我要同时使用多个,该怎么办呢?一般来说,我们先用一般用户创建User ,然后把这个一般用户映射成root,在容器内用root来创建其它的。

2.6

2.7 文件

同一个容器的进程在一个NS下。

本文到此结束,希望对大家有所帮助。

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至81118366@qq.com举报,一经查实,本站将立刻删除。发布者:简知小编,转载请注明出处:https://www.jianzixun.com/95080.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫

相关推荐

软文友链广告合作联系站长qq81118366