深入理解Docker鏡像大小

都說容器大法好,但是假設沒有Docker鏡像,Docker該是多無趣啊。docker

是否還記得第一個接觸Docker的時候,你從Docker Hub下拉的那個鏡像呢?在那個處女鏡像的基礎上。你執行了容器生涯的處女容器。鏡像的基石做用已經很是明顯。在Docker的世界裏,可以說是:No Image,No Container。ubuntu

再進一步思考Docker鏡像,你們可能很是快就會聯想到下面幾類鏡像:微信

1.系統級鏡像:如Ubuntu鏡像。CentOS鏡像以及Debian容器等;markdown

2.工具棧鏡像:如Golang鏡像。Flask鏡像,Tomcat鏡像等;工具

3.服務級鏡像:如MySQL鏡像,MongoDB鏡像。RabbitMQ鏡像等;post

4.應用級鏡像:如WordPress鏡像,DockerRegistry鏡像等。學習

鏡像林林總總。想要執行Docker容器。必需要有Docker鏡像;想要有Docker鏡像,必需要先下載Docker鏡像。既然涉及到下載Docker鏡像,天然會存在Docker鏡像存儲。談到Docker鏡像存儲,那咱們首先來聊聊Docker鏡像大小方面的知識。優化

下面將從三個角度來分析Docker鏡像的大小問題:Dockerfile與鏡像聯合文件系統以及鏡像共享關係ui

Dockerfile與鏡像

Dockerfile由多條指令構成,隨着深刻研究Dockerfile與鏡像的關係,很是快你們就會發現。Dockerfile中的每一條指令都會相應於Docker鏡像中的一層。spa

繼續以例如如下Dockerfile爲例:

FROM ubuntu:14.04
ADD run.sh /
VOLUME /data
CMD ["./run.sh"]

經過docker build以上Dockerfile的時候。會在Ubuntu:14.04鏡像基礎上,加入三層獨立的鏡像,依次相應於三條不一樣的命令。

鏡像示意圖例如如下:

鏡像

有了Dockerfile與鏡像關係的初步認識以後,咱們再進一步聯繫到每一層鏡像的大小。

不得不說,在層級化管理的Docker鏡像中。有很多層大小都爲0。

那些鏡像層大小不爲0的狀況,歸根結底的緣由是:構建Docker鏡像時,對當前的文件系統形成了改動更新。

而改動更新的狀況主要有兩種:

1.ADD或COPY命令:ADD或者COPY的做用是在docker build構建鏡像時向容器中加入內容。僅僅要內容加入成功,當前構建的那層鏡像就是加入內容的大小,如以上命令ADD run.sh /。新構建的那層鏡像大小爲文件run.sh的大小。

2.RUN命令:RUN命令的做用是在當前空的鏡像層內執行一條命令,假若執行的命令需要更新磁盤文件。那麼所有的更新內容都在存儲在當前鏡像層中。

舉例說明:RUN echo DaoCloud命令不涉及文件系統內容的改動,故命令執行完以後當前鏡像層的大小爲0;RUN wget http://abc.com/def.tar命令會將壓縮包下載至當前文件夾下,所以當前這一層鏡像的大小爲:對文件系統內容的增量改動部分,即def.tar文件的大小。

聯合文件系統

Dockerfile中命令與鏡像層一一相應。那麼是否意味着docker build完成以後。鏡像的總大小=每一層鏡像的大小總和呢?答案是確定的。

依舊以上圖爲例:假設ubuntu:14.04鏡像的大小爲200MB,而run.sh的大小爲5MB,那麼以上三層鏡像從上到下,每層大小依次爲0、0以及5MB,那麼終於構建出的鏡像大小的確爲0+0+5+200=205MB。

儘管終於鏡像的大小是每層鏡像的累加,但是需要額外注意的是:Docker鏡像的大小並不等於容器中文件系統內容的大小(不包含掛載文件,/proc、/sys等虛擬文件)。箇中原因,就和聯合文件系統有很是大的關係了。

