<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                > 原文出處:[infoq中文站](http://www.infoq.com/cn/articles/docker-source-code-analysis-part1) 作者:孫宏亮 在[《深入淺出Docker》](http://www.hmoore.net/infoq/docker)系列文章的基礎上,InfoQ推出了《Docker源碼分析》系列文章。《深入淺出Docker》系列文章更多的是從使用角度出發,幫助讀者了解Docker的來龍去脈,而《Docker源碼分析》系列文章通過分析解讀Docker源碼,來讓讀者了解Docker的內部實現,以更好的使用Docker。總之,我們的目標是促進Docker在國內的發展以及傳播。另外,歡迎加入InfoQ Docker技術交流群,QQ群號:272489193。 - [1 背景](#) - [1.1 Docker簡介](#) - [1.2 Docker版本信息](#) - [2 Docker架構分析內容安排](#) - [3 Docker總架構圖](#) - [4 Docker架構內各模塊的功能與實現分析](#) - [4.1 Docker Client](#) - [4.2 Docker Daemon](#) - [4.3 Docker Registry](#) - [4.4 Graph](#) - [4.5 Driver](#) - [4.6 libcontainer](#) - [4.7 Docker container](#) - [5 Docker運行案例分析](#) - [5.1 docker pull](#) - [5.2 docker run](#) - [6 總結](#) - [7 作者簡介](#) - [8 參考文獻](#) ### 1 背景 ### 1.1 Docker簡介 Docker是Docker公司開源的一個基于輕量級虛擬化技術的容器引擎項目,整個項目基于Go語言開發,并遵從Apache 2.0協議。目前,Docker可以在容器內部快速自動化部署應用,并可以通過內核虛擬化技術(namespaces及cgroups等)來提供容器的資源隔離與安全保障等。由于Docker通過操作系統層的虛擬化實現隔離,所以Docker容器在運行時,不需要類似虛擬機(VM)額外的操作系統開銷,提高資源利用率,并且提升諸如IO等方面的性能。 由于眾多新穎的特性以及項目本身的開放性,Docker在不到兩年的時間里迅速獲得諸多廠商的青睞,其中更是包括Google、Microsoft、VMware等業界行業領導者。[Google在今年六月份推出了Kubernetes](https://github.com/GoogleCloudPlatform/kubernetes),提供Docker容器的調度服務,而今年8月[Microsoft宣布Azure上支持Kubernetes](http://www.infoq.com/cn/news/2014/09/azure-kubernetes),隨后[傳統虛擬化巨頭VMware宣布與Docker強強合作](http://www.infoq.com/cn/news/2014/08/vmware-partners-with-docker)。今年9月中旬,[Docker更是獲得4000萬美元的C輪融資](https://blog.docker.com/2014/09/docker-closes-40m-series-c-led-by-sequoia/),以推動分布式應用方面的發展。 從目前的形勢來看,Docker的前景一片大好。本系列文章從源碼的角度出發,詳細介紹Docker的架構、Docker的運行以及Docker的卓越特性。本文是Docker源碼分析系列的第一篇---——Docker架構篇。 ### 1.2 Docker版本信息 本文關于Docker架構的分析都是基于Docker的源碼與Docker相應版本的運行結果,其中Docker為最新的1.2版本。 ### 2 Docker架構分析內容安排 本文的目的是:在理解Docker源代碼的基礎上,分析Docker架構。分析過程中主要按照以下三個步驟進行: - Docker的總架構圖展示 - Docker架構圖內部各模塊功能與實現分析 - 以Docker命令的執行為例,進行Docker運行流程闡述 ### 3 Docker總架構圖 學習Docker的源碼并不是一個枯燥的過程,反而可以從中理解Docker架構的設計原理。Docker對使用者來講是一個C/S模式的架構,而Docker的后端是一個非常松耦合的架構,模塊各司其職,并有機組合,支撐Docker的運行。 在此,先附上Docker總架構,如圖3.1。 ![](https://box.kancloud.cn/2016-01-12_5694aac96745b.jpg) 圖3.1 Docker總架構圖 如圖3.1,不難看出,用戶是使用Docker Client與Docker Daemon建立通信,并發送請求給后者。 而Docker Daemon作為Docker架構中的主體部分,首先提供Server的功能使其可以接受Docker Client的請求;而后Engine執行Docker內部的一系列工作,每一項工作都是以一個Job的形式的存在。 Job的運行過程中,當需要容器鏡像時,則從Docker Registry中下載鏡像,并通過鏡像管理驅動graphdriver將下載鏡像以Graph的形式存儲;當需要為Docker創建網絡環境時,通過網絡管理驅動networkdriver創建并配置Docker容器網絡環境;當需要限制Docker容器運行資源或執行用戶指令等操作時,則通過execdriver來完成。 而libcontainer是一項獨立的容器管理包,networkdriver以及execdriver都是通過libcontainer來實現具體對容器進行的操作。 當執行完運行容器的命令后,一個實際的Docker容器就處于運行狀態,該容器擁有獨立的文件系統,獨立并且安全的運行環境等。 ### 4 Docker架構內各模塊的功能與實現分析 接下來,我們將從Docker總架構圖入手,抽離出架構內各個模塊,并對各個模塊進行更為細化的架構分析與功能闡述。主要的模塊有:Docker Client、Docker Daemon、Docker Registry、Graph、Driver、libcontainer以及Docker container。 ### 4.1 Docker Client Docker Client是Docker架構中用戶用來和Docker Daemon建立通信的客戶端。用戶使用的可執行文件為docker,通過docker命令行工具可以發起眾多管理container的請求。 Docker Client可以通過以下三種方式和Docker Daemon建立通信:tcp://host:port,unix://path_to_socket和fd://socketfd。為了簡單起見,本文一律使用第一種方式作為講述兩者通信的原型。與此同時,與Docker Daemon建立連接并傳輸請求的時候,Docker Client可以通過設置命令行flag參數的形式設置安全傳輸層協議(TLS)的有關參數,保證傳輸的安全性。 Docker Client發送容器管理請求后,由Docker Daemon接受并處理請求,當Docker Client接收到返回的請求相應并簡單處理后,Docker Client一次完整的生命周期就結束了。當需要繼續發送容器管理請求時,用戶必須再次通過docker可執行文件創建Docker Client。 ### 4.2 Docker Daemon Docker Daemon是Docker架構中一個常駐在后臺的系統進程,功能是:接受并處理Docker Client發送的請求。該守護進程在后臺啟動了一個Server,Server負責接受Docker Client發送的請求;接受請求后,Server通過路由與分發調度,找到相應的Handler來執行請求。 Docker Daemon啟動所使用的可執行文件也為docker,與Docker Client啟動所使用的可執行文件docker相同。在docker命令執行時,通過傳入的參數來判別Docker Daemon與Docker Client。 Docker Daemon的架構,大致可以分為以下三部分:Docker Server、Engine和Job。Daemon架構如圖4.1。 ![](https://box.kancloud.cn/2016-01-12_5694aac983f06.jpg) 圖4.1 Docker Daemon架構示意圖 #### 4.2.1 Docker Server Docker Server在Docker架構中是專門服務于Docker Client的server。該server的功能是:接受并調度分發Docker Client發送的請求。Docker Server的架構如圖4.2。 ![](https://box.kancloud.cn/2016-01-12_5694aac996b35.png) 圖4.2 Docker Server架構示意圖 在Docker的啟動過程中,通過包gorilla/mux,創建了一個mux.Router,提供請求的路由功能。在Golang中,gorilla/mux是一個強大的URL路由器以及調度分發器。該mux.Router中添加了眾多的路由項,每一個路由項由HTTP請求方法(PUT、POST、GET或DELETE)、URL、Handler三部分組成。 若Docker Client通過HTTP的形式訪問Docker Daemon,創建完mux.Router之后,Docker將Server的監聽地址以及mux.Router作為參數,創建一個httpSrv=http.Server{},最終執行httpSrv.Serve()為請求服務。 在Server的服務過程中,Server在listener上接受Docker Client的訪問請求,并創建一個全新的goroutine來服務該請求。在goroutine中,首先讀取請求內容,然后做解析工作,接著找到相應的路由項,隨后調用相應的Handler來處理該請求,最后Handler處理完請求之后回復該請求。 需要注意的是:Docker Server的運行在Docker的啟動過程中,是靠一個名為"serveapi"的job的運行來完成的。原則上,Docker Server的運行是眾多job中的一個,但是為了強調Docker Server的重要性以及為后續job服務的重要特性,將該"serveapi"的job單獨抽離出來分析,理解為Docker Server。 #### 4.2.2 Engine Engine是Docker架構中的運行引擎,同時也Docker運行的核心模塊。它扮演Docker container存儲倉庫的角色,并且通過執行job的方式來操縱管理這些容器。 在Engine數據結構的設計與實現過程中,有一個handler對象。該handler對象存儲的都是關于眾多特定job的handler處理訪問。舉例說明,Engine的handler對象中有一項為:{"create": daemon.ContainerCreate,},則說明當名為"create"的job在運行時,執行的是daemon.ContainerCreate的handler。 #### 4.2.3 Job 一個Job可以認為是Docker架構中Engine內部最基本的工作執行單元。Docker可以做的每一項工作,都可以抽象為一個job。例如:在容器內部運行一個進程,這是一個job;創建一個新的容器,這是一個job,從Internet上下載一個文檔,這是一個job;包括之前在Docker Server部分說過的,創建Server服務于HTTP的API,這也是一個job,等等。 Job的設計者,把Job設計得與Unix進程相仿。比如說:Job有一個名稱,有參數,有環境變量,有標準的輸入輸出,有錯誤處理,有返回狀態等。 ### 4.3 Docker Registry Docker Registry是一個存儲容器鏡像的倉庫。而容器鏡像是在容器被創建時,被加載用來初始化容器的文件架構與目錄。 在Docker的運行過程中,Docker Daemon會與Docker Registry通信,并實現搜索鏡像、下載鏡像、上傳鏡像三個功能,這三個功能對應的job名稱分別為"search","pull" 與 "push"。 其中,在Docker架構中,Docker可以使用公有的Docker Registry,即大家熟知的[Docker Hub](https://registry.hub.docker.com/),如此一來,Docker獲取容器鏡像文件時,必須通過互聯網訪問Docker Hub;同時Docker也允許用戶構建本地私有的Docker Registry,這樣可以保證容器鏡像的獲取在內網完成。 ### 4.4 Graph Graph在Docker架構中扮演已下載容器鏡像的保管者,以及已下載容器鏡像之間關系的記錄者。一方面,Graph存儲著本地具有版本信息的文件系統鏡像,另一方面也通過GraphDB記錄著所有文件系統鏡像彼此之間的關系。Graph的架構如圖4.3。 ![](https://box.kancloud.cn/2016-01-12_5694aac9c093f.jpg) 圖4.3 Graph架構示意圖 其中,GraphDB是一個構建在SQLite之上的小型圖數據庫,實現了節點的命名以及節點之間關聯關系的記錄。它僅僅實現了大多數圖數據庫所擁有的一個小的子集,但是提供了簡單的接口表示節點之間的關系。 同時在Graph的本地目錄中,關于每一個的容器鏡像,具體存儲的信息有:該容器鏡像的元數據,容器鏡像的大小信息,以及該容器鏡像所代表的具體rootfs。 ### 4.5 Driver Driver是Docker架構中的驅動模塊。通過Driver驅動,Docker可以實現對Docker容器執行環境的定制。由于Docker運行的生命周期中,并非用戶所有的操作都是針對Docker容器的管理,另外還有關于Docker運行信息的獲取,Graph的存儲與記錄等。因此,為了將Docker容器的管理從Docker Daemon內部業務邏輯中區分開來,設計了Driver層驅動來接管所有這部分請求。 在Docker Driver的實現中,可以分為以下三類驅動:graphdriver、networkdriver和execdriver。 graphdriver主要用于完成容器鏡像的管理,包括存儲與獲取。即當用戶需要下載指定的容器鏡像時,graphdriver將容器鏡像存儲在本地的指定目錄;同時當用戶需要使用指定的容器鏡像來創建容器的rootfs時,graphdriver從本地鏡像存儲目錄中獲取指定的容器鏡像。 在graphdriver的初始化過程之前,有4種文件系統或類文件系統在其內部注冊,它們分別是aufs、btrfs、vfs和devmapper。而Docker在初始化之時,通過獲取系統環境變量”DOCKER_DRIVER”來提取所使用driver的指定類型。而之后所有的graph操作,都使用該driver來執行。 graphdriver的架構如圖4.4: ![](https://box.kancloud.cn/2016-01-12_5694aac9dee26.png) 圖4.4 graphdriver架構示意圖 networkdriver的用途是完成Docker容器網絡環境的配置,其中包括Docker啟動時為Docker環境創建網橋;Docker容器創建時為其創建專屬虛擬網卡設備;以及為Docker容器分配IP、端口并與宿主機做端口映射,設置容器防火墻策略等。networkdriver的架構如圖4.5: ![](https://box.kancloud.cn/2016-01-12_5694aaca0ee95.jpg) 圖4. 5 networkdriver架構示意圖 execdriver作為Docker容器的執行驅動,負責創建容器運行命名空間,負責容器資源使用的統計與限制,負責容器內部進程的真正運行等。在execdriver的實現過程中,原先可以使用LXC驅動調用LXC的接口,來操縱容器的配置以及生命周期,而現在execdriver默認使用native驅動,不依賴于LXC。具體體現在Daemon啟動過程中加載的ExecDriverflag參數,該參數在配置文件已經被設為"native"。這可以認為是Docker在1.2版本上一個很大的改變,或者說Docker實現跨平臺的一個先兆。execdriver架構如圖4.6: ![](https://box.kancloud.cn/2015-11-12_56443b08219f3.jpg) 圖4.6 execdriver架構示意圖 ### 4.6 libcontainer libcontainer是Docker架構中一個使用Go語言設計實現的庫,設計初衷是希望該庫可以不依靠任何依賴,直接訪問內核中與容器相關的API。 正是由于libcontainer的存在,Docker可以直接調用libcontainer,而最終操縱容器的namespace、cgroups、apparmor、網絡設備以及防火墻規則等。這一系列操作的完成都不需要依賴LXC或者其他包。libcontainer架構如圖4.7: ![](https://box.kancloud.cn/2016-01-12_5694aaca2866e.jpg) 圖4.7 libcontainer示意圖 另外,libcontainer提供了一整套標準的接口來滿足上層對容器管理的需求。或者說,libcontainer屏蔽了Docker上層對容器的直接管理。又由于libcontainer使用Go這種跨平臺的語言開發實現,且本身又可以被上層多種不同的編程語言訪問,因此很難說,未來的Docker就一定會緊緊地和Linux捆綁在一起。而于此同時,Microsoft在其著名云計算平臺Azure中,也添加了對Docker的支持,可見Docker的開放程度與業界的火熱度。 暫不談Docker,由于libcontainer的功能以及其本身與系統的松耦合特性,很有可能會在其他以容器為原型的平臺出現,同時也很有可能催生出云計算領域全新的項目。 ### 4.7 Docker container Docker container(Docker容器)是Docker架構中服務交付的最終體現形式。 Docker按照用戶的需求與指令,訂制相應的Docker容器: - 用戶通過指定容器鏡像,使得Docker容器可以自定義rootfs等文件系統; - 用戶通過指定計算資源的配額,使得Docker容器使用指定的計算資源; - 用戶通過配置網絡及其安全策略,使得Docker容器擁有獨立且安全的網絡環境; - 用戶通過指定運行的命令,使得Docker容器執行指定的工作。 Docker容器示意圖如圖4.8: ![](https://box.kancloud.cn/2016-01-12_5694aaca3d5e0.jpg) 圖4.8 Docker容器示意圖 ### 5 Docker運行案例分析 上一章節著重于Docker架構中各個部分的介紹。本章的內容,將以串聯Docker各模塊來簡要分析,分析原型為Docker中的docker pull與docker run兩個命令。 ### 5.1 docker pull docker pull命令的作用為:從Docker Registry中下載指定的容器鏡像,并存儲在本地的Graph中,以備后續創建Docker容器時的使用。docker pull命令執行流程如圖5.1。 ![](https://box.kancloud.cn/2016-01-12_5694aaca4ce6c.jpg) 圖5.1 docker pull命令執行流程示意圖 如圖,圖中標記的紅色箭頭表示docker pull命令在發起后,Docker所做的一系列運行。以下逐一分析這些步驟。 (1) Docker Client接受docker pull命令,解析完請求以及收集完請求參數之后,發送一個HTTP請求給Docker Server,HTTP請求方法為POST,請求URL為"/images/create? "+"xxx"; (2) Docker Server接受以上HTTP請求,并交給mux.Router,mux.Router通過URL以及請求方法來確定執行該請求的具體handler; (3) mux.Router將請求路由分發至相應的handler,具體為PostImagesCreate; (4) 在PostImageCreate這個handler之中,一個名為"pull"的job被創建,并開始執行; (5) 名為"pull"的job在執行過程中,執行pullRepository操作,即從Docker Registry中下載相應的一個或者多個image; (6) 名為"pull"的job將下載的image交給graphdriver; (7) graphdriver負責將image進行存儲,一方創建graph對象,另一方面在GraphDB中記錄image之間的關系。 ### 5.2 docker run docker run命令的作用是在一個全新的Docker容器內部運行一條指令。Docker在執行這條命令的時候,所做工作可以分為兩部分:第一,創建Docker容器所需的rootfs;第二,創建容器的網絡等運行環境,并真正運行用戶指令。因此,在整個執行流程中,Docker Client給Docker Server發送了兩次HTTP請求,第二次請求的發起取決于第一次請求的返回狀態。Docker run命令執行流程如圖5.2。 ![](https://box.kancloud.cn/2016-01-12_5694aaca60f73.jpg) 圖5.2 docker run命令執行流程示意圖 如圖,圖中標記的紅色箭頭表示docker run命令在發起后,Docker所做的一系列運行。以下逐一分析這些步驟。 (1) Docker Client接受docker run命令,解析完請求以及收集完請求參數之后,發送一個HTTP請求給Docker Server,HTTP請求方法為POST,請求URL為"/containers/create? "+"xxx"; (2) Docker Server接受以上HTTP請求,并交給mux.Router,mux.Router通過URL以及請求方法來確定執行該請求的具體handler; (3) mux.Router將請求路由分發至相應的handler,具體為PostContainersCreate; (4) 在PostImageCreate這個handler之中,一個名為"create"的job被創建,并開始讓該job運行; (5) 名為"create"的job在運行過程中,執行Container.Create操作,該操作需要獲取容器鏡像來為Docker容器創建rootfs,即調用graphdriver; (6) graphdriver從Graph中獲取創建Docker容器rootfs所需要的所有的鏡像; (7) graphdriver將rootfs所有鏡像,加載安裝至Docker容器指定的文件目錄下; (8) 若以上操作全部正常執行,沒有返回錯誤或異常,則Docker Client收到Docker Server返回狀態之后,發起第二次HTTP請求。請求方法為"POST",請求URL為"/containers/"+container_ID+"/start"; (9) Docker Server接受以上HTTP請求,并交給mux.Router,mux.Router通過URL以及請求方法來確定執行該請求的具體handler; (10)mux.Router將請求路由分發至相應的handler,具體為PostContainersStart; (11)在PostContainersStart這個handler之中,名為"start"的job被創建,并開始執行; (12)名為"start"的job執行完初步的配置工作后,開始配置與創建網絡環境,調用networkdriver; (13)networkdriver需要為指定的Docker容器創建網絡接口設備,并為其分配IP,port,以及設置防火墻規則,相應的操作轉交至libcontainer中的netlink包來完成; (14)netlink完成Docker容器的網絡環境配置與創建; (15)返回至名為"start"的job,執行完一些輔助性操作后,job開始執行用戶指令,調用execdriver; (16)execdriver被調用,初始化Docker容器內部的運行環境,如命名空間,資源控制與隔離,以及用戶命令的執行,相應的操作轉交至libcontainer來完成; (17)libcontainer被調用,完成Docker容器內部的運行環境初始化,并最終執行用戶要求啟動的命令。 ### 6 總結 本文從Docker 1.2的源碼入手,分析抽象出Docker的架構圖,并對該架構圖中的各個模塊進行功能與實現的分析,最后通過兩個docker命令展示了Docker內部的運行。 通過對Docker架構的學習,可以全面深化對Docker設計、功能與價值的理解。同時在借助Docker實現用戶定制的分布式系統時,也能更好地找到已有平臺與Docker較為理想的契合點。另外,熟悉Docker現有架構以及設計思想,也能對云計算PaaS領域帶來更多的啟發,催生出更多實踐與創新。 ### 7 作者簡介 孫宏亮,[DaoCloud](http://www.daocloud.io/)初創團隊成員,軟件工程師,浙江大學VLIS實驗室應屆研究生。讀研期間活躍在PaaS和Docker開源社區,對Cloud Foundry有深入研究和豐富實踐,擅長底層平臺代碼分析,對分布式平臺的架構有一定經驗,撰寫了大量有深度的技術博客。2014年末以合伙人身份加入DaoCloud團隊,致力于傳播以Docker為主的容器的技術,推動互聯網應用的容器化步伐。郵箱:[allen.sun@daocloud.io](#) ### 8 參考文獻 [](http://en.wikipedia.org/wiki/Docker_(software))[http://en.wikipedia.org/wiki/Docker_(software](http://en.wikipedia.org/wiki/Docker_(software)) [](http://www.slideshare.net/rajdeep/docker-architecturev2)[http://www.slideshare.net/rajdeep/docker-architecturev2](http://www.slideshare.net/rajdeep/docker-architecturev2) [](https://github.com/docker/libcontainer)[https://github.com/docker/libcontainer](https://github.com/docker/libcontainer) [](http://www.infoq.com/cn/articles/docker-core-technology-preview)[http://www.infoq.com/cn/articles/docker-core-technology-preview](http://www.infoq.com/cn/articles/docker-core-technology-preview) [](https://blog.docker.com/2014/03/docker-0-9-introducing-execution-drivers-and-libcontainer/)[https://blog.docker.com/2014/03/docker-0-9-introducing-execution-drivers-and-libcontainer/](https://blog.docker.com/2014/03/docker-0-9-introducing-execution-drivers-and-libcontainer/) [](https://crosbymichael.com/the-lost-packages-of-docker.html)[https://crosbymichael.com/the-lost-packages-of-docker.html](https://crosbymichael.com/the-lost-packages-of-docker.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看