Docker基本概念和原理理解
來自專欄不會唱歌的博士生不是好男朋友3 人贊了文章
最近在公司用GPU集群,不可避免地要使用docker,所以看了一些docker相關的資料,這裡做一些總結。
可能是把Docker的概念講的最清楚的一篇文章這篇文章寫得很好,我總結一下其中的要點並且寫了一些我自己的理解(引用原文的部分都在文中標出)。因為本科的時候linux課沒有好好聽,所以裡面還是有很多不太明白以及理解有問題的,希望能有大神指正。
什麼是docker
1. Docker是世界領先的軟體容器平台。
2. Docker使用Google公司推出的Go語言進行開發實現,基於Linux內核的cgroup,namespace,以及AUFS類的UnionFS等技術,對進程進行封裝隔離,屬於操作系統層面的虛擬化技術。 由於隔離的進程獨立於宿主和其它的隔離的進程,因此也稱其為容器。Docker最初實現是基於LXC。
簡單地說就是,docker是一種虛擬化技術的產品,屬於一種「容器」。「容器」這個東西有點像虛擬機,但是有很大的不同。理解容器和虛擬機的區別是很重要的一點。下面做一下簡單的對比區分。
一句話概括容器:容器就是將軟體打包成標準化單元,以用於開發、交付和部署。
我們知道,如果將計算機的層次做一下簡單的劃分,最底層是硬體,最上層是軟體,中間是操作系統。(這是一種極為籠統且不嚴謹不專業的劃分,我只記到這裡了……)我們非常熟悉的虛擬機,就是一個物理硬體層抽象,運行在硬體之上:它向下面對一套硬體和硬體介面,對其進行虛擬,然後向上提供一套獨立的操作系統,然後就可以在操作系統之上再運行各種軟體應用等(如下圖右,可以無視那個「管理程序」層因為我也不知道是啥)。這就使得虛擬機這個東西非常龐大沉重(因為包含了一整套操作系統,一般都好幾G,還可能有一套單獨的存儲空間),啟動時間長(一般幾分鐘,有SSD不算),且不容易移植(因為我們知道,在安裝操作系統的時候,會根據硬體的不同編譯出不同的內核,而每台電腦的硬體配置幾乎不會完全一樣,因而直接把一台電腦的操作系統文件考到另一台一般是沒法啟動的)。而容器是一個應用層抽象,運行在操作系統之上的,確切地說是操作系統內核之上(如下圖左),面對的是操作系統提供的介面,屬於進程級別;容器對我們的代碼和依賴進行打包,比如一個docker中只有一個python3,還有TensorFlow以及其他的package(經常會在一個docker中發現連「sudo」命令都沒有);這樣體積就很小,啟動快(幾秒幾毫秒),且容易移植(不同硬體上的同一操作系統向上提供相同的介面)。
其他還有一些對比:
通過Docker官網,我們知道了這麼多Docker的優勢,但是大家也沒有必要完全否定虛擬機技術,因為兩者有不同的使用場景。虛擬機更擅長於徹底隔離整個運行環境。例如,雲服務提供商通常採用虛擬機技術隔離不同的用戶。而Docker通常用於隔離不同的應用 ,例如前端,後端以及資料庫。
Docker的三個基本概念
- 鏡像(Image)
- 容器(Container)
- 倉庫(Repository)
簡單來說,Docker的image可以理解是一個只讀的靜態模板,類似於我們在裝系統的時候用到的.iso文件;而container則相對而言是一個動態的instance,或者說可以理解為我們裝好了系統之後的某一台計算機,可以開機,關機,重啟等等,也可以被格式化(刪除)。如果我們想在另一台計算機上復現我這台計算機的系統,則可以ghost一個新的鏡像,然後去安裝(雖然這種操作通常不行,因為底層硬體的驅動可能不匹配)。
鏡像(Image)
操作系統分為內核和用戶空間。對於Linux而言,內核啟動後,會掛載root文件系統為其提供用戶空間支持。而Docker鏡像(Image),就相當於是一個root文件系統。
現在重新理解一下我們使用一個linux系統的過程。我們開機的時候,linux內核會先啟動,然後掛載root文件系統作為用戶空間;而Docker鏡像就相當於是一個root文件系統,每開一個就有了一個獨立的用戶空間。
Docker設計時,就充分利用Union FS的技術,將其設計為分層存儲的架構。
鏡像構建時,會一層層構建,前一層是後一層的基礎。每一層構建完就不會再發生改變,後一層上的任何改變只發生在自己這一層。比如,刪除前一層文件的操作,實際不是真的刪除前一層的文件,而是僅在當前層標記為該文件已刪除。在最終容器運行的時候,雖然不會看到這個文件,但是實際上該文件會一直跟隨鏡像。因此,在構建鏡像的時候,需要額外小心,每一層盡量只包含該層需要添加的東西,任何額外的東西應該在該層構建結束前清理掉。
容器(Container)
鏡像(Image)和容器(Container)的關係,就像是面向對象程序設計中的類和實例一樣,鏡像是靜態的類,容器是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等 。
容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行於屬於自己的獨立的命名空間。前面講過鏡像使用的是分層存儲,容器也是如此。按照Docker最佳實踐的要求,容器不應該向其存儲層內寫入任何數據 ,容器存儲層要保持無狀態化。所有的文件寫入操作,都應該使用數據卷(Volume)、或者綁定宿主目錄,在這些位置的讀寫會跳過容器存儲層,直接對宿主(或網路存儲)發生讀寫,其性能和穩定性更高。
所謂「綁定宿主目錄」,就是在run一個container的時候使用-v命令把宿主機的存儲目錄映射進container。我們可以這樣理解,image是分層存儲的,我們每做一次修改就會在原本的Image存儲層上多搭一層,記錄這個更改;而新搭的這層是靜態、且可以持久化存儲的。Container也是相同額存儲架構,但是每次修改新搭的一層是動態的,而且並不是持久化存儲的;當容器被remove,或者重啟計算機(內存斷電)之後,container沒了,相應的這些容器存儲層也沒了。因此要盡量保持容器存儲層無狀態化,所有的contain里產生的數據(比如container里的程序的運行結果)都要通過掛載宿主目錄直接寫進宿主硬碟里。
倉庫(Repository)
我們可以把構建後的鏡像上傳到伺服器,從而可以在任何地方使用到這個鏡像。
一個Docker Registry中可以包含多個倉庫(Repository);每個倉庫可以包含多個標籤(Tag);每個標籤對應一個鏡像。
通常,一個倉庫會包含同一個軟體不同版本的鏡像,而標籤就常用於對應該軟體的各個版本 。我們可以通過<倉庫名>:<標籤>的格式來指定具體是這個軟體哪個版本的鏡像。如果不給出標籤,將以latest作為默認標籤。最常使用的Registry公開服務是官方的Docker Hub ,這也是默認的Registry,並擁有大量的高質量的官方鏡像,網址為:http://hub.docker.com/ 。
推薦閱讀:
※Redis【一】:Redis在Ubuntu安裝配置
※CentOS 7中使用Apache + mod_wsgi部署Django項目
※從頭學習大數據培訓課程 任務調度工具 oozie(三)Linux 的 crontab 和 oozie 的 cronschedule
※使用 Python 和 Click 編寫命令行應用程序
※Linux系統安裝