zoukankan      html  css  js  c++  java
  • linux中的namespace与openVZ



    一直对linux内核的namespace感到困惑,今天看了一下代码才知道,原来所谓的namespace其实就是给虚拟化用的,PID namespace其实就是建立一个新的PID空间,这样内部可以使用一套新的PID,而且不会和外部冲突。这也就是说某个进程其实会有两个PID,一个空间一个。

    我写了段C代码来展示这个问题。



    /*
     * gcc namespace.c -o ns
     * 
     root@ubuntu-9.04# ./ns 3
        Out of the container, my pid is: 15169
        In the container, my pid is: 1
        pid of my child is 2
        cpid: 15170
        Parent sleeping 20 seconds
        pid of my child is 3
        pid of my child is 4

    */


    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sched.h>
    #include <linux/sched.h>
     
    static int fork_child(void *arg)
    {
        int a = (int)arg;
        int i;
        pid_t pid;
     
        printf("In the container, my pid is: %d\n", getpid());
        for (i = 0; i <a; i++) {
            pid = fork();
            if (pid <0)
                return pid;
            else if (pid)
                printf("pid of my child is %d\n", pid);
            else if (pid == 0) {
                sleep(3);
                exit(0);
            }
        }
        return 0;
    }
     
    int main(int argc, char *argv[])
    {
        int cpid;
        void *childstack, *stack;
        int flags;
        int ret = 0;
        int stacksize = getpagesize() * 4;
     
        if (argc != 2) {
            fprintf(stderr, "Wrong usage.\n");
            return -1;
        }
     
        stack = malloc(stacksize);
        if (!stack) {
            perror("malloc");
            return -1;
        }
     
        printf("Out of the container, my pid is: %d\n", getpid());
     
        childstack = stack + stacksize;
        flags = CLONE_NEWPID | CLONE_NEWNS;
     
        cpid = clone(fork_child, childstack, flags, (void *)atoi(argv[1]));
        printf("cpid: %d\n", cpid);
     
        if (cpid <0) {
            perror("clone");
            ret = -1;
            goto out;
        }
     
        fprintf(stderr, "Parent sleeping 20 seconds\n");
        sleep(20);
        ret = 0;
     
    out:
        free(stack);
        return ret;
    }

    其实被namespace化的不只是PID,还有很多东西,貌似它们合起来被称为container。可以看 include/linux/nsproxy.h:

    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;
    struct net *net_ns;
    };


    openvz基础应该是Linux kernel namespace,进程被隔离在各自的namespace,因此额外开销很小,只能叫隔离容器,算不得虚拟机。有空要读一这个系统源码

    http://openvz.org/WP/What_are_containers


    http://www.cnblogs.com/lisperl/archive/2012/05/03/2480316.html

    Linux Namespaces 机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace。每个Namespace里面的 资源对其他Namespace都是透明的。要创建新的Namespace,只需要在调用clone时指定相应的flag。 Linux Namespaces机制为实现基于容器的虚拟化技术提供了很好的基础,LXC(Linux containers)就是利用这一特性实现了 资源的隔离。不同container内的进程属于不同的Namespace,彼此透明,互不干扰。下面我们就从clone系统调用的flag出发,来介绍 各个Namespace。

    当调用clone时, 设定了CLONE_NEWPID,就会创建一个新的PID Namespace,clone出来的新进程将成为Namespace里的第一个进程。一个 PID Namespace为进程提供了一个独立的PID环境,PID Namespace内的PID将从1开始,在Namespace内调用 fork,vfork或clone都将产生一个在该Namespace内独立的PID。新创建的Namespace里的第一个进程在该Namespace 内的PID将为1,就像一个独立的系统里的init进程一样。该Namespace内的孤儿进程都将以该进程为父进程,当该进程被结束时,该 Namespace内所有的进程都会被结束。PID Namespace是层次性,新创建的Namespace将会是创建该Namespace的进程属于 的Namespace的子Namespace。子Namespace中的进程对于父Namespace是可见的,一个进程将拥有不止一个PID,而是在所 在的Namespace以及所有直系祖先Namespace中都将有一个PID。系统启动时,内核将创建一个默认的PID Namespace,该 Namespace是所有以后创建的Namespace的祖先,因此系统所有的进程在该Namespace都是可见的。

    当调用clone时, 设定了CLONE_NEWIPC,就会创建一个新的IPC Namespace,clone出来的进程将成为Namespace里的第一个进程。一个 IPC Namespace有一组System V IPC objects 标识符构成,这标识符有IPC相关的系统调用创建。在一个 IPC Namespace里面创建的IPC object对该Namespace内的所有进程可见,但是对其他Namespace不可见,这样就使得不 同Namespace之间的进程不能直接通信,就像是在不同的系统里一样。当一个IPC Namespace被销毁,该Namespace内的所有 IPC object会被内核自动销毁。

    PID Namespace 和IPC Namespace可以组合起来一起使用,只需在调用clone时,同时指定CLONE_NEWPID和CLONE_NEWIPC,这样新创建 的Namespace既是一个独立的PID空间又是一个独立的IPC空间。不同Namespace的进程彼此不可见,也不能互相通信,这样就实现了进程间 的隔离。

    当调用clone时, 设定了CLONE_NEWNS,就会创建一个新的mount Namespace。每个进程都存在于一个mount Namespace里 面,mount Namespace为进程提供了一个文件层次视图。如果不设定这个flag,子进程和父进程将共享一个mount Namespace, 其后子进程调用mount或umount将会影响到所有该Namespace内的进程。如果子进程在一个独立的mount Namespace里面,就可 以调用mount或umount建立一份新的文件层次视图。该flag配合pivot_root系统调用,可以为进程创建一个独立的目录空间。

    当调用clone时, 设定了CLONE_NEWNET,就会创建一个新的Network Namespace。一个Network Namespace为进程提供了一个完全独 立的网络协议栈的视图。包括网络设备接口,IPv4和IPv6协议栈,IP路由表,防火墙规则,sockets等等。一个 Network Namespace提供了一份独立的网络环境,就跟一个独立的系统一样。一个物理设备只能存在于一个Network Namespace 中,可以从一个Namespace移动另一个Namespace中。虚拟网络设备(virtual network device)提供了一种类似管道的 抽象,可以在不同的Namespace之间建立隧道。利用虚拟化网络设备,可以建立到其他Namespace中的物理设备的桥接。当一个 Network Namespace被销毁时,物理设备会被自动移回init Network Namespace,即系统最开始的Namespace。

    当调用clone时, 设定了CLONE_NEWUTS,就会创建一个新的UTS Namespace。一个UTS Namespace就是一组被uname返回的标识符。新的 UTS Namespace中的标识符通过复制调用进程所属的Namespace的标识符来初始化。Clone出来的进程可以通过相关系统调用改变这些标 识符,比如调用sethostname来改变该Namespace的hostname。这一改变对该Namespace内的所有进程可见。 CLONE_NEWUTS和CLONE_NEWNET一起使用,可以虚拟出一个有独立主机名和网络空间的环境,就跟网络上一台独立的主机一样。

    以上所有 clone flag都可以一起使用,为进程提供了一个独立的运行环境。LXC正是通过在clone时设定这些flag,为进程创建一个有独立 PID,IPC,FS,Network,UTS空间的container。一个container就是一个虚拟的运行环境,对container里的进程 是透明的,它会以为自己是直接在一个系统上运行的。

    一个container就像传统虚拟化技术里面的一台安装了OS的虚拟机,但是开销更小,部署更为便捷。

    作者曰:Linux  Namespaces机制本身就是为了实现container based  virtualizaiton开发的。它提供了一套轻量级、高效率的系统资源隔离方案,远比传统的虚拟化技术开销小,不过它也不是完美的,它为内核的开发 带来了更多的复杂性,它在隔离性和容错性上跟传统的虚拟化技术比也还有差距


  • 相关阅读:
    php使用时间戳保存时间的意义
    php输出控制函数存在的意义
    php中foreach使用引用的陷阱
    mac下php添加openssl扩展
    gitlab配置自动同步
    lnmp集成环境tp nginx vhost配置
    上传文件中文文件名乱码的解决方法以及iconv函数的使用
    php返回数据格式
    怎样让Git忽略当前已经更改的文件
    connect() php-cgi.sock failed (2: No such file or directory)
  • 原文地址:https://www.cnblogs.com/mull/p/4477834.html
Copyright © 2011-2022 走看看