下面是Docker官方的一張描述文件系統的圖片,顯示了一張聯合文件系統在串聯鏡像層和容器層起到的做用linux
Docker支持多種聯合文件系統,常見的有aufs,deviceMapper,overlay,overlay2,本文章中使用的系統版本爲debian9.1,Docker版本爲17.06.2-ce,默認使用是overlay2。json
FROM hub.c.163.com/library/debian:stretch
MAINTAINER nim
#下載jdk
ADD http://10.173.11.100/nim/jdk-8u202-linux-x64.tar.gz /usr/local/nim/
#解壓jdk並刪除
RUN tar -xzvf /usr/local/nim/jdk-8u202-linux-x64.tar.gz -C /usr/local/nim/ \
&& rm /usr/local/nim/jdk-8u202-linux-x64.tar.gz
#設置環境變量
ENV JAVA_HOME=/usr/local/nim/jdk1.8.0_202
ENV PATH=$JAVA_HOME/bin:$PATH
CMD ["/bin/bash"]
根據構建鏡像,查看構建結果,原基礎鏡像100M,構建後鏡像體積697M。複製代碼
如今開始看一下構建鏡像工做在文件層存儲狀況。首先咱們使用Docker history查看一下剛剛構建鏡像狀況,能夠看到基礎鏡像佔用100M,兩個鏡像分層佔用194MB和403M。緩存
接下來咱們看查看一下文件系統中的存儲狀況,本環境使用overlay2,Docker鏡像層存儲默認路徑爲/var/lib/Docker/overlay2/,能夠看到鏡像存儲目錄下有4個目錄,其中110M的對應是基礎鏡像,另外兩個爲ADD JDK(186M)和解壓JDK壓縮包的鏡像分層(389M)。bash
其中的l目錄包含了全部層的軟鏈接,軟連接使用短名稱,避免mount時候參數達到頁面大小限制。網絡
下面咱們瞭解一下,每一個分層中的文件內容。基礎鏡像分層包含diff文件夾和link文件,diff文件夾中存放當前分層內容,link文件記錄短名稱。app
接下來看一下COPY JDK生成的內容,diff文件夾保存了jdk壓縮包,本層相比基礎鏡像層,多了lower,merged,work三個文件/文件夾,其中lower記錄了此層的下層ID(基礎鏡像層),merged目錄做爲提供了統一視圖,在容器層讀寫層被使用,work目錄用於聯合掛載指定的工做目錄,使用過程對用戶不可見。運維
解壓JDK層的文件夾結構內容和上一層相似,主要關注jdk壓縮包占用空間爲0,表示已被刪除。curl
如今來重點關注一個問題,鏡像大小等於全部分層相加,在後續分層中被刪除的jdk壓縮包仍然要佔用存儲空間,這並非咱們本來意圖,所以這裏就出現了鏡像文件進行優化的點。優化後的Dockerfile以下優化
FROM hub.c.163.com/library/debian:stretch
MAINTAINER nim
RUN curl -o /usr/local/nim/jdk-8u202-linux-x64.tar.gz http://10.173.11.100/nim/jdk-8u202-linux-x64.tar.gz \
&& tar -xzvf /usr/local/nim/jdk-8u202-linux-x64.tar.gz -C /usr/local/nim/ \
&& rm /usr/local/nim/jdk-8u202-linux-x64.tar.gz \
&& export JAVA_HOME=/usr/local/nim/jdk1.8.0_202 \
&& export PATH=$JAVA_HOME/bin:$PATH
CMD ["/bin/bash"]複製代碼
構建鏡像真的是層數越少越好嗎?固然不是這麼絕對,尤爲在早期鏡像版本不是很穩定或是後續迭代比較頻繁時,合理的鏡像分層會減小編譯時間,下降出錯機率,也可讓Dockerfile更具備可讀性。能夠再穩定版本造成以後對鏡像進行二次優化。ui
/var/lib/Docker/image/overlay2/imaged/
/var/lib/Docker/image/overlay2/layerdb/
/var/lib/Docker/overlay2/複製代碼
Docker鏡像的基本信息保存在/var/lib/Docker/image/overlay2/imaged/content/sha256/下面,能夠根據Docker image ID在此目錄下查找到對應ID開頭文件。此文件中以json的形式保存了該鏡像的分層文件系統、構建信息、相關容器等內容。
第二個目錄/var/lib/Docker/image/overlay2/layerdb/sha256/保存分層元數據,每個分層元數據目錄下有cache-id,diff,size信息,其中cache-id對應分層存儲層,diff關聯鏡像基礎元數據信息。
建立容器完成以後,在鏡像存儲目錄/var/lib/Docker/overlay2/會生成容器的初始層和讀寫層,二者使用相同標識,初始層後面多了-init。初始層中主要保存初始化容器環境時,與容器相關的環境信息,如容器主機名,主機host信息以及域名服務文件等;讀寫層用於容器的讀寫,Docker容器內的進程只對讀寫層擁有寫權限,而對其餘層文件內容只擁有讀權限。
接下來咱們進入容器操做進行一系列操做,再根據結果分析一下讀寫層對於文件的保存和處理,下面是操做和對應結果以及讀寫層實際文件存儲狀況。
讀寫層中的merged文件夾提供了統一視圖,面向用戶展現聯合文件系統掛載完成的最終形態。
接下來咱們再基於同一個鏡像啓動幾個容器實例,而後來查詢一下Docker容器使用空間,只有第一個容器因爲上面修改文件只佔用154k,新啓動的容器並無額外佔用空間。可見基於同一個鏡像建立容器時,全部的容器共享鏡像層內容,有效節約了空間。讀寫層只保存修改內容,若是是操做鏡像層文件,Docker採用的是修改時複製策略(copy-on-write)。這時回頭再看一下第一節出現的兩張圖,會對Docker的文件系統有了更深的體會。
更多技術乾貨,歡迎關注vx公衆號「網易智慧企業技術+」。系列課程提早看,精品禮物免費得,還可直接對話CTO。