關於docker容器是怎樣創建新的namespace的。

最近博客收到了一封交流的私信,感謝您的關注;如今就我理解的docker創建容器時namespace的創建問題作一個 我的的回答:html

一,從原理角度來說:linux

docker建立container,說白了就是linux系統中的一次fork的調用,在fork調用的時候,會傳入一些flag參數,這些參數能夠控制對linux內核的調用使用新的namespace;具體的作法是docker daemon封裝好一個Command類,在這個Command類中,有關於namespace的配置;接着docker daemon將這個Command類發給execdriver,execdriver從中提取出關於namespace配置,而後最終將這些配置賦給golang 的exec.Cmd類,這個類就是docker 容器跑起來之後的第一個進程;這個進程在創立的時候就會建立新的namespace;git

 

二,從代碼角度來說:github

http://www.cnblogs.com/yuhan-TB/p/5118122.html 這篇文章講了docker run的啓動過程,其中docker daemon 與execdriver之間的交互是經過Command類,這是個重要的類,類的定義在daemon/execdriver/driver.go中;其中主要有:Network、Ipc、Pid、UTS等幾種命名空間,uid namespace 如今還不支持建立獨立的,也就是docker 容器裏面的root和 宿主機的root應該是同樣的;而這幾個命名空間是怎麼放到Command裏面來的呢,具體代碼在daemon/container_unix.go的populateCommand()函數中,這裏面主要的做用就是經過container的config和hostconfig來生成Command中的關於這幾個namespace的配置。golang

 

如今對於docker daemon來講,它已經生成好了發給execdriver的Command類,那麼在execdriver中是怎麼使用的呢。docker

在 daemon/execdriver/native/create.go中app

func (d *Driver) createContainer(c *execdriver.Command) (*configs.Config, error)函數

這個函數的做用是接收Command類,根據裏面的配置返回一個libcontainer/configs.Config類, 這個類就是execdriver去實際調用去執行關於生成容器的系統調用的時候的配置;ui

裏面有四個這樣的函數,就是來從execdriver.Command類中來提取出namespace的相關配置;spa

if err := d.createIpc(container, c); err != nil {
    return nil, err
}

if err := d.createPid(container, c); err != nil {
    return nil, err
}

if err := d.createUTS(container, c); err != nil {
    return nil, err
}

if err := d.createNetwork(container, c); err != nil {
    return nil, err
}

生成的這個libcontainer/configs.Config類會在vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go的函數

func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error)  中被複制到linuxContainer類裏面:

 return &linuxContainer{

        id:            id,

        root:          containerRoot,

        config:        config,   //對,就是這個config

        initPath:      l.InitPath,

        initArgs:      l.InitArgs,

        criuPath:      l.CriuPath,

        cgroupManager: l.NewCgroupsManager(config.Cgroups, nil),

    },nil

接着這個config的配置 在 /vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go 

func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) {     t := "_LIBCONTAINER_INITTYPE=standard"

    cloneFlags := c.config.Namespaces.CloneFlags()

    if cloneFlags&syscall.CLONE_NEWUSER != 0 {

        if err := c.addUidGidMappings(cmd.SysProcAttr); err != nil {

            // user mappings are not supported

            return nil, err

        }

        enableSetgroups(cmd.SysProcAttr)

        // Default to root user when user namespaces are enabled.

        if cmd.SysProcAttr.Credential == nil {

            cmd.SysProcAttr.Credential = &syscall.Credential{}

        }

    }

    cmd.Env = append(cmd.Env, t)

    cmd.SysProcAttr.Cloneflags = cloneFlags

    return &initProcess{

        cmd:        cmd,

        childPipe:  childPipe,

        parentPipe: parentPipe,

        manager:    c.cgroupManager,

        config:     c.newInitConfig(p),

    }, nil

}

在飄紅的這兩個部分,將這些關於namespace的配置交給exec.Cmd類;

相關文章
相關標籤/搜索