docker 源碼入門

前言

docker是go語言編寫的,要看docker源碼,最起碼要學會go的基礎語法。

了解 docker 基礎架構(gòu) 以后??梢詫υ创a總體結(jié)構(gòu)有一個大體了解,然后就可以順利的進行源碼的入門解讀了。

本文主要剖析 docker-ce 的源碼。

docker-ce github:
https://github.com/docker/docker-ce

環(huán)境

操作系統(tǒng):centos7
docker版本:docker-ce: 18.09

正文

docker 源碼簡介

https://github.com/docker,這里是docker源碼的家目錄。
可以看到這里有許多許多的項目,比如:docker-engine、docker-ce、cli等,這些項目和docker的架構(gòu)都有關(guān)系,我安裝時就只安裝了一個,為啥這里這么多?到底如何查看?

首先要說一點,docker這個項目的源碼挺雜。

docker 家目錄下包含:docker-engine、docker-ce、cli等。

進入docker-ce可以發(fā)現(xiàn) components下也有cli 和 engine。

通過簡單得對比,發(fā)現(xiàn)docker-ce下得cli 和 engine與docker家目錄下得docker-engine和cli是一樣得。也就是docker-ce只是組合了docker-engine,cli等。

還有一個概念需要提,docker項目 fork 自 moby。

進入到 docker-ce 中,
可以在 components 中看到:

components

在我們安裝完docker時,使用 docker version 命令可以看到一個docker client和一個docker server。docker client 對應這里的cli;docker server對應這里的engine。
至于那個package,可以暫時不用管它。

當我們使用 docker start <container> 。一個容器是如何被啟動起來的?

閱讀源碼前,可以先猜測一下主體流程:

  1. 如何生成命令行供我們使用?
  2. 在調(diào)用命令行后,如何訪問到docker server 提供的 restful api?
  3. docker engine 一定在監(jiān)聽 restful api 對應的地址!
  4. docker engine 收到指令,接下來如何執(zhí)行?
  5. docker engine 執(zhí)行完,我們也可以收拾收拾進入下一階段的學習了!
docker 源碼解讀

根據(jù)上文猜測的 啟動容器 流程,進行源碼解讀。
兩個部分:

  1. 命令行:https://github.com/docker/docker-ce/tree/18.09/components/cli
  2. server :https://github.com/docker/docker-ce/tree/18.09/components/engine
1. 如何生成命令行供我們使用?

很明顯了,這是cli組件。那么直接進cli目錄中進行翻看。(注:docker 使用 cobra 這個包去實現(xiàn)命令行功能。)

每一個功能模塊或程序都會存在一個入口函數(shù)。

根據(jù)經(jīng)驗,docker.go是功能的入口,它在:https://github.com/docker/docker-ce/blob/18.09/components/cli/cmd/docker/docker.go

入口函數(shù)找到了,先放到一邊?,F(xiàn)在去找具體命令行實現(xiàn)的地方。

現(xiàn)在去到 https://github.com/docker/docker-ce/tree/18.09/components/cli/cli/command 這個目錄下。這個目錄下的子目錄,看著是不是稍微有點眼熟?使用 docker --help 列出來的子命令,有一個算一個,分別對應這些子目錄!

排查容器啟動流程,當然去container目錄下,進入container目錄后,可以清晰的看到容器相關(guān)命令對應的文件!到這里,可以看出docker cli的目錄結(jié)構(gòu)和命令行的結(jié)構(gòu)十分相似!

找到 start.go,主要代碼如下:

image.png

稍微去了解了一下 cobra 。根據(jù)其使用方式,可以知道這里就是定義docker start 命令的地方了。上圖標注處,是下面第2步驟需要分析的代碼。

至此,命令定義的地方已經(jīng)找到,接下來就是分析命令如何執(zhí)行。

2. 在調(diào)用命令行后,如何訪問到docker server 提供的 restful api?

在上面那張圖里的 runSatrt 方法中可以發(fā)現(xiàn) 啟動容器指向 dockerCli.Client().ContainerStart。如下:
https://github.com/docker/docker-ce/blob/18.09/components/cli/cli/command/container/start.go

image.png

結(jié)合導包,dockerCli 指向 command.Cli , 而 command.Cli 中的 Client 指向 docker/docker/client。如下:
https://github.com/docker/docker-ce/blob/18.09/components/engine/client/client.go

image.png

現(xiàn)在 client 已找到,接下來順著 client 去找 ContainerStart 。
在當前client下并沒有發(fā)現(xiàn)目標方法。這也是go的一個特點,其它的文件也可以聲明成該client。
最后在 container_start.go 發(fā)現(xiàn)了目標方法,如下:
https://github.com/docker/docker-ce/blob/18.09/components/engine/client/container_start.go

image.png

如上圖,這個 ContainerStart 方法調(diào)用的是 cli.post。很明顯的,這是一個訪問restful api的封裝方法。

至此,客戶端行為基本結(jié)束。向 "/containers/<containerID>/start" 地址發(fā)送了一個post請求。

接下來便是去服務端找到監(jiān)聽這個地址的方法。

3. docker engine 一定在監(jiān)聽 restful api 對應的地址!

對于一個web server。路由可以幫助我們快速找到地址對應的方法。

現(xiàn)在,進入到engine目錄下,開始分析源碼。

類似于 cli 組件,engine 組件也有入口函數(shù)。也叫 docker.go。這個文件了解就好,暫時不會用到。

路由的定義如下:
https://github.com/docker/docker-ce/blob/18.09/components/engine/api/server/router/container/container.go

image.png

至此,路由已然找到。接下來就是分析 postContainersStart 這個方法干了什么。

4. docker engine 收到指令,接下來如何執(zhí)行?

postContainersStart 方法位于:
https://github.com/docker/docker-ce/blob/18.09/components/engine/api/server/router/container/container_routes.go

image.png

在當前方法中,可以看到引用了 backend.ContainerStart 。

https://github.com/docker/docker-ce/blob/18.09/components/engine/api/server/router/container/backend.go 中可以找到 ContainerStart 的定義。具體由daemon實現(xiàn)。

daemon位于:https://github.com/docker/docker-ce/blob/18.09/components/engine/daemon。

其中 start.go 就是我們需要找的目標文件,如下:
https://github.com/docker/docker-ce/blob/18.09/components/engine/daemon/start.go

image.png

當前方法指向:daemon.containerStart ,該方法就在當前文件中。

到這里應該已經(jīng)差不多了,我們不是要從零開始寫一個docker。

擴展

總結(jié):

  1. 命令行或者sdk均是訪問 docker server 的restful api。
  2. docker server 源碼總體層次:【api】--【daemon】。api 定義路由,daemon實現(xiàn)路由中的具體方法。
  3. docker-ce 中的cli和engine略有交叉,對于常見 c/s 架構(gòu),這種代碼交叉的情況比較少。一般 client 為單獨部署的方式,而docker 并沒有將cli獨立出來,可能是由于設計初衷就不是集群模式。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容