docker命令之commit
阿新 • • 發佈:2018-12-26
1、命令用法
docker commit -a|--author[=""] -m|--message[=""] CONTAINER [REPOSITORY[:TAG]]
docker version:1.0.0
2、命令分析
例如 docker commit -a=author -m=balabala container-name repo:t
CmdCommit(api/client/command.go)----> PostCommit(api/server/server.go) ---> ContainerCommit(server/server.go)
3 步驟
3.1 CmdCommit
解析命令列引數。
name:Container名
repository:registry名
tag:tag名
解析registry是否正確if cmd.NArg() == 3 { fmt.Fprintf(cli.err, "[DEPRECATED] The format 'CONTAINER [REPOSITORY [TAG]]' as been deprecated. Please use CONTAINER [REPOSITORY[:TAG]]\n") name, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2) } else { name = cmd.Arg(0) repository, tag = utils.ParseRepositoryTag(cmd.Arg(1)) }
if repository != "" {
if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
return err
}
}
請求包變數填充,其中config是名為name的Container配置
v := url.Values{} v.Set("container", name) v.Set("repo", repository) v.Set("tag", tag) v.Set("comment", *flComment) v.Set("author", *flAuthor) var ( config *runconfig.Config env engine.Env )
向httpserver發起請求並解析返回的結果
stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false)
if err != nil {
return err
}
if err := env.Decode(stream); err != nil {
return err
}
3.2 PostCommit設定job環境引數
job.Setenv("repo", r.Form.Get("repo"))
job.Setenv("tag", r.Form.Get("tag"))
job.Setenv("author", r.Form.Get("author"))
job.Setenv("comment", r.Form.Get("comment"))
job.SetenvSubEnv("config", &config)
執行job並返回生成的映象id
if err := job.Run(); err != nil {
return err
}
env.Set("Id", engine.Tail(stdoutBuffer, 1))
3.3 ContainerCommit
得到映象名並 通過映象名得到container
name := job.Args[0]
container := srv.daemon.Get(name)
if container == nil {
return job.Errorf("No such container: %s", name)
}
獲取Container配置,並新建一個配置變數var (
config = container.Config
newConfig runconfig.Config
)
將命令上中攜帶的配置放入newConfig中if err := job.GetenvJson("config", &newConfig); err != nil {
return job.Error(err)
}
將映象中的Container配置合入新的配置中if err := runconfig.Merge(&newConfig, config); err != nil {
return job.Error(err)
}
做提交操作,job環境變數中的repo、tag將在將來要生成的lay作為標記img, err := srv.daemon.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &newConfig)
if err != nil {
return job.Error(err)
}
3.4 srv .daemon.Commit----> Commit(daemon/daemon.go)
掛在Container的檔案系統,Mount操作實際是就是將
if err := container.Mount(); err != nil {
return nil, err
}
對當前layer打包,ExportRw方法使用daemon的diff方法找出檔案系統中變化的部分並打包rwTar, err := container.ExportRw()
if err != nil {
return nil, err
}
建立新的layervar (
containerID, containerImage string
containerConfig *runconfig.Config
)
if container != nil {
containerID = container.ID
containerImage = container.Image
containerConfig = container.Config
}
img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
if err != nil {
return nil, err
}
如果有tag資訊,將tag打到新layer上if repository != "" {
if err := daemon.repositories.Set(repository, tag, img.ID, true); err != nil {
return img, err
}
}
在向下分析就是檔案系統驅動了,比如如何給Container中變動的東東做diff之類的,這部分還需要時間深入的瞭解docker使用各種檔案系統驅動及檔案系統本身。