本篇文章給大家帶來了關于docker鏡像原理之聯合文件系統和分層理解的相關知識,其中包括聯合文件系統、分層結構和分層實踐的相關問題,希望對大家有幫助。
docker——鏡像原理之聯合文件系統和分層理解
1、聯合文件系統
UnionFS( 聯合文件系統)
UnionFS( 聯合文件系統):Union文件系統(UnionFS )是一種分層、輕量級并且高性能的文件系統,它支持對文件系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬文件系統下(unite several directories into a single virtualfilesystem)。Union文件系統是Docker鏡像的基礎。鏡像可以通過分層來進行繼承,基于基礎鏡像(沒有父鏡像),可以制作各種具體的應用鏡像。
另外,不同 Docker 容器就可以共享一些基礎的文件系統層,同時再加上自己獨有的改動層,大大提高了存儲的效率。
Docker 中使用的 AUFS(AnotherUnionFS)就是一種聯合文件系統。 AUFS 支持為每一個成員目錄(類似 Git 的分支)設定只讀(readonly)、讀寫(readwrite)和寫出(whiteout-able)權限, 同時 AUFS 里有一個類似分層的概念, 對只讀權限的分支可以邏輯上進行增量地修改(不影響只讀部分的)。
Docker 目前支持的聯合文件系統種類包括 AUFS, btrfs, vfs 和 DeviceMapper。
特性:一次同時加載多個文件系統,但從外面看起來,只能看到一個文件系統,聯合加載會把各層文件系統疊加起來,這樣最終的文件系統會包含所有底層的文件和目錄。
base 鏡像
base 鏡像簡單來說就是不依賴其他任何鏡像,完全從0開始建起,其他鏡像都是建立在他的之上,可以比喻為大樓的地基,docker鏡像的鼻祖。
base 鏡像有兩層含義:(1)不依賴其他鏡像,從 scratch 構建;(2)其他鏡像可以之為基礎進行擴展。
所以,能稱作 base 鏡像的通常都是各種 Linux 發行版的 Docker 鏡像,比如 Ubuntu, Debian, CentOS 等。
Docker 鏡像加載原理
docker的鏡像實際上由一層一層的文件系統組成,這種層級的文件系統就是UnionFS。
典型的 Linux 啟動到運行需要兩個FS,bootfs + rootfs:
bootfs(boot file system)主要包含 bpotloader 和 kernel,bootloader主要是引導加載 kernel,Linux 剛啟動時會加載 bootfs文件系統,在Docker鏡像的最底層是bootfs。這一層與我們典型的Linux/Unix系統是一樣的,包含boot加載器bootloader和內核kernel。當boot加載完成之后整個內核就都在內存中了,此時內存的使用權已由bootfs轉交給內核,此時系統也會卸載bootfs。
rootfs (root file system),在bootfs之上。包含的就是典型Linux系統中的/dev, /proc, /bin, /etc等標準目錄和文件。roots就是各種不同的操作系統發行版,比如Ubuntu,Centos等等。
Docker 鏡像中為什么沒有內核
從鏡像大小上面來說,一個比較小的鏡像只有1KB多點,或幾MB,而內核文件需要幾十MB, 因此鏡像里面是沒有內核的,鏡像在被啟動為容器后將直接使用宿主機的內核,而鏡像本身則只提供相應的rootfs,即系統正常運行所必須的用戶空間的文件系統,比如/dev/,/proc,/bin,/etc等目錄,所以容器當中基本是沒有/boot目錄的,而/boot當中保存的就是與內核相關的文件和目錄。
由于容器啟動和運行過程中是直接使用了宿主機的內核,不會直接調用過物理硬件,所以也不會涉及到硬件驅動,因此也用不上內核和驅動。而如果虛擬機技術,對應每個虛擬機都有自已獨立的內核
2、分層結構
Docker 鏡像是一種分層結構,每一層構建在其他層之上,從而實現增量增加內容的功能,Docker 鏡像下載的時候也是分層下載,以下載redis鏡像為例:
可以看到,新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增加一層。
為什么 Docker 鏡像要采用這種分層結構呢?
最大的好處,莫過于是資源共享了。比如有多個鏡像都從相同的Base鏡像構建而來,那么宿主機只需在磁盤上保留一份base鏡像,同時內存中也只需要加載一份base鏡像,這樣就可以為所有的容器服務了,而且鏡像的每一層都可以被共享。
可寫的容器層
Docker 鏡像都只是可讀(read-only)的,當容器啟動時,一個新的可寫層被加載到鏡像頂部。
這新的一層就是可寫的容器層,容器之下都叫鏡像層。
Docker通過一個修改時復制策略copy-on-write來保證base鏡像的安全性,以及更高的性能和空間利用率。
- 當容器需要讀取文件的時候
從最上層的鏡像層開始往下找,找到后讀取到內存中,若已經在內存中,可以直接使用。換句話說,運行在同一臺機器上的Docker容器共享運行時相同的文件。
- 當容器需要修改文件的時候
從上往下查找,找到后復制到容器層,對于容器來說,可以看到的是容器層的這個文件,看不到鏡像層里的文件,然后直接修改容器層的文件。
- 當容器需要刪除文件的時候
從上往下查找,找到后在容器中記錄刪除,并不是真正的刪除,而是軟刪除。這導致鏡像體積只會增加,不會減少。
- 當容器需要增加文件的時候
直接在最上層的容器可寫層增加,不會影響鏡像層。
所有對容器的改動,無論添加、刪除、還是修改文件都只會發生在容器層中。只有容器層是可寫的,容器層下面的所有鏡像層都是只讀的,所以鏡像可以被多個容器共享。
3、分層實踐——commit 提交鏡像
通過鏡像創建容器,然后對容器層進行操作,鏡像層不動,再把操作后的容器層和鏡像層打包成一個新的鏡像提交。
docker commit:用容器創建一個新的鏡像。
語法:
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
OPTIONS說明:
- **-a*提交的鏡像作者;
- **-c*使用Dockerfile指令來創建鏡像;
- **-m *提交時的說明文字;
- **-p *在commit時,將容器暫停。
使用實例:通過鏡像創建容器,然后對容器層進行操作,再把操作后的容器層和鏡像層打包成一個新的鏡像提交。
1、先下載 tomcat 鏡像
2、通過tomcat 鏡像創建運行tomcat 容器:
docker run -d --name="tomcat01" tomcat
3、進入正在運行的tomcat容器:
docker exec -it tomcat01 /bin/bash
4、把tomcat容器 webapps.dist目錄下的文件拷貝到webapps目錄下:
cp -r webapps.dist/* webapps
5、docker commit 提交鏡像
將容器 dc904437d987 保存為新的鏡像,并添加提交人信息和說明信息,提交后的鏡像名為tomcatplus,版本為1.0:
docker commit -a="wanli" -m="add webapps files" dc904437d987 tomcatplus:1.0
可以看到commit提交后的新 tomcat 鏡像大小比原來的tomcat鏡像要大一點,因為我們在容器層中進行了復制文件操作。
推薦學習:《docker視頻教程》