先拋出幾個我在學習過程當中產生的幾個問題.git
1. 容器鏡像是什麼, 和裝系統時的鏡像有什麼關係?github
2. 容器鏡像的做用是什麼?docker
3. 不一樣版本的ubuntu鏡像有什麼區別, 好比說 ubuntu:18.04和ubuntn:16.04 的區別?shell
使用docker pull <image name>下載一個鏡像看看ubuntu
能夠看到咱們僅僅是pull了一個ubuntu18.04的鏡像, docker pull的結果卻出現了多行, 這是由於鏡像是分紅多層的. 具體爲何要分層? 每一層又是什麼? 下文咱們會談到.緩存
因爲docker 18.04採用的是overlayfs2做爲默認的存儲驅動, 因此下載的鏡像都存儲在/var/lib/docker/overlay2 中.學習
能夠看到這裏的目錄個數和鏡像層數是一致. 而且除了0c開頭的那一層, 其餘目錄都是有diff和work兩個子目錄 . 0c開頭的目錄就是整個鏡像最底層的只讀層 ui
l目錄下所有都是指向這些diff目錄的軟連接.讓咱們進入0c.../diff中看看, 能夠看到在diff目錄中是一套完整的根目錄. 因此說本質上, 根目錄就是一個rootfs. this
跟裝系統時的鏡像沒有一點點關係.spa
本節來講說如何使用, 使用Dockerfile構建本身的鏡像, dockfile由一系列的命令構成。我目前用過的有FROM RUN CMD ADD COPY命令。
From用來制定一個基礎鏡像層。
RUN命令會在一個新的鏡像層上執行參數中所指定的任何命令, 並commit命令的執行結果。
CMD命令在我初次使用時, 與RUN有所混淆. 可是其實兩者是徹底不一樣的, CMD只是指定了運行容器時的初始命令, 可是在鏡像構建時沒有commit任何命令的結果。
舉例來講, 下圖是一個Dockerfile. 在其中咱們先在一個新的鏡像層建立一個shell腳本, 而後在CMD中運行這個腳本。
能夠看到容器執行CMD中指定的命令.
2.1 分層特性
在咱們使用docker run命令啓動一個容器時, 就會在現有的只讀鏡像層之上在建立一個可讀寫的容器層. 當咱們將這些容器刪除時, 這些容器層也會被刪除.
可是容器層之下的鏡像層卻不會改變.
圖盜自(docker reference)
經過這種共享相同的鏡像層的方式, 容器即實現了必定的隔離(容器層之間), 又節省了空間.
2.2 寫時拷貝(COW)
若是容器須要讀底層的文件或者目錄, 那麼直接讀取底層的文件. 可是若是容器須要修改底層的文件, 那麼容器層就會拷貝一個底層的文件.
雖然說都是COW策略, 可是實現起來, 不一樣的存儲驅動也是有所不一樣的.
以overlayfs/overlayfs2爲例:
1. 搜索全部的鏡像層, 找到要修改的文件, 這個過程從最新的一層直到最底層. 另外搜索結果會放到緩存中, 加速下一次的查找。
2. 執行copy_up操做, 將文件拷貝到容器層
3. 修改文件的拷貝, 同時底層的文件對於容器層是不可見的.
只說了修改和讀取, 那麼當容器層要刪除一個鏡像層的文件時, 會發生什麼呢? 讓咱們看看。
先直接在底層鏡像層中建立一個文件, 還記得上文中說到的那個只有diff目錄和link文件的目錄嗎?那個就是最底層的鏡像層。
咱們直接在diff/tmp/目錄中建立一個文件, 文件名爲thisIsAFileCreateImageLayer
而後運行一個容器, 進入tmp目錄, 能夠看到這個文件對於容器是可見的.
在容器層刪除該文件
在鏡像層看看
由上圖能夠看到在鏡像層, 該文件是依然存在的, 這是由於在容器層, 在容器層刪除文件或者目錄
時, overlayfs採用了whiteouts和opaque技術.
Whiteouts是一個設備號爲0/0的字符設備文件. 當上層目錄中發現一個whiteout文件時, 在上層目錄中讀取底層的同名的文件時, 底層的文件就會被忽略.
以下圖所示, 在新建立的容器層中咱們能夠看到一個設備號爲0,0的字符設備文件.
接下來我來嘗試解答一下我以前的疑問:
其實前兩個問題已經獲得瞭解答, 先說說第三個問題
3. 不一樣版本的ubuntu鏡像有什麼區別, 好比說 ubuntu:18.04和ubuntn:16.04 的區別?
不一樣版本的ubuntu的區別我目前知道的區別是軟件庫的版本不一樣.