看了一圈答案,都沒有感覺比較滿意的。
當然,如果想一兩句話給個定義,或者用一個大家熟悉的東西打個比方來說明Docker, @劉允鵬 的高贊答就很好。但個人感覺還是沒有完整的解釋清楚Docker,自己開一個回答補充一下。
要解釋清楚Docker,首先要說解釋清楚容器(Container)的概念。 要解釋容器的話,需要從作業系統說起。太深入的一兩本書都說不清楚,直接參照維基的說法,作業系統就是管理電腦的硬體軟體和資源,並且為軟體執行提供通用服務的系統軟體。
硬體、作業系統、應用程式之間的關系可以簡單的用下圖表示:
+--------------------------+
| Applications |
+--------------------------+
|+------------------------+|
|| Runtime Library ||
|+------------------------+|
|| Kernel ||
|+------------------------+|
| Operating System |
+-----+--------+-----------+
| CPU | Memory | IO Device |
+-----+--------+-----------+
隨著硬體的效能提升,以及軟體種類的豐富,有兩種情況變得很常見:
- 硬體效能過剩——很多電腦的硬體配置,即使不能完全滿足峰值效能的要求,也往往會有大量時間處於硬體資源閑置的狀態。例如一般家用電腦,已經是四核、六核的配置了,除了3A遊戲、視訊制作、3D渲染、高效能計算等特殊套用外,通常有90%以上時間CPU是閑置的。
- 軟體沖突——因為業務需要,兩個或者多個軟體之間沖突,或者需要同一個軟體的不同版本。例如早幾年做web前端的,要測試網頁在不同版本的IE上是否能正常顯示,然而Windows只能裝一個版本的IE。
為了解決軟體沖突,只能配置多台電腦,或者很麻煩的在同一台電腦上安裝多個作業系統,透過重新開機來進行切換。顯然這兩個方案都有其缺點:多台電腦成本太高,多作業系統的安裝、切換都很麻煩。在硬體效能過剩的時候,硬體虛擬化的普及就很自然而然的提出來了。
所謂硬體虛擬化,就是某個特殊的軟體,仿真出一台或者多台電腦的各種硬體,使用者可以在這一台虛擬機器上安裝、執行作業系統(一般叫來賓作業系統,Guest OS)和各種套用,並且把Guest OS和上面套用軟體對硬體資源的存取轉發到底層的硬體上來實作。對於Guest OS和上面的應用程式來說,這台虛擬機器和普通的物理電腦是完全一樣沒有任何區別的——除了效能可能差一點。著名的VMware就是這麽一個軟體,這類軟體英語有一個專用的單詞是Hypervisor(維基的Hypervisor詞條說另一種叫法是虛擬機器監視器, V irtual M achine M onitor,vmm。但我個人覺得叫虛擬機器管理器,Virtual Machine Manager,更合適一點,雖然可能會和微軟的System Center Virtual Machine Manager以及Redhat的Virtual Machine Manager這兩個軟體混淆),中文大概應該叫虛擬化軟體/套用之類的。
Hypervisor根據其對硬體資源的存取方式,可以分為兩大類,Type I是Hypervisor直接存取硬體資源,通常會有另一個作業系統執行於Hypervisor之上來對硬體資源,例如VMware EXSi,Windows的Hyper-V,Linux的Xen;Type II是Hypervisor和普通的套用一樣,執行在某個作業系統(例如Windows或者Linux等,這裏稱之為宿主機作業系統,Host OS)之上,Hypervisor透過Host OS存取硬體資源,例如VMware Workstation,Virtual Box等。兩種型別的Hypervisor區別如圖所示。
+-----+-----+-----+-----+
|App A|App B|App C|App D|
+-----+-----+-----+-----+ +-----+-----+-----+-----+
|App A|App B|App C|App D| |Guest|Guest|Guest|Guest|
+-----+-----+-----+-----+ | OS0 | OS1 | OS2 | OS3 |
|Guest|Guest|Guest|Guest| +-----+-----+-----+-----+
| OS0 | OS1 | OS2 | OS3 | | Hypervisor |
+-----+-----+-----+-----+ +-----------------------+
| Hypervisor | | Host OS |
+-----------------------+ +-----------------------+
| Hardware | | Hardware |
+-----------------------+ +-----------------------+
Type I Type II
虛擬機器的一個缺點在於Guest OS通常會占用不少硬體資源。例如Windows安裝開機不執行任何運用,就需要占用2~3G記憶體,20~30G硬碟空間。即使是沒有圖形界面的Linux,根據發行版以及安裝軟體的不同也會占用100~1G記憶體,1~4G硬碟空間。而且為了套用系統執行的效能,往往還要給每台虛擬機器留出更多的記憶體容量。雖然不少Hypervisor支持動態記憶體,但基本上都會降低虛擬機器的效能。如果說這樣的資源占用少量的虛擬機器還可以接受的話,同時執行十數台數十台虛擬機器的時候,浪費的硬體資源就相當可觀了。通常來說,其中相當大部份甚至全部Guest OS都是相同的。
能不能所有的套用使用同一個的作業系統減少硬體資源的浪費,但是又能避免包括執行庫執行庫在內的軟體沖突呢?作業系統層虛擬化——容器概念的提出,就是為了解決這個問題。在Linux可以透過控制組(Control Group,通常簡寫為cgroup)隔離,並把套用和執行庫打包在一起,來實作這個目的。容器和Type II虛擬機器、物理機的區別見下圖:
+-----+-----+-----+-----+ +-----+-----+-----+-----+
|App A|App B|App C|App D| +-----+-----+-----+-----+ |App A|App B|App C|App D|
+-----+-----+-----+-----+ |App A|App B|App C|App D| +-----+-----+-----+-----+
|+---------------------+| +-----+-----+-----+-----+ |Guest|Guest|Guest|Guest|
|| Runtime Library || |Lib A|Lib B|Lib C|Lib D| | OS0 | OS1 | OS2 | OS3 |
|+---------------------+| +-----+-----+-----+-----+ +-----+-----+-----+-----+
|| Kernel || | Container Engine | | Hypervisor |
|+---------------------+| +-----------------------+ +-----------------------+
| Operating System | | Host OS | | Host OS |
+-----------------------+ +-----------------------+ +-----------------------+
| Hardware | | Hardware | | Hardware |
+-----------------------+ +-----------------------+ +-----------------------+
Physical Machine Container Type II Hypervisor
上圖中,每一個App和Lib的組合,就是一個容器。也就是Docker圖示裏面的一個貨櫃。和虛擬機器相比,容器有以下優點:
- 迅速啟動:沒有虛擬機器硬體的初始化,沒有Guest OS的啟動過程,可以節約很多啟動時間,這就是容器的「開箱即用」。
- 占用資源少:沒有執行Guest OS所需的記憶體開銷,無需為虛擬機器預留執行記憶體,無需安裝、執行App不需要的執行庫/作業系統服務,記憶體占用、儲存空間占用都小的多。相同配置的伺服器,如果執行虛擬機器只能執行十多台的,通常可以執行上百個容器毫無壓力——當然前提是單個容器套用本身不會消耗太多資源。
當然,和虛擬機器相比,因為共用內核,只靠cgroup隔離,套用之間的隔離是不如虛擬機器徹底的,如果某個套用執行時導致內核崩潰,所有的容器都會崩潰。而虛擬機器內的套用崩潰,理論上是不會影響其它虛擬機器以及上面執行的套用的,除非是硬體或者Hypervisor有Bug。
Docker把App和Lib的檔打包成為一個映像,並且采用類似多次快照的儲存技術,例如aufs/device mapper/btrfs/zfs等,可以實作:
- 多個App可以共用相同的底層映像(初始的作業系統映像)
- App執行時的IO操作和映像檔隔離;
- 透過掛載包含不同配置/數據檔的目錄或者卷(Volume),單個App映像可以同時用來執行無數個不同業務的容器。
+---------+ +---------+ +---------+ +-----+ +-----+ +-----+
| abc.com | | def.com | | xyz.com | | DB1 | | DB2 | | DB3 |
+----+----+ +----+----+ +----+----+ +--+--+ +--+--+ +--+--+
| | | | | |
+----+----+ +----+----+ +----+----+ +--+--+ +--+--+ +--+--+
| abc | | def.com | | xyz.com | | DB1 | | DB2 | | DB3 |
| config | | config | | config | | conf| | conf| | conf|
| data | | data | | data | | data| | data| | data|
+----+----+ +----+----+ +----+----+ +--+--+ +--+--+ +--+--+
| | | | | |
+------------+------------+ +-------+-------+
| |
+------+------+ +------+------+
| Nginx Image | | MySQL Image |
+------+------+ +------+------+
| |
+----------------+----------------+
|
+------+-------+
| Alpine Image |
+------+-------+
上圖是基於一個Alpine Linux的映像,分別建立了Nginx和MySQL的映像,並且掛載不同的配置/數據同時執行3個網站套用3個資料庫套用的示意圖。
此外,Docker公司提供公共的映像倉庫(Docker稱之為Repository),Github connect,自動構建映像,大大簡化了套用分發、部署、升級流程。加上Docker可以非常方便的建立各種自訂的映像檔,這些都是Docker成為最流行的容器技術的重要因素。
透過以上這些技術的組合,最後的結果就是,絕大部份套用,開發者都可以透過docker build建立映像,透過docker push上傳映像,使用者透過docker pull下載映像,用docker run執行套用。使用者不需要再去關心如何搭建環境,如何安裝,如何解決不同發行版的庫沖突——而且通常不會需要消耗更多的硬體資源,不會明顯降低效能。這就是其他答主所說的標準化、貨櫃的原因所在。
題外話:除了Docker以外,還有其它很多種容器,例如Linux上的LXC、OpenVZ,FreeBSD的Jail,Solaris的Zones等等。此外,Unix-Like作業系統的chroot命令從某種角度來說也是一種特殊的容器實作方式。和*nix采用單核心,且內核和各種執行庫耦合松散,很方便實作容器不同,Windows因為采用微內核,且內核與各種執行庫耦合緊密,雖然從Windows 10/2016開始也支持容器,但事實上還是透過Hyper-V執行不同的虛擬機器進行內核級隔離——雖然也有執行緒級的隔離,但只有Windows Server支持,並且只能執行相同版本的映像[1]。而且即使是Hyper-V,也只支持執行更低版本的映像而不能執行更高版本的映像。另外Windows容器的映像體積通常還是很大。
[1]:Windows Container Version Compatibility