天天看點

docker核心原理

簡單記錄了一下關于docker的學習,從概念到使用,到研究和心原理。日後每個步驟詳細分解。

容器概念。

docker是一種容器,應用沙箱機制實作虛拟化。能在一台主控端裡面獨立多個虛拟環境,互不影響。在這個容器裡面可以運作着我餓們的業務,輸入輸出。可以和主控端互動。

使用方法。

拉取鏡像

預設是從官網的docker倉庫上面擷取,其中pull的指令是拉取,與之對應的是push指令,日後有能力自己建立鏡像并且上傳到docker倉庫的時候用到。registry是鏡像名,docker官方維護有很多基礎鏡像,可以直接下載下傳來用。同時在公共倉庫也有很多共享的鏡像,自己可以視情況來下載下傳使用。

啟動容器

第一步把鏡像下載下傳到本地,現在可以在鏡像的基礎上啟動容器。run指令就是啟動的意思,後面可以加一下附屬參數。指令中-d就是daemon的意思,以守護程序方式運作。--name就是制定容器的名字,友善日後管理,不然每次都要使用容器的ID,12位16進制數。後面就是我們的鏡像名。容器啟動後就會傳回一串數字,作為sha256,這一串是我們的長ID。長ID和短ID的差別如下:

一般操作使用短ID,下面說到的檔案目錄用長ID标記。

這是最基本的用法。

核心原理。

這是用方式不是一個鏡像一台提供不同服務的虛拟機嗎?

應用不同,這是兩個完全不一樣的産品。docker可以快速部署相同的和不同的環境,虛拟機隻是節省資源,在同一台主控端安裝多個系統。

容器是共用鏡像,獨立的服務,屬于雲計算中的paas服務,在統一的基礎環境延伸。虛拟機提供的是iaas,從底層開始。

docker的實作方法是共享和隔離。虛拟機的隻是虛拟硬體,虛拟機間沒有共享成分。

容器的實作原理很炫嗎?

它是通過利用核心自帶的namespace和cgroup功能隔離系統必須的六個子產品,以完成一個獨立的系統環境。用namespace隔離一個小空間,UTS、IPC、PID、Network、mount、User六個環境的新隔離,用cgroup作為系統資源的控制。

UTC實作主機名和域名的隔離,使容器有獨立的主機名;IPC隔離信号量和消息隊列,使之有獨立的工作通訊;Network隔離網絡,使之有獨立的網絡裝置;mount隔離檔案系統,使之有獨立的存儲;PID隔離程序号,使之有獨立的程序編排。運作起來就像一個獨立的計算機環境。

除了檔案,其他一些隔離都可以調用接口實作。每個容器裡面有整個系統的檔案,而且都是一秒鐘生成。就很難了解了。

    上面說了,容器操作的時候,用名字就不用每次都找ID。exec指令是發送指令給容器執行,-i是使用互動模式保持輸入流的開放,-t是建立虛拟終端,smokeping是指定的容器名,bash是容器要執行的指令。我們看看容器的這些檔案存放在主控端的什麼地方  。

運作目錄。

容器是虛拟的,檔案總不能也是虛拟的。查找了相關資料發現全部都是儲存在docker容器的運作目錄。/var/lib/docker

看了一下,還真有。

為了能看到檔案的變化,我們把docker的運作目錄都删掉了。

重新開機docker daemon,一切都是新的。

Docker運作目錄的變化

拉取第一個鏡像開始,/var/lib/docker開始建立,包含了下下目錄。

删除鏡像。

展開目錄。

全部目錄為空,打開image/aufs/repositories.json的記錄檔案也為空。

重新拉取鏡像,再展開對比

Aufs目錄下的三個檔案夾的首層子目錄或者檔案名都是各層ID。

diff目錄儲存着隻讀層和可讀寫層的資料。每層隻儲存曆史當次讀寫。

Layer目錄下的檔案名和diff子目錄名一一對應,裡面的内容是層依賴。

Mnt目錄下的子目錄名和iff子目錄名一一對應,裡面的内容暫時為空。

Container的目錄為空。

Image目錄下的distribution、imagedb、layerdb。

Distribution下的diffid-by-digest和v2metadata-by-diffid都有sha256。

Imagedb就隻有一個sha256。這個正是image的ID。

Layerdb的sha256下面也有同數量子目錄。每個目錄裡面有相同名字的配置檔案。

repositories.json記錄的也是鏡像的sha256。

Network檔案夾為空,本來是用來存放容器内網絡相關檔案。

Volumes檔案夾為空,是存放容器裡面挂載的目錄,有真實可讀寫的檔案。

小結:在上面“使用方法”示範的“docker pull”過程中,docker下載下傳的鏡像檔案全部分層儲存在aufs目錄下的diff目錄,目錄名是sha256,和層ID無關。

啟動容器時的目錄變化。

