摘要:源碼走讀在運行時發生了什么標簽空格分隔原文作者是,原文地址是在這篇博文中我將回答一下問題運行一個期間內部發生了什么開始首先從并檢查代碼。這個發生在和行之間。如果一個錯誤發生,它會被記錄,然后程序退出。這些覆蓋了在客戶端里面發生了什么。
Docker 源碼走讀 - 在運行 Docker run 時發生了什么?
標簽(空格分隔): Docker
原文作者是 Frank Scholten,原文地址是 Docker code walkthrough – What happens during a Docker run?
在這篇博文中我將回答一下問題:運行一個 Docker run 期間 Docker 內部發生了什么?
開始首先從 Docker Github repo clone 并檢查代碼。
$ git clone https://github.com/docker/docker范讀
用你喜歡的編輯器打開工程并且范讀下 main tree。Docker 是使用 golang 編寫并由很多包組成。比如,從頂部到底部開始瀏覽,你會看到 api, builder, builtins, contrib 等等。一些目錄包含更多的子目錄。
Docker executable 內部第一件事,就是尋找 func main,當我們運行 Docker executable 時被執行的 Golang 函數。實際上,在代碼樹中有超過 30 個 main 函數。這些都是工具類的函數,我不會立即就深入其中。讓我們繼續我們主要尋找的:存在于 docker/docker.go 中的一個 main 函數。讓我們更仔細的看。
解析 flags看以下的代碼片段,顯示了 main func 的前十幾行。當 Docker 啟動,它通過 reexec 運行任何的初始化(initializers),如果有,這時它為 Docker executable 解析通過 mflag 包傳遞的參數。這個包在 pkg/mgflag 下面,別名為 flag。如果需要的話,在這一點它可以打印出版本信息或是開啟 debug 模式并記錄 debug 日志。
func main() { if reexec.Init() { return } flag.Parse() // FIXME: validate daemon flags here if *flVersion { showVersion() return } if *flDebug { os.Setenv("DEBUG", "1") } initLogging(*flDebug) ... SNIP }Dispatch Docker command & error handling
在選擇解析 Docker 捕獲的主機設置后,如果有必要,對服務器執行 TLS verification 校驗。這個發生在 40 和 107 行之間。看以下的代碼片段。flags 解析早于傳遞給來自于 api/client/cli.go 的 DockerCli 類型的 Cmd 方法。
如果一個錯誤發生,它會被記錄,然后程序退出。
func main() { ... SNIP if err := cli.Cmd(flag.Args()...); err != nil { if sterr, ok := err.(*utils.StatusError); ok { if sterr.Status != "" { log.Println("%s", sterr.Status) } os.Exit(sterr.StatusCode) } log.Fatal(err) } }cli 包
讓我們深入 cli 包看看 Docker 命令被怎樣處理的。為了能夠運行子命令,我們關注 3 件事:
DockerCli struct
Cmd 方法
GetMethod 方法
DockerCliDockerCli struct 包含每個 Docker 命令必需的數據結構,比如使用的協議, in-, output- 和 error writers 以及 TLS 指定的數據結構。
type DockerCli struct { proto string addr string configFile *registry.ConfigFile in io.ReadCloser out io.Writer err io.Writer key libtrust.PrivateKey tlsConfig *tls.Config scheme string // inFd holds file descriptor of the client"s STDIN, if it"s a valid file inFd uintptr // outFd holds file descriptor of the client"s STDOUT, if it"s a valid file outFd uintptr // isTerminalIn describes if client"s STDIN is a TTY isTerminalIn bool // isTerminalOut describes if client"s STDOUT is a TTY isTerminalOut bool transport *http.Transport }Cmd 方法
Cmd 函數的職責是通過使用 getMethod 函數 把命令參數轉換成一個函數。它將來已經支持多個命令,也許是 docker groups create,盡管目前為止我知道還沒有這樣的命令實現。
func (cli *DockerCli) Cmd(args ...string) error { if len(args) > 1 { method, exists := cli.getMethod(args[:2]...) if exists { return method(args[2:]...) } } if len(args) > 0 { method, exists := cli.getMethod(args[0]) if !exists { fmt.Println("Error: Command not found:", args[0]) return cli.CmdHelp(args[1:]...) } return method(args[1:]...) } return cli.CmdHelp(args...) }getMethod
注意 getMethod 是小寫字母。這意味著它無法導出包外,因此它僅僅是在 cli 內可用的。因此這個方法怎樣找出正確的函數?看下面的代碼片段。它首先建立一個以 Cmd 開始的由大寫字母組合的 string。萬一 Docker 運行 methodName 變量將被 CmdRun。使用來自于 Golang reflect 包的 MethodByName 函數,它檢索到一個函數指針并返回它。
func (cli *DockerCli) getMethod(args ...string) (func(...string) error, bool) { camelArgs := make([]string, len(args)) for i, s := range args { if len(s) == 0 { return nil, false } camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) } methodName := "Cmd" + strings.Join(camelArgs, "") fmt.Println(methodName) method := reflect.ValueOf(cli).MethodByName(methodName) if !method.IsValid() { return nil, false } return method.Interface().(func(...string) error), true }CmdRun
最后我們到達一個負責容器運行的函數:在 api/client/commands.go 的 CmdRun。這個文件包含了所有的 Docker 命令。它自己運行的參數被解析,比如 image,command 和其他參數。因為我們已經通讀,我不會展示那些代碼,我會以展示更有趣的事代替:運行命令啟動一個新的容器。
創建容器以下代碼片段展示了容器是怎樣被創建的。容器的配置被合并到 run config 和 host config。
實際創建一個容器是調用一個 HTTP POST 給 Docker 服務器。
func (cli *DockerCli) CmdRun(args ...string) error { SNIP ... runResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName) if err != nil { return err } SNIP ... } func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (engine.Env, error) { containerValues := url.Values{} if name != "" { containerValues.Set("name", name) } mergedConfig := runconfig.MergeConfigs(config, hostConfig) var containerIDFile *cidFile if cidfile != "" { var err error if containerIDFile, err = newCIDFile(cidfile); err != nil { return nil, err } defer containerIDFile.Close() } //create the container stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false) //if image not found try to pull it if statusCode == 404 { fmt.Fprintf(cli.err, "Unable to find image "%s" locally ", config.Image) // we don"t want to write to stdout anything apart from container.ID if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil { return nil, err } // Retry if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false); err != nil { return nil, err } } else if err != nil { return nil, err } var result engine.Env if err := result.Decode(stream); err != nil { return nil, err } for _, warning := range result.GetList("Warnings") { fmt.Fprintf(cli.err, "WARNING: %s ", warning) } if containerIDFile != nil { if err = containerIDFile.Write(result.Get("Id")); err != nil { return nil, err } } return result, nil }
這些覆蓋了在 Docker 客戶端里面發生了什么。當然在 Docker 服務器和 libcontainer 還有更多的代碼等待探索,但這將會留給以后的博文。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26346.html
摘要:標簽空格分隔資源管理內存磁盤注該文作者是,原文是。如果你運行命令,你自己可以看到這個結構當我們想管理資源的時候,這個方法提供了很大的靈活性,因為我們可以分別的管理每個組。 標簽(空格分隔): Docker 資源管理 內存 CPU 磁盤 I/O 注:該文作者是 Marek Goldmann,原文是 Resource management in Docker。 在這篇博客文章...
摘要:工程師選擇了環境中的一臺當前沒有在負載均衡器中被激活的主機。工程師登陸到這臺主機并從注冊表中獲取新的版本。在生產維護窗口中,更新負載均衡器使其指向更新過的主機。然而將部署代碼化的問題仍然存在。 這篇文章是一系列文章的第一篇,在這一系列文章中,我們想要分享我們如何使用Docker、Docker-Compose和Rancher完成容器部署工作流的故事。我們想帶你從頭開始走過pipeline...
摘要:年我們開始專注于開源云計算技術,當時開源的力量正在逐漸浮現。問你現在在實驗室的工作是什么我主要負責實驗室云計算團隊的技術工作,以及與技術相關的其他事宜,包括開源以及一些商業上的技術合作。 非商業轉載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203520 張磊,浙江大學計算機學院博士生,科研人員,VLIS實驗室云計算組技...
摘要:年我們開始專注于開源云計算技術,當時開源的力量正在逐漸浮現。問你現在在實驗室的工作是什么我主要負責實驗室云計算團隊的技術工作,以及與技術相關的其他事宜,包括開源以及一些商業上的技術合作。 非商業轉載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203520 張磊,浙江大學計算機學院博士生,科研人員,VLIS實驗室云計算組技...
摘要:年我們開始專注于開源云計算技術,當時開源的力量正在逐漸浮現。問你現在在實驗室的工作是什么我主要負責實驗室云計算團隊的技術工作,以及與技術相關的其他事宜,包括開源以及一些商業上的技術合作。 非商業轉載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203520 張磊,浙江大學計算機學院博士生,科研人員,VLIS實驗室云計算組技...
閱讀 1368·2021-09-13 10:25
閱讀 552·2019-08-30 15:53
閱讀 2265·2019-08-30 15:44
閱讀 2026·2019-08-29 17:20
閱讀 1594·2019-08-29 16:36
閱讀 1795·2019-08-29 14:10
閱讀 1785·2019-08-29 12:44
閱讀 1168·2019-08-23 14:13