首先來看一下這個簡單的Dockerfile樣例(假如在Dockerfile當前文件夾下有一個100MB的壓縮文件compressed.tar):

FROM ubuntu:14.04
ADD compressed.tar /
RUN rm /compressed.tar
ADD compressed.tar /

1.FROM ubuntu:鏡像ubuntu:14.04的大小爲200MB;

2.ADD compressed.tar /: compressed.tar文件爲100MB,所以當前鏡像層的大小爲100MB,鏡像總大小爲300MB。

3.RUN rm /compressed.tar:刪除文件compressed.tar,此時的刪除並不會刪除下一層的compressed.tar文件。僅僅會在當前層產生一個compressed.tar的刪除標記,確保經過該層將看不到compressed.tar,所以當前鏡像層的大小也爲0。鏡像總大小爲300MB。

4.ADD compressed.tar /:compressed.tar文件爲100MB,所以當前鏡像層的大小爲300MB+100MB。鏡像總大小爲400MB。

分析完成以後,咱們發現鏡像的總大小爲400MB。但是假設執行該鏡像的話,咱們很是快可以發現在容器根文件夾下執行du -sh以後。顯示的數值並非400MB,而是300MB左右。基本的緣由仍是:聯合文件系統的性質保證了兩個擁有compressed.tar文件的鏡像層,僅僅會容器看到一個。同一時候這也說明了一個現狀,當用戶基於一個很是大,甚至好幾個GB的鏡像執行容器時。在容器內部查看根文件夾大小,發現竟然僅僅有500MB不到,設置更小。

分析至此,有一點你們需要很是注意:鏡像大小和容器大小有着本質的差異。

鏡像共享關係

Docker鏡像說大不大,說小不小。但是一旦鏡像的總數上來以後,豈不是對本地磁盤形成很是大的存儲壓力?平均每個鏡像500MB,豈不是100個鏡像就需要準備50GB的存儲空間?

結果每每不是咱們想象的那樣,Docker在鏡像複用方面設計得很是出色,大大節省鏡像佔用的磁盤空間。

Docker鏡像的複用主要體現在:多個不一樣的Docker鏡像可以共享一樣的鏡像層。

假設本地鏡像存儲中僅僅有一個ubuntu:14.04的鏡像。咱們以兩個Dockerfile來講明鏡像複用:

FROM ubuntu:14.04
RUN apt-get update
FROM ubuntu:14.04
ADD compressed.tar /

假設終於docker build構建出來的鏡像名分別爲image1和image2。由於兩個Dockerfile均基於ubuntu:14.04。所以。image1和image2這兩個鏡像均複用了鏡像ubuntu:14.04。

假設RUN apt-get update改動的文件系統內容爲20MB,終於本地三個鏡像的大小關係應該例如如下:

ubuntu:14.04: 200MB

image1:200MB(ubuntu:14.04)+20MB=220MB

image2:200MB(ubuntu:14.04)+100MB=300MB

假設僅僅是單純的累加三個鏡像的大小,那結果應該是:200+220+300=720MB,但是由於鏡像複用的存在,實際佔用的磁盤空間大小是:200+20+100=320MB,足足節省了400MB的磁盤空間。在此,足以證實鏡像複用的巨大優勢。

總結

學習Docker的同一時候,每每有三部份內容是分不開的,那就是Dockerfile。Docker鏡像與Docker容器,分析Docker鏡像大小也是如此。Docker鏡像的大小,貌似平淡無奇,倒是優化鏡像,容器磁盤限額必需要涉及的內容。

本系列將經過下面多篇文章來分析Docker鏡像:

1.深入理解 Docker 鏡像大小

2.事實上 docker commit 很是easy

3.不得不說的 docker save 與 docker export 差異

4.爲何有些容器文件動不得

5.打破 MNT Namespace 的容器 VOLUME

這裏寫圖片描寫敘述

歡迎關注[Docker源代碼分析]微信公衆號。不少其它精彩即將呈現。

相關文章
相關標籤/搜索