[TOC=3]
## 1.Docker Server簡介
Docker架構中,Docker Server是Docker Daemon的重要組成部分。Docker Server最主要的功能是:接受用戶通過Docker Client發送的請求,并按照相應的路由規則實現路由分發。
同時,Docker Server具備十分優秀的用戶友好性,多種通信協議的支持大大降低Docker用戶使用Docker的門檻。除此之外,Docker Server設計實現了詳盡清晰的API接口,以供Docker用戶選擇使用。通信安全方面,Docker Server可以提供安全傳輸層協議(TLS),保證數據的加密傳輸。并發處理方面,Docker Daemon大量使用了Golang中的goroutine,大大提高了服務端的并發處理能力。
本文為《Docker源碼分析》系列的第五篇——Docker Server的創建。
## 2\. Docker Server源碼分析內容安排
本文將從源碼的角度分析Docker Server的創建,分析內容的安排主要如下:
(1) “serveapi”這個job的創建并執行流程,代表Docker Server的創建;
(2) “serveapi”這個job的執行流程深入分析;
(3) Docker Server創建Listener并服務API的流程分析。
## 3.Docker Server創建流程
[《Docker源碼分析(三):Docker Daemon啟動》](http://www.infoq.com/cn/articles/docker-source-code-analysis-part3)主要分析了Docker Daemon的啟動,而在mainDaemon()運行的最后環節,實現了創建并運行名為”serveapi”的job。這一環節的作用是:讓Docker Daemon提供API訪問服務。實質上,這正是實現了Docker架構中Docker Server的創建與運行。
從流程的角度來說,Docker Server的創建并運行,代表了”serveapi”這個job的整個生命周期:創建Job實例job,配置job環境變量,以及最終執行該job。本章分三節具體分析這三個不同的階段。
### 3.1創建名為”serveapi”的job
Job是Docker架構中Engine內部最基本的任務執行單位,故創建Docker Server這一任務的執行也不例外,需要表示為一個可執行的Job。換言之,需要創建Docker Server,則必須創建一個相應的Job。具體的Job創建形式位于[./docker/docker/daemon.go](https://github.com/docker/docker/blob/v1.2.0/docker/daemon.go#L66),如下:
~~~
job := eng.Job("serveapi", flHosts...)
~~~
以上代碼通過Engine實例eng創建一個Job類型的實例job,job名為”serveapi”,同時用flHost的值來初始化job.Args。flHost的作用是:配置Docker Server監聽的協議與監聽的地址。
需要注意的是,《Docker源碼分析(三):Docker Daemon啟動》mainDaemon()具體實現過程中,在加載builtins環節已經向eng對象注冊了key為”serveapi”的Handler,而該Handler的value為api.ServeApi。因此,在運行名為”serveapi”的job時,會執行該job的Handler,即api.ServeApi。
### 3.2配置job環境變量
創建完Job實例job之后,Docker Daemon為job配置環境參數。在Job實現過程中,為Job配置參數有兩種方式:第一,創建Job實例時,用指定參數直接初始化Job的Args屬性;第二,創建完Job后,給Job添加指定的環境變量。以下代碼則實現了為創建的job配置環境變量:
~~~
job.SetenvBool("Logging", true)
job.SetenvBool("EnableCors", *flEnableCors)
job.Setenv("Version", dockerversion.VERSION)
job.Setenv("SocketGroup", *flSocketGroup)
job.SetenvBool("Tls", *flTls)
job.SetenvBool("TlsVerify", *flTlsVerify)
job.Setenv("TlsCa", *flCa)
job.Setenv("TlsCert", *flCert)
job.Setenv("TlsKey", *flKey)
job.SetenvBool("BufferRequests", true)
~~~
對于以上配置,環境變量的歸納總結如下表:
| 環境變量名 | flag參數 | 默認值 | 作用值 |
|---|---|---|---|
| Logging | | true | 使用日志輸出 |
| EnableCors | flEnableCors | false | 在遠程API中提供CORS頭 |
| Version | | | 顯示Docker版本號 |
| SocketGroup | flSocketGroup | “docker” | 在daemon模式中unix domain socket分配用戶組名 |
| Tls | flTls | false | 使用TLS安全傳輸協議 |
| TlsVerify | flTlsVerify | false | 使用TLS并驗證遠程Client |
| TlsCa | flCa | | 指定CA文件路徑 |
| TlsCert | flCert | | TLS證書文件路徑 |
| TlsKey | flKey | | TLS密鑰文件路徑 |
| BufferRequest | | true | 緩存Docker Client請求 |
### 3.3 運行job
配置完畢job的環境變量,隨即執行job的運行函數,具體實現代碼如下:
~~~
if err := job.Run(); err != nil {
log.Fatal(err)
}
~~~
在eng對象中已經注冊過key為”serveapi”的Handler,故在運行job的時候,執行這個Handler的value值,相應Handler的value為api.ServeApi。至此,名為”serveapi”的job的生命周期已經完備。下文將深入分析job的Handler,api.ServeApi執行細節的具體實現。
## 4.ServeApi運行流程
本章將深入分析Docker Server提供API服務的部分,從源碼的角度剖析Docker Server的架構設計與實現。
作為一個監聽請求、處理請求的服務端,Docker Server首先明確自身需要為多少種通信協議提供服務,在Docker這個C/S模式的架構中,可以使用的協議無外乎三種:TCP協議,Unix Socket形式,以及fd的形式。隨后,Docker Server根據協議的不同,分別創建不同的服務端實例。最后,在不同的服務端實例中,創建相應的路由模塊,監聽模塊,以及處理請求的Handler,形成一個完備的server。
”serveapi”這個job在運行時,將執行api.ServeApi函數。ServeApi的功能是:循環檢查所有Docker Daemon當前支持的通信協議,并對于每一種協議都創建一個goroutine,在這個goroutine內部配置一個服務于HTTP請求的server端。ServeApi的代碼實現位于[./docker/api/server/server.go#L1339](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1339-L1368):
第一,判斷job.Args的長度是否為0,由于通過flHosts來初始化job.Args,故job.Args的長度若為0的話,說明沒有Docker Server沒有監聽的協議與地址,參數有誤,返回錯誤信息。代碼如下:
~~~
if len(job.Args) == 0 {
return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
}
~~~
第二,定義兩個變量,protoAddrs代表flHosts的內容;而chError定義了和protoAddrs長度一致的error類型channel管道,chError的作用在下文中會說明。同時還定義了activationLock,這是一個用來同步”serveapi”和”acceptconnections”這兩個job執行的channel。在serveapi運行時ServeFd和ListenAndServe的實現中,由于activationLock這個channel中沒有內容而阻塞,而當運行”acceptionconnections”這個job時,會首先通知init進程Docker Daemon已經啟動完畢,并關閉activationLock,同時也開啟了serveapi的繼續執行。正是由于activationLock的存在,保證了”acceptconnections”這個job的運行起到通知”serveapi”開啟正式服務于API的效果。代碼如下:
~~~
var (
protoAddrs = job.Args
chErrors = make(chan error, len(protoAddrs))
)
activationLock = make(chan struct{})
~~~
第三,遍歷protoAddrs,即job.Args,將其中的每一項都按照字符串“://”進行分割,若分割后protoAddrParts的長度不為2,則說明協議加地址的書寫形式有誤,返回job錯誤;若不為2,則分割獲得每一項中的協議protoAddrPart[0]與地址protoAddrParts[1]。最后分別創建一個goroutine來執行ListenAndServe的操作。goroutine的運行主要依賴于ListenAndServe(protoAddrParts[0], protoAddrParts[1], job)的運行結果,若返回error,則chErrors中有error,當前goroutine執行完畢;若沒有返回error,則該goroutine持續運行,持續提供服務。其中最為重要的是ListenAndServe的實現,該函數具體實現了如何創建listener、router以及server,并協調三者進行工作,最終服務于API請求。代碼如下:
~~~
for _, protoAddr := range protoAddrs {
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
if len(protoAddrParts) != 2 {
return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
}
go func() {
log.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job)
}()
}
~~~
第四,根據chErrors的值運行,若chErrors這個channel中有錯誤內容,則ServeApi該函數返回;若無錯誤內容,則循環被阻塞。代碼如下:
~~~
for i := 0; i < len(protoAddrs); i += 1 {
err := <-chErrors
if err != nil {
return job.Error(err)
}
}
return engine.StatusOK
~~~
至此, ServeApi的運行流程已經詳細分析完畢,其中核心部分ListenAndServe的實現,下一章開始深入。
## 5.ListenAndServe實現
ListenAndServe的功能是:使Docker Server監聽某一指定地址,接受該地址上的請求,并對以上請求路由轉發至相應的處理函數Handler處。從實現的角度來看,ListenAndServe主要實現了設置一個服務于HTTP的server,該server將監聽指定地址上的請求,并對請求做特定的協議檢查,最終完成請求的路由與分發。代碼實現位于[./docker/api/server/server.go](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1247-L1335)。
ListenAndServe的實現可以分為以下4個部分:
(1) 創建router路由實例;
(2) 創建listener監聽實例;
(3) 創建http.Server;
(4) 啟動API服務。
ListenAndServe的執行流程如下圖:

圖5.1 ListenAndServer執行流程圖
下文將按照ListenAndServe執行流程圖一一深入分析各個部分。
### 5.1 創建router路由實例
首先,ListenAndServe的實現中通過createRouter創建了一個router路由實例。代碼實現如下:
~~~
rr, err := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"))
if err != nil {
return err
}
~~~
createRouter的實現位于[./docker/api/server/server.go#L1094](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1094-L1171)。
創建router路由實例是一個重要的環節,路由實例的作用是:負責Docker Server對請求進行路由以及分發。實現過程中,主要兩個步驟:第一,創建全新的router路由實例;第二,為router實例添加路由記錄。
#### **5.1.1** **創建空路由實例**
實質上,createRouter通過包gorilla/mux實現了一個功能強大的路由器和分發器。如下:
~~~
r := mux.NewRouter()
~~~
NewRouter()函數返回了一個全新的router實例r。在創建Router實例時,給Router對象的兩個屬性進行賦值,這兩個屬性為nameRoutes和KeepContext。其中namedRoutes屬性為一個map類型,其中key為string類型,value為Route路由記錄類型;另外,KeepContext屬性為false,表示Docker Server在處理完請求之后,就清除請求的內容,不對請求做存儲操作。代碼位于[./docker/vendor/src/github.com/gorilla/mux/mux.go#L16](https://github.com/docker/docker/blob/v1.2.0/vendor/src/github.com/gorilla/mux/mux.go#L16-L18),如下:
~~~
func NewRouter() *Router {
return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}
~~~
可見,以上代碼返回的類型為mux.Router。mux.Router會通過一系列已經注冊過的路由記錄,來為接受的請求做匹配,首先通過請求的URL或者其他條件,找到相應的路由記錄,并調用這條路由記錄中的執行Handler。mux.Router有以下這些特性:
* 請求可以基于URL 的主機名、路徑、路徑前綴、shemes、請求頭和請求值、HTTP請求方法類型或者使用自定義的匹配規則;
* URL主機名和路徑可以擁有一個正則表達式來表示;
* 注冊的URL可以被直接運用,也可以被保留,這樣可以保證維護資源的使用;
* 路由記錄可以被用以子路由器:如果父路由記錄匹配,則嵌套記錄只會被用來測試。當設計一個組內的路由記錄共享相同的匹配條件時,如主機名、路勁前綴或者其他重復的屬性,子路由的方式很有幫助;
* mux.Router實現了http.Handler接口,故和標準的http.ServeMux兼容。
#### **5.1.2** **添加路由記錄**
Router路由實例r創建完畢,下一步工作是為Router實例r添加所需要的路由記錄。路由記錄存儲著用來匹配請求的信息,包括對請求的匹配規則,以及匹配之后的Handler執行入口。
回到[createRouter實現代碼](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1094-L1171)中,首先判斷Docker Daemon的啟動過程中有沒有開啟DEBUG模式。通過docker可執行文件啟動Docker Daemon,解析flag參數時,若flDebug的值為false,則說明不需要配置DEBUG環境;若flDebug的值為true,則說明需要為Docker Daemon添加DEBUG功能。具體的代碼實現如下:
~~~
if os.Getenv("DEBUG") != "" {
AttachProfiler(r)
}
~~~
AttachProiler(r)的功能是為路由實例r添加與DEBUG相關的路由記錄,具體實現位于[./docker/api/server/server.go#L1083](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1083-L1092),如下:
~~~
func AttachProfiler(router *mux.Router) {
router.HandleFunc("/debug/vars", expvarHandler)
router.HandleFunc("/debug/pprof/", pprof.Index)
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
router.HandleFunc("/debug/pprof/profile", pprof.Profile)
router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
router.HandleFunc("/debug/pprof/heap", pprof.Handler("heap").ServeHTTP)
router.HandleFunc("/debug/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP)
router.HandleFunc("/debug/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP)
}
~~~
分析以上源碼,可以發現Docker Server使用兩個包來完成DEBUG相關的工作:expvar和pprof。包expvar為公有變量提供標準化的接口,使得這些公有變量可以通過HTTP的形式在”/debug/vars”這個URL下被訪問,傳輸時格式為JSON。包pprof將Docker Server運行時的分析數據通過”/debug/pprof/”這個URL向外暴露。這些運行時信息包括以下內容:可得的信息列表、正在運行的命令行信息、CPU信息、程序函數引用信息、ServeHTTP這個函數三部分信息使用情況(堆使用、goroutine使用和thread使用)。
回到[createRouter函數實現](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1094-L1171)中,完成DEBUG功能的所有工作之后,Docker Docker創建了一個map類型的對象m,用于初始化路由實例r的路由記錄。簡化的m對象,代碼如下:
~~~
m := map[string]map[string]HttpApiFunc{
"GET": {
……
"/images/{name:.*}/get": getImagesGet,
……
},
"POST": {
……
"/containers/{name:.*}/copy": postContainersCopy,
},
"DELETE": {
"/containers/{name:.*}": deleteContainers,
"/images/{name:.*}": deleteImages,
},
"OPTIONS": {
"": optionsHandler,
},
}
~~~
對象m的類型為map,其中key為string類型,代表HTTP的請求類型,如”GET”,”POST”,”DELETE”等,value為另一個map類型,該map代表的是URL與執行Handler的映射。在第二個map類型中,key為string類型,代表是的請求URL,value為HttpApiFunc類型,代表具體的執行Handler。其中HttpApiFunc類型的定義如下:
~~~
type HttpApiFunc func(eng *engine.Engine, version version.Version,
w http.ResponseWriter, r *http.Request, vars map[string]string) error
~~~
完成對象m的定義,隨后Docker Server通過該對象m來添加路由實例r的路由記錄。對象m的請求方法,請求URL和請求處理Handler這三樣內容可以為對象r構建一條路由記錄。實現代碼。如下:
~~~
for method, routes := range m {
for route, fct := range routes {
log.Debugf("Registering %s, %s", method, route)
localRoute := route
localFct := fct
localMethod := method
f := makeHttpHandler(eng, logging, localMethod,
localRoute, localFct, enableCors, version.Version(dockerVersion))
if localRoute == "" {
r.Methods(localMethod).HandlerFunc(f)
} else {
r.Path("/v{version:[0-9.]+}" + localRoute).
Methods(localMethod).HandlerFunc(f)
r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
}
}
}
~~~
以上代碼,在第一層循環中,按HTTP請求方法劃分,獲得請求方法各自的路由記錄,第二層循環,按匹配請求的URL進行劃分,獲得與URL相對應的執行Handler。在嵌套循環中,通過makeHttpHandler返回一個執行的函數f。在返回的這個函數中,涉及了logging信息,CORS信息(跨域資源共享協議),以及版本信息。以下舉例說明makeHttpHandler的實現,從對象m可以看到,對于”GET”請求,請求URL為”/info”,則請求Handler為”getInfo”。執行makeHttpHandler的具體代碼實現如下:
~~~
func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string,
localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// log the request
log.Debugf("Calling %s %s", localMethod, localRoute)
if logging {
log.Infof("%s %s", r.Method, r.RequestURI)
}
if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
log.Debugf("Warning: client and server don't have the same version
(client: %s, server: %s)", userAgent[1], dockerVersion)
}
}
version := version.Version(mux.Vars(r)["version"])
if version == "" {
version = api.APIVERSION
}
if enableCors {
writeCorsHeaders(w, r)
}
if version.GreaterThan(api.APIVERSION) {
http.Error(w, fmt.Errorf("client and server don't have same version
(client : %s, server: %s)", version, api.APIVERSION).Error(), http.StatusNotFound)
return
}
if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil {
log.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
httpError(w, err)
}
}
}
~~~
可見makeHttpHandler的執行直接返回一個函數func(w http.ResponseWriter, r *http.Request) 。在這個func函數的實現中,判斷makeHttpHandler傳入的logging參數,若為true,則將該Handler的執行通過日志顯示,另外通過makeHttpHandler傳入的enableCors參數判斷是否在HTTP請求的頭文件中添加跨域資源共享信息,若為true,則通過writeCorsHeaders函數向response中添加有關CORS的HTTP Header,代碼實現位于[./docker/api/server/server.go#L1022](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1022-L1026),如下:
~~~
func writeCorsHeaders(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*")
w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
}
~~~
最為重要的執行部分位于handlerFunc(eng, version, w, r, mux.Vars(r)),如以下代碼:
~~~
if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil {
log.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
httpError(w, err)
}
~~~
對于”GET”請求類型,”/info”請求URL的請求,由于Handler名為getInfo,也就是說handlerFunc這個形參的值為getInfo,故執行部分直接運行getInfo(eng, version, w, r, mux.Vars(r)),而getInfo的具體實現位于[./docker/api/server/serve.go#L269](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L269-L273),如下:
~~~
func getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter,
r *http.Request, vars map[string]string) error {
w.Header().Set("Content-Type", "application/json")
eng.ServeHTTP(w, r)
return nil
}
~~~
以上makeHttpHandler的執行已經完畢,返回func函數,作為指定URL對應的執行Handler。
創建完處理函數Handler,需要向路由實例中添加新的路由記錄。如果URL信息為空,則直接為該HTTP請求方法類型添加路由記錄;若URL不為空,則為請求URL路徑添加新的路由記錄。需要額外注意的是,在URL不為空,為路由實例r添加路由記錄時,考慮了API版本的問題,通過r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)來實現。
至此,mux.Router實例r的兩部分工作工作已經全部完成:創建空的路由實例r,為r添加相應的路由記錄,最后返回路由實例r。
現I時er路由記錄。需要額外的利次循環中,都有不同的組合1083lla/mux/mux.go,
### 5.2 創建listener監聽實例
路由模塊,完成了請求的路由與分發這一重要部分,屬于[ListenAndServe實現](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1247-L1335)中的第一個重要工作。對于請求的監聽功能,同樣需要模塊來完成。而在[ListenAndServe實現](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1247-L1335)中,第二個重要的工作就是創建Listener。Listener是一種面向流協議的通用網絡監聽模塊。
在創建Listener之前,先判斷Docker Server允許的協議,若協議為fd形式,則直接通過ServeFd來服務請求;若協議不為fd形式,則繼續往下執行。
在程序執行過程中,需要判斷”serveapi”這個job的環境中”BufferRequests”的值,是否為真,若為真,則通過包listenbuffer創建一個Listener的實例l,否則的話直接通過包net創建Listener實例l。具體的代碼位于[./docker/api/server/server.go#L1269](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1269-L1273),如下:
~~~
if job.GetenvBool("BufferRequests") {
l, err = listenbuffer.NewListenBuffer(proto, addr, activationLock)
} else {
l, err = net.Listen(proto, addr)
}
~~~
由于在mainDaemon()中創建”serveapi”這個job之后,給job添加環境變量時,已經給”BufferRequets”賦值為true,故使用包listenbuffer創建listener實例。
Listenbuffer的作用是:讓Docker Server可以立即監聽指定協議地址上的請求,但是將這些請求暫時先緩存下來,等Docker Daemon全部啟動完畢之后,才讓Docker Server開始接受這些請求。這樣設計有一個很大的好處,那就是可以保證在Docker Daemon還沒有完全啟動完畢之前,接收并緩存盡可能多的用戶請求。
若協議的類型為TCP,另外job中環境變量Tls或者TlsVerify有一個為真,則說明Docker Server需要支持HTTPS服務,需要為Docker Server配置安全傳輸層協議(TLS)的支持。為實現TLS協議,首先需要建立一個tls.Config類型實例tlsConfig,然后在tlsConfig中加載證書,認證信息等,最終通過包tls中的NewListener函數,創建出適應于接收HTTPS協議請求的Listener實例l,代碼如下:
~~~
l = tls.NewListener(l, tlsConfig)
~~~
至此,創建網絡監聽的Listener部分已經全部完成。
### 5.3 創建http.Server
Docker Server同樣需要創建一個Server對象來運行HTTP服務端。在[ListenAndServe實現](https://github.com/docker/docker/blob/v1.2.0/api/server/server.go#L1247-L1335)中第三個重要的工作就是創建http.Server:
~~~
httpSrv := http.Server{Addr: addr, Handler: r}
~~~
其中addr為需要監聽的地址,r為mux.Router路由實例。
### 5.4 啟動API服務
創建http.Server實例之后,Docker Server立即啟動API服務,使Docker Server開始在Listener監聽實例l上接受請求,并對于每一個請求都生成一個新的goroutine來做專屬服務。對于每一個請求,goroutine會讀取請求,查詢路由表中的路由記錄項,找到匹配的路由記錄,最終調用路由記錄中的執行Handler,執行完畢后,goroutine對請求返回響應信息。代碼如下:
~~~
return httpSrv.Serve(l)
~~~
至此,ListenAndServer的所有流程已經分析完畢,Docker Server已經開始針對不同的協議,服務API請求。
## 6.總結
Docker Server作為Docker Daemon架構中請求的入口,接管了所有Docker Daemon對外的通信。通信API的規范性,通信過程的安全性,服務請求的并發能力,往往都是Docker用戶最為關心的內容。本文基于源碼,分析了Docker Server大部分的細節實現。希望Docker用戶可以初探Docker Server的設計理念,并且可以更好的利用Docker Server創造更大的價值。
## 7.作者簡介
孫宏亮,[DaoCloud](http://www.daocloud.io/)初創團隊成員,軟件工程師,浙江大學VLIS實驗室應屆研究生。讀研期間活躍在PaaS和Docker開源社區,對Cloud Foundry有深入研究和豐富實踐,擅長底層平臺代碼分析,對分布式平臺的架構有一定經驗,撰寫了大量有深度的技術博客。2014年末以合伙人身份加入DaoCloud團隊,致力于傳播以Docker為主的容器的技術,推動互聯網應用的容器化步伐。郵箱:[allen.sun@daocloud.io](mailto:allen.sun@daocloud.io)
## 8.參考文獻
[http://guzalexander.com/2013/12/06/golang-channels-tutorial.html](http://guzalexander.com/2013/12/06/golang-channels-tutorial.html)
[http://www.gorillatoolkit.org/pkg/mux](http://www.gorillatoolkit.org/pkg/mux)
[http://docs.studygolang.com/pkg/expvar/](http://docs.studygolang.com/pkg/expvar/)
[http://docs.studygolang.com/pkg/net/http/pprof/](http://docs.studygolang.com/pkg/net/http/pprof/)