Docker是一個開源的應用容器引擎。它的理念是「Buildonce, Run anywhere, Configure once, Run anything」,這與Java提出的「Write Once, Run Anywhere」有殊途同歸之妙。
Java與Docker在面對平臺移植方面的問題時,採用了相似的解決方案。Java語言使用虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成能夠在Java虛擬機上運行的目標代碼(字節碼),就能夠在多種平臺上不加修改地運行。docker
相似地,Docker使用容器引擎解決平臺依賴問題,它在每臺宿主機上都啓動一個Docker的守護進程,守護進程屏蔽了與具體平臺相關的信息,對上層應用提供統一的接口。這樣,Docker化的應用,就能夠在多個平臺下運行,Docker會針對不一樣的平臺,解析給對應的執行驅動、存儲驅動和網絡驅動去執行。
這裏說的平臺主要針對不一樣的Linux發行版,由於Docker的實現須要用到Linux的cgroups、namespaces等特性,因此目前只能運行在Linux環境下,要想在Windows和Mac上使用Docker,則要採用虛擬機的方式。網絡
此外,Docker還有本身的生態圈,從官方鏡像倉庫下載的鏡像,能夠運行在任何裝有Docker引擎的操做系統上,開發人員也能夠將本身製做的鏡像提交的官方倉庫供別人使用。還能夠搭建私有的鏡像倉庫。這就相似Android或iOS系統與應用商店的關係。架構
最後,Docker還具備版本控制功能,能夠對鏡像作修改後提交新的版本、能夠在多個版本間快速切換。性能
綜上,Docker是一個開源的應用容器引擎,它的應用以鏡像的形式存在,Docker經過屏蔽環境的差別,能夠方便地讓應用在各類環境運行,並且Docker還具備對鏡像的版本控制功能。ui
Docker有本身完善的生態圈,整體來講分爲Docker鏡像倉庫和Docker自身程序兩部分。
其中Docker自身程序又分爲Server和Client兩部分,採用了C/S架構,用Go語言編寫。
Docker的Server端又稱做Docker Daemon,在宿主機上之後臺守護進程的形式運行。Docker Client使用比較靈活,既能夠在本機上以bin命令的形式(如Docker info、Docker start)發送指令,也能夠在遠端經過RESTful API的形式發送指令;Docker的Server端接收指令並把指令分解爲一系列任務去執行。spa
當經過Docker client發送docker run指令來建立並啓動容器的時候,Docker Daemon首先會檢查本地是否有對應的鏡像,若是沒有就從官方倉庫下載,而後基於下載的鏡像建立並啓動容器,最後把執行結果返回給Docker Client。操作系統
Docker會把軟件和它依賴的環境(包括操做系統和共享庫等)、依賴的配置文件打包在一塊兒,以虛擬機鏡像的形式放到官方倉庫供別人下載使用。
但操做系統的體積相對軟件的體積來講太大了,爲了運行軟件,每次都下載配套的操做系統是不現實的。爲了解決這個問題,Docker引入了分層的概念。把一個應用分爲任意多個層,好比操做系統是第一層,依賴的庫和第三方軟件是第二層,應用的軟件包和配置文件是第三層。若是兩個應用有相同的底層,就能夠共享這些層。越是處於底部體積大的層,共享的可能也就更大。版本控制
但分層方式還會面臨共享層衝突的問題,因此Docker爲文件層增長了優先級屬性,上層和下層有相同的文件和配置時,上層覆蓋下層。好比,應用A須要修改操做系統的某個配置,應用B不須要修改。這時給以應用A增長一個優先級最高的空白層,若是須要修改下層的文件,就把這個文件拷貝到這個空白層進行修改,保證下層的文件不作任何改變,這稱爲寫時拷貝策略。日誌
應用A: ====運行的應用====== ======空白層======== =====配置文件======= =====依賴的庫======= =====操做系統=======
應用B: ====運行的應用====== =====配置文件======= =====依賴的庫======= =====操做系統=======
KVM、Xen、VMWare、VirtualBox等主流的虛擬機通常比較笨重,在運行的時候,虛擬機自己就要消耗大量的系統資源(CPU、內存等),並且這類虛擬機啓動時間也比較長,動輒耗時數分鐘。
而以OpenVZ、VServer、LXC爲表明的容器類虛擬機,是一種內核虛擬化技術,與宿主機運行在相同Linux內核,不須要指令級模擬,性能消耗很是小,是很是輕量級的虛擬化容器,虛擬容器的系統資源消耗和一個普通的進程差很少。Docker就是使用LXC(後來又推出libcontainer)讓虛擬機變得輕量化。code
那麼鏡像與容器是什麼關係呢,根據前面的描述得知:鏡像指的是以分層的、能夠被LXC/libcontainer理解的文件存儲格式。Docker的應用都是以這種格式發佈到Docker倉庫中,供你們使用。而容器則是指:把應用鏡像從Docker倉庫下載到本地機器上,以鏡像爲模板,在一個容器類虛擬機中把這個應用啓動,這個虛擬機叫就是容器了。
從另外一個角度來講,鏡像和容器能夠看做是一個Docker化應用的兩種不一樣狀態。鏡像狀態時,一個應用只有運行所需的必要文件、程序包等內容,並且應用也處於靜止態;而容器狀態時,應用要運行起來以對外提供服務,有可能修改文件,好比輸出日誌、動態更新某個配置等等,這時須要有空白層用於寫時拷貝。
利用鏡像分層存儲的特性,Docker還能夠作到靈活的變動管理。
好比一個Docker鏡像它的V1.0版本有三層,如今要對它作以下修改:修改位於第一層的文件A;刪除位於第二層的文件B;添加一個新文件C。
這時就會增長一個第四層,在這一層作修改:把第一層的文件A拷貝到第四層,修改文件A的內容;在第四層,把名稱爲B的文件設置爲不存在;在第四層,建立一個新文件C。
v1.0: =====第三層 50M===== =====第二層 500M==== =====第一層 1G======
v1.1: ===第四層 修改 1M=== =====第三層 50M===== =====第二層 500M==== =====第一層 1G======
這樣修改就完成了,在向倉庫發佈這個新版本時,由於前三層已經存儲在倉庫,只須要上傳體積很小的第四層就能夠了。使用這個鏡像的其它機器要升級版本時,一樣也只須要從倉庫下載第四層。
因而可知這種分層的特性對於Docker的重要意義,利用分層特性,Docker能夠作到鏡像的增量變動,使得Docker鏡像的下載上傳變得很是輕量(除了第一次操做)。
參考資料 李金榜 尹燁 劉天斯 陳純 著 《按部就班學Docker》