[docker 1.13 源码分析]第二章 Docker container创建

来源:互联网 发布:linux查看文件夹下文件 编辑:程序博客网 时间:2024/05/16 07:11

第一章 Container create源码分析

1.1 NewCreateCommand函数(cli/command/container/create.go)

 

 

1.2 ContainerCreate函数(client/container_create.go)

创建一个容器在客户端实现是在client/container_create.go这个文件唯一一个函数,传入的参数主要有容器基本配置container.Configcontainer.HostConfignetwork.NetworkingConfig

Config只要目的是基于容器的可移植性信息,与host相互独立,非可移植性在HostConfig结构体中。Config包括容器的基本信息,名字,输入输出流等,不解释结构体注释很清晰。

type Config struct {
       Hostname        string                // Hostname
       Domainname      string                // Domainname
       User            string                // User that will run the command(s) inside the container, also support user:group
       AttachStdin     bool                  // Attach the standard input, makes possible user interaction
       AttachStdout    bool                  // Attach the standard output
       AttachStderr    bool                  // Attach the standard error
       ExposedPorts    nat.PortSet           `json:",omitempty"` // List of exposed ports
       Tty             bool                  // Attach standard streams to a tty, including stdin if it is not closed.
       OpenStdin       bool                  // Open stdin
       StdinOnce       bool                  // If true, close stdin after the 1 attached client disconnects.
       Env             []string              // List of environment variable to set in the container
       Cmd             strslice.StrSlice     // Command to run when starting the container
       Healthcheck     *HealthConfig         `json:",omitempty"` // Healthcheck describes how to check the container is healthy
       ArgsEscaped     bool                  `json:",omitempty"` // True if command is already escaped (Windows specific)
       Image           string                // Name of the image as it was passed by the operator (e.g. could be symbolic)
       Volumes         map[string]struct{}   // List of volumes (mounts) used for the container
       WorkingDir      string                // Current directory (PWD) in the command will be launched
       Entrypoint      strslice.StrSlice     // Entrypoint to run when starting the container
       NetworkDisabled bool                  `json:",omitempty"` // Is network disabled
       MacAddress      string                `json:",omitempty"` // Mac Address of the container
       OnBuild         []string              // ONBUILD metadata that were defined on the image Dockerfile
       Labels          map[string]string     // List of labels set to this container
       StopSignal      string                `json:",omitempty"` // Signal to stop a container
       StopTimeout     *int                  `json:",omitempty"` // Timeout (in seconds) to stop a container
       Shell           strslice.StrSlice     `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
}

 

只要是通过http请求发送至server端使用POST方法

func (cli *Clientpost(ctx context.Contextpath stringquery url.Valuesobj interface{}headers map[string][]string) (serverResponseerror) {
       bodyheaderserr := encodeBody(objheaders)
       if err != nil {
              return serverResponse{}err
       }
       return cli.sendRequest(ctx"POST"pathquerybodyheaders)
}

 

1.3 postContainerCreate函数

创建容器的操作对应在server端得实现在api/server/router/container/container_routes.go中的postContainersCreate()函数;

主要工作是校验工作,从body获取1.2中的配置container配置,host配置,network配置,最终用的方法是调用接口方法ContainerCreate,这个方法是daemon中实现。

ccrerr := s.backend.ContainerCreate(types.ContainerCreateConfig{
       Name:             name,
       Config:           config,
       HostConfig:       hostConfig,
       NetworkingConfig: networkingConfig,
       AdjustCPUShares:  adjustCPUShares,
}validateHostname)

 

 

1.4 ContainerCreate函数

Daemon中的方法daemon/create.go文件。

主要是校验工作,不解释了。看主要方法daemon.create1.5中讲解

containererr := daemon.create(paramsmanaged)
if err != nil {
       return containertypes.ContainerCreateCreatedBody{Warnings: warnings}daemon.imageNotExistToErrcode(err)
}

 

1.5 create函数

if params.Config.Image != "" {
       imgerr = daemon.GetImage(params.Config.Image)
       if err != nil {
              return nilerr
       }

       if runtime.GOOS == "solaris" && img.OS != "solaris " {
              return nilerrors.New("Platform on which parent image was created is not Solaris")
       }
       imgID = img.ID()
}

 

 

if containererr = daemon.newContainer(params.Nameparams.ConfigimgIDmanaged)err != nil {
       return nilerr
}

 

new一个新的container;接下来的就是为启动容器所做的工作

 

if err := daemon.setRWLayer(container)err != nil {
       return nilerr
}

创建读写层,详细看1.6讲解

 

rootUIDrootGIDerr := idtools.GetRootUIDGID(daemon.uidMapsdaemon.gidMaps)
if err != nil {
       return nilerr
}
if err := idtools.MkdirAs(container.Root0700rootUIDrootGID)err != nil {
       return nilerr
}
if err := idtools.MkdirAs(container.CheckpointDir()0700rootUIDrootGID)err != nil {
       return nilerr
}

root uid gid的属性创建目录

 

if err := daemon.setHostConfig(containerparams.HostConfig)err != nil {
       return nilerr
}

① daemon.registerMountPoints注册所有挂载到容器的数据卷(1.8讲解)

② daemon.registerLinksload所有links(包括父子关系),写入host配置至文件( 注册互联容器,容器可以通过 ip:端口访问,可以通过--link互联。)

③ container.ToDiskcontainer持久化至disk。路径为如下所示

/var/lib/docker/containers/$containerID

 

1.6 CreateRWLayer函数

位于文件layer/layer_store.go文件,layerStore结构体如下所示:

MetadataStore为接口,主要为获得层基本信息的方法。 metadata是这个层的额外信息,不仅能够让Docker获取运行和构建的信息,也包括父层的层次信息(只读层和读写层都包含元数据)。

graphdriver.Driver也为接口,主要以aufs主要介绍,在daemon/graphdriver文件下有aufsbtrfsdevmapperoverlay等的实现。 除差别和改动等的方法,graphdriver主要的功能是 Get、 Put、 Create 和 Remove 方法 。

 

 

Aufs层关系

 

type layerStore struct {
       store  MetadataStore
       driver graphdriver.Driver

       layerMap map[ChainID]*roLayer
       layerL   sync.Mutex

       mounts map[string]*mountedLayer
       mountL sync.Mutex
}

 

type roLayer struct {
       chainID    ChainID
       diffID     DiffID
       parent     *roLayer
       cacheID    string
       size       int64
       layerStore *layerStore
       descriptor distribution.Descriptor

       referenceCount int
       references     map[Layer]struct{}
}

每一层都包括指向父层的指针。如果没有这个指针,说明处于最底层。

 

 

1.7 CreateReadWrite函数

文件位于daemon/gradphdriver/aufs/aufs.go。主要功能是创建三个目录mntlayersdiff,在将父层id记录

 

if err := a.createDirsFor(id)err != nil {
       return err
}

创建三个目录 mntlayersdiff

ferr := os.Create(path.Join(a.rootPath()"layers"id))
if err != nil {
       return err
}

以层的metadata为后缀名创建文件

 

if parent != "" {
       idserr := getParentIDs(a.rootPath()parent)
       if err != nil {
              return err
       }

       if _err := fmt.Fprintln(fparent)err != nil {
              return err
       }
       for _i := range ids {
              if _err := fmt.Fprintln(fi)err != nil {
                     return err
              }
       }
}

获得该层的父层,存在将所有父层id记录该文件

 

 

 

1.8 registerMountPoints函数

位于daemon/volumes.go,注册所有挂载到容器的数据卷,bind挂载。主要有三种方式和来源:

1)容器本身自带的挂载的数据卷,容器的json镜像文件中 "Volumes"这个key对应内容;

2)其他容器(--volumes-from)挂载的数据卷;

3)命令行参数(-v)挂载与主机绑定的数据卷,与主机绑定得数据卷在docker中叫做bind-mounts

 


0 0
原创粉丝点击