• Docker原理之Namespace


     Linux Namespace

      namespace是linux内核用来隔离内核资源的方案。 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。

    隔离资源

    名称 宏定义   隔离的资源
    IPC  CLONE_NEWIPC System V IPC(信号量、消息队列、共享内存) 和POSIX MESSAGE QUEUES
    Network CLONE_NEWNET Network devices、stacks、ports(网络设备、网络栈、端口等)
    Mount  CLONE_NEWNS Mount points(文件系统挂载点)
    PID CLONE_NEWPID Process IDs(进程编号)
    User CLONE_NEWUSER User and Groups IDs(用户和用户组)
    UTS CLONE_NEWUTS Hostname and NIS domain name(主机名与NIS域名)
    Cgroup CLONE_NEWCGROUP Cgroup root directory(cgroup的根目录)

    表现形式

    • 查看进程ID的namespace  
    # 查看进程18863的namespace
    ll /proc/18863/ns

      

       可以看到,namespace 是链接文件,格式为[隔离类型:唯一标识],唯一标识可看成namespace的ID,同一个ID下的进程共享该namespace的全局资源。

    函数

    • clone():Clone()函数是在libc库中定义的一个封装函数,它负责建立新轻量级进程的堆栈并且调用对编程者隐藏了clone系统条用。实现clone()系统调用的sys_clone()服务例程并没有fn和arg参数。封装函数把fn指针存放在子进程堆栈的每个位置处,该位置就是该封装函数本身返回地址存放的位置。Arg指针正好存放在子进程堆栈中的fn的下面。当封装函数结束时,CPU从堆栈中取出返回地址,然后执行fn(arg)函数。
    • setns(): 通过 setns() 函数可以将当前进程加入到已有的 namespace 中。
    • unshare():通过 unshare 函数可以在原进程上进行 namespace 隔离。

    容器里的进程看到的文件系统

      启用隔离函数CLONE_NEWNS, 进入容器看到就是容器自己的文件系统?

    • 函数验证, 在~目录下创建个ns.c文件
    #define _GNU_SOURCE
    #include <sys/mount.h> 
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <sched.h>
    #include <signal.h>
    #include <unistd.h>
    #define STACK_SIZE (1024 * 1024)
    static char container_stack[STACK_SIZE];
    char* const container_args[] = {
      "/bin/bash",
      NULL
    };
    
    int container_main(void* arg)
    {  
      printf("进入容器里面!
    ");
    execv(container_args[0], container_args); printf("错误 ");
    return 1; } int main() { printf("宿主机启动一个容器! ");
    int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNS | SIGCHLD , NULL); waitpid(container_pid, NULL, 0); printf("容器停止! ");
    return 0; }

      编译并执行:

    # 编译
    gcc -o  ns ns.c -D_GNU_SOURCE  -lpthread
    # 执行
    ./ns

      结果:

      

      执行ns,显示我们进入到了一个容器中。假象我们容器是挂载到/tmp目录下,查看/tmp,其实这里仍然是宿主机的文件。紧接着,把容器以 tmpfs(内存盘)格式,重新挂载了 /tmp 目录。

    #define SOURCE
    #include <sys/mount.h> 
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <sched.h>
    #include <signal.h>
    #include <unistd.h>
    #define STACK_SIZE (1024 * 1024)
    static char container_stack[STACK_SIZE];
    char* const container_args[] = {
      "/bin/bash",
      NULL
    };
    
    int container_main(void* arg)
    {  
      printf("进入容器里面!
    ");
     
      mount("none", "/tmp", "tmpfs", 0, "");
    
      execv(container_args[0], container_args);
    
      printf("错误
    ");
      return 1;
    }
    
    int main()
    {
      printf("宿主机启动一个容器!
    ");
      int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNS | SIGCHLD , NULL);
      waitpid(container_pid, NULL, 0);
      printf("容器停止!
    ");
      return 0;
    }

       在容器启动前加 mount("none", "/tmp", "tmpfs", 0, "");

       再编译执行ns,挂载后,就看不见任何宿主机的文件了。这就是在当前容器下的单独的文件系统了。

       

    参考

      https://time.geekbang.org/column/article/17921

      本文直接拷贝了部分代码,如有侵权,请告知删除。

    目录

      https://www.cnblogs.com/lioa/p/12664686.html

  • 相关阅读:
    android gradle 打包命令
    android RRO
    android adb 常用命令
    mui执行滑动事件: Unable to preventDefault inside passive event listener
    获取 input[type=file] 文件上传尺寸
    MySQL:You can't specify target table for update in FROM clause
    input标签中autocomplete="off" 失效的解决办法
    @media属性针对苹果手机写法
    centos7 下mysql5.7修改默认编码格式为UTF-8
    使用Mui加载数据后a标签点击事件失效
  • 原文地址:https://www.cnblogs.com/lioa/p/12666497.html
Copyright © 2020-2023  润新知