Docker原始碼分析(二)之Docker Client
一、建立Docker Client
Docker是一個client/server的架構,通過二進位制檔案docker建立Docker客戶端將請求型別與引數傳送給Docker Server,Docker Server具體執行命令呼叫。
Docker Client執行流程圖如下:
說明:本文分析的程式碼為Docker 1.2.0版本。
(一)Docker命令flag引數解析
Docker Server與Docker Client由可執行檔案docker命令建立並啟動。
- Docker Server的啟動:docker -d或docker --daemon=true
- Docker Client的啟動:docker --daemon=false ps等
docker引數分為兩類:
- 命令列引數(flag引數):--daemon=true,-d
- 實際請求引數:ps ,images, pull, push等
/docker/docker.go
|
reexec.Init()作用:協調execdriver與容器建立時dockerinit的關係。如果返回值為真則直接退出執行,否則繼續執行。判斷reexec.Init()之後,呼叫flag.Parse()解析命令列中的flag引數。
/docker/flag.go
"G" , "-group" }, "docker" , "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group" )
|
flag.go定義了flag引數,並執行了init的初始化。
Go中的init函式
- 用於程式執行前包的初始化工作,比如初始化變數
- 每個包或原始檔可以包含多個init函式
- init函式不能被呼叫,而是在mian函式呼叫前自動被呼叫
- 不同init函式的執行順序,按照包匯入的順序執行
當解析到第一個非flag引數時,flag解析工作就結束。例如docker --daemon=flase --version=false ps
- 完成flag的解析,--daemon=false
- 遇到第一個非flag引數ps,則將ps及其後的引數存入flag.Args(),以便執行之後的具體請求。
(二)處理flag引數並收集Docker Client的配置資訊
處理的flag引數有flVersion,flDebug,flDaemon,flTlsVerify以及flTls。
/docker/docker.go
|
flHosts的作用是為Docker Client提供所要連線的host物件,也就是為Docker Server提供所要監聽的物件。
當flHosts為空,預設取環境變數DOCKER_HOST,若仍為空或flDaemon為真,則設定為unix socket,值為unix:///var/run/docker.sock。取自/api/common.go中的常量DEFAULTUNIXSOCKET。
/docker/docker.go
|
若flDaemon為真,表示啟動Docker Daemon,呼叫/docker/daemon.go中的func mainDaemon()。
/docker/docker.go
|
protoAddrParts的作用是解析出Docker Client 與Docker Server建立通訊的協議與地址,通過strings.SplitN函式分割儲存。flHosts[0]的值可以是tcp://0.0.0.0.2375或者unix:///var/run/docker.sock等。
/docker/docker.go
|
tlsConfig物件的建立是為了保障cli在傳輸資料的時候遵循安全傳輸層協議(TLS)。flTlsVerity引數為真,則說明Docker Client 需Docker Server一起驗證連線的安全性,如果flTls和flTlsVerity兩個引數中有一個為真,則說明需要載入併發送客戶端的證書。
/docker/flags.go
|
(三)如何建立Docker Client
/docker/docker.go
|
在已有配置引數的情況下,通過/api/client/cli.go中的NewDockerCli方法建立Docker Client例項cli。
/api/client/cli.go
|
二、Docke命令執行
(一)Docker Client解析請求命令
建立Docker Client,docker命令中的請求引數(例如ps,經flag解析後放入flag.Args()),分析請求引數及請求的型別,轉義為Docker Server可識別的請求後發給Docker Server。
/docker/docker.go
|
解析flag.Args()的具體請求引數,執行cli.Cmd函式。程式碼在/api/client/cli.go
/api/client/cli.go
|
在getMethod中,返回method值為“CmdPull”。最後執行method(args[1:]...),即CmdPull(args[1:]...)。
(二)Docker Client執行請求命令
docker pull ImageName中,即執行CmdPull(args[1:]...),args[1:]即為ImageName。命令程式碼在/api/client/command.go。
/api/client/commands.go
|
將args引數進行第二次flag引數解析,解析過程中先提取是否有符合tag這個flag的引數,若有賦值給tag引數,其餘存入cmd.NArg(),若沒有則所有的引數存入cmd.NArg()中。
/api/client/commands.go
|
通過remote變數先得到映象的repository名稱,並賦值給remote自身,隨後解析改變後的remote,得出映象所在的host地址,即Docker Registry的地址。若沒有指定預設為Docker Hub地址https://index.docker.io/v1/。
/api/client/commands.go
|
通過cli物件獲取與Docker Server的認證配置資訊。
/api/client/commands.go
|
定義pull函式:cli.stream("POST", "/images/create?"+v.Encode(),...)像Docker Server傳送POST請求,請求url為“"/images/create?"+v.Encode()”,請求的認證資訊為:map[string][]string{"X-Registry-Auth": registryAuthHeader,}
/api/client/commands.go
|
呼叫pull函式,實現下載請求傳送。後續有Docker Server接收到請求後具體實現。
文章參考:
《Docker原始碼分析》