當前位置: 華文星空 > 知識

如何通俗解釋Docker是什麽?

2015-02-22知識

看了一圈答案,都沒有感覺比較滿意的。

當然,如果想一兩句話給個定義,或者用一個大家熟悉的東西打個比方來說明Docker, @劉允鵬 的高贊答就很好。但個人感覺還是沒有完整的解釋清楚Docker,自己開一個回答補充一下。

要解釋清楚Docker,首先要說解釋清楚容器(Container)的概念。 要解釋容器的話,需要從作業系統說起。太深入的一兩本書都說不清楚,直接參照維基的說法,作業系統就是管理電腦的硬件軟件和資源,並且為軟件執行提供通用服務的系統軟件。

  • 硬件管理,包括分配CPU時間、記憶體;從網絡、儲存器材等IO器材讀寫數據。
  • 軟件管理,就是各種軟件的執行,執行緒、行程排程之類的工作。
  • 為軟件提供執行環境,這個執行環境通常一部份由作業系統內核(Kernel)提供,另一部份由執行庫(Runtime Library)提供。
  • 硬件、作業系統、應用程式之間的關系可以簡單的用下圖表示:

    +--------------------------+ | Applications | +--------------------------+ |+------------------------+| || Runtime Library || |+------------------------+| || Kernel || |+------------------------+| | Operating System | +-----+--------+-----------+ | CPU | Memory | IO Device | +-----+--------+-----------+

    隨著硬件的效能提升,以及軟件種類的豐富,有兩種情況變得很常見:

    1. 硬件效能過剩——很多電腦的硬件配置,即使不能完全滿足峰值效能的要求,也往往會有大量時間處於硬件資源閑置的狀態。例如一般家用電腦,已經是四核、六核的配置了,除了3A遊戲、影片制作、3D渲染、高效能計算等特殊套用外,通常有90%以上時間CPU是閑置的。
    2. 軟件沖突——因為業務需要,兩個或者多個軟件之間沖突,或者需要同一個軟件的不同版本。例如早幾年做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圖示裏面的一個貨櫃。和虛擬機器相比,容器有以下優點:

    1. 迅速啟動:沒有虛擬機器硬件的初始化,沒有Guest OS的啟動過程,可以節約很多啟動時間,這就是容器的「開箱即用」。
    2. 占用資源少:沒有執行Guest OS所需的記憶體開銷,無需為虛擬機器預留執行記憶體,無需安裝、執行App不需要的執行庫/作業系統服務,記憶體占用、儲存空間占用都小的多。相同配置的伺服器,如果執行虛擬機器只能執行十多台的,通常可以執行上百個容器毫無壓力——當然前提是單個容器套用本身不會消耗太多資源。

    當然,和虛擬機器相比,因為共用內核,只靠cgroup隔離,套用之間的隔離是不如虛擬機器徹底的,如果某個套用執行時導致內核崩潰,所有的容器都會崩潰。而虛擬機器內的套用崩潰,理論上是不會影響其它虛擬機器以及上面執行的套用的,除非是硬件或者Hypervisor有Bug。

    Docker把App和Lib的檔打包成為一個映像,並且采用類似多次快照的儲存技術,例如aufs/device mapper/btrfs/zfs等,可以實作:

    1. 多個App可以共用相同的底層映像(初始的作業系統映像)
    2. App執行時的IO操作和映像檔隔離;
    3. 透過掛載包含不同配置/數據檔的目錄或者卷(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