生成容器的ID:

  bc893c0031db98114a48ebb924cf5d0b9b2c77968839696e735528648a1a531b

aufs的三個目錄。

Diff沒有變化,但是多了一層把diff的内容都挂載上去。

Layer增加了一個目錄,目錄檔案是個别層實作可讀寫。

Mnt中前面的目錄沒變,但是多了一層把diff的内容都挂載上去。

Container的目錄不再為空,首先是以容器ID為目錄名建立了個目錄。然後在目錄下存放hostname、hosts等配置檔案。

Image目錄完全沒有改動。

Volumes下面出現了容器定義挂載的資料檔案。此資料檔案在mnt目錄沒有挂載。

小結:在上面“使用方法”示範的“docker run”過程中,aufs下的diff和mnt目錄,自動生成兩個目錄,名為sha256的一串數字ID,另一個是ID-init。diff下也是這兩個目錄,此ID是在diff是最新一層,在mnt中是目前容器所有檔案;aufs/mnt/ID的檔案由diff下的鏡像目錄通過aufs系統整合挂載而來,aufs系統是實作多目錄挂載在同一個目錄的工具。aufs/mnt/ID-init目錄為空;aufs/diff/ID下儲存的是最新一層也就是目前可讀寫檔案,aufs/diff/ID-init是最新一層也就是目前的隻讀檔案hostname、host等。一句話,資料都是儲存在diff,mnt是打醬油的。過程就是aufs整合鏡像存放在diff下的内容,一起挂載在aufs/mnt/ID下,連最新一層aufs/diff/ID(有幾個可讀寫檔案)和aufs/diff/ID-init(隻有隻讀檔案)都挂載上去。

運作目錄生成檔案時的變化。

在root目錄touch ken.txt

其他目錄都沒有變化。

aufs下的diff和mnt的那個容器新生成的ID目錄下随地生成了ken.txt檔案,應該是資料庫檔案記錄了此檔案在容器中的位置。

Mnt目錄和diff的關系。

Mnt目錄是被挂載。

在root目錄mv rc.local rc.loca

其他目錄沒有變化。

aufs下的diff的那個容器新生成的ID目錄下etc中生成rc.loca檔案。

diff下鏡像層的檔案沒改。

修改的檔案存在于diff和mnt中。

新增的檔案直接放在aufs/diff/e36b1bd8e430d4731211af3984aed0fd3fa6fa62c57f5c877a013856ba32abc4目錄這裡,修改的檔案連帶目錄生成到這裡。

小結:容器啟動之後,建立目錄ID,和ID-init目錄;容器需要更改的檔案從鏡像檔案複制到diff下的ID目錄,經過容器的操作,ID目錄就擁有了最新的變更,ID-init是亘古不變的隻讀檔案;新增檔案出現在建立層級diff的ID的儲存方式是直接随地放在根目錄下,修改檔案出現在建立層級diff的ID的儲存方式是連帶目錄首先複制到diff的建立層級,然後修改。最終挂載到aufs/mnt/ID展示在容器内的正确位置。

運作目錄在停止容器後的變化。

Aufs目錄下的三個檔案夾。

Diff完全沒有變化,說明一旦容器停止的時候,容器必須的配置檔案時複制的。

Layer檔案完全沒有變化。

Mnt那個建立作為挂載diff各層檔案的目錄為空,說明已經解除安裝。

Images目錄不變。

Container目錄不變,保留着diff時刻準備着的檔案。

小結:容器停止後,在mnt上面的挂載馬上卸掉,但是目錄不變。而在diff上面的檔案狀态保持不變,期待下次容器啟動的時候一次挂載到mnt下面。

運作目錄在删除容器的變化。

Aufs目錄下的三個子目錄。

Diff在容器啟動時所生成的那個ID的檔案夾消失。

Layer在容器啟動時所生成的那個帶ID的檔案夾消失。

Mnt在容器啟動時所生成的那個ID的檔案夾消失.

Container目錄下容器啟動時所生成的那個ID的檔案夾消失。

Volumes目錄下的檔案存活下來。

小結:當容器删除,鏡像檔案不變,其他全部删除。如果有定義volume的,會有所保留。

總結:容器在主控端上運作,無非是圍繞隻讀層和可讀寫,利用複制和挂載,靈活操作;來得快的檔案時通過挂載,如果在隻讀層無法修改檔案就可以先複制出來再說;整個過程就是,容器一啟動,diff就建立可讀寫的新ID目錄和ID-init目錄,ID-init目錄一開始就加載了隻讀檔案。然後和其他各層資料挂在mnt的分别挂在ID一一對應的mnt下,aufs系統把全部資料整合嫁接到mnt的新ID下。此時mnt中其他的目錄為空,新ID擁有容器的全部資料。當容器産生動态資料,就作用于那個可讀寫并且挂在mnt新ID下的diff新ID檔案夾。