分層存儲
??因為鏡像包含操作系統(tǒng)完整的 root
文件系統(tǒng)朗兵,其體積往往是龐大的,因此在 Docker 設(shè)計時,就充分利用 Union FS 的技術(shù),將其設(shè)計為分層存儲的架構(gòu)遵蚜。所以嚴(yán)格來說,鏡像并非是像一個 ISO 那樣的打包文件奈惑,鏡像只是一個虛擬的概念吭净,其實際體現(xiàn)并非由一個文件組成,而是由一組文件系統(tǒng)組成肴甸,或者說寂殉,由多層文件系統(tǒng)聯(lián)合組成。
??鏡像構(gòu)建時原在,會一層層構(gòu)建友扰,前一層是后一層的基礎(chǔ)。每一層構(gòu)建完就不會再發(fā)生改變庶柿,后一層上的任何改變只發(fā)生在自己這一層村怪。比如,刪除前一層文件的操作浮庐,實際不是真的刪除前一層的文件甚负,而是僅在當(dāng)前層標(biāo)記為該文件已刪除。在最終容器運行的時候兔辅,雖然不會看到這個文件腊敲,但是實際上該文件會一直跟隨鏡像。因此维苔,在構(gòu)建鏡像的時候碰辅,需要額外小心,每一層盡量只包含該層需要添加的東西介时,任何額外的東西應(yīng)該在該層構(gòu)建結(jié)束前清理掉没宾。
??分層存儲的特征還使得鏡像的復(fù)用凌彬、定制變的更為容易。甚至可以用之前構(gòu)建好的鏡像作為基礎(chǔ)層循衰,然后進(jìn)一步添加新的層铲敛,以定制自己所需的內(nèi)容,構(gòu)建新的鏡像会钝。
docker鏡像原理
??docker鏡像在構(gòu)建的時候利用了aufs文件系統(tǒng)的掛載原理伐蒋,對文件系統(tǒng)進(jìn)行構(gòu)建。
??首先,存在一個 docker 容器在啟動時其內(nèi)部進(jìn)程可見的文件系統(tǒng)視角,或者稱為docker 容器的根目錄rootfs迁酸。目錄下含有 docker 容器所需要的系統(tǒng)文件先鱼、工具、容器文件等奸鬓。(只讀屬性)
??接著焙畔,在特定的鏡像中存在每一個鏡像獨有的文件系統(tǒng)(讀寫屬性),以ubuntu鏡像為例串远,如下圖:
??在docker實際應(yīng)用中宏多,鏡像相當(dāng)于只讀層,而容器則相當(dāng)去上圖中的可寫層澡罚。已構(gòu)建的鏡像會設(shè)置成只讀模式伸但,read-write寫操作是在read-only上的一種增量操作,固不影響read-only層始苇。
??無論是unbuntu這種OS系統(tǒng)砌烁,還是mysql,mongo這種具體應(yīng)用筐喳。docker利用的aufs文件系統(tǒng)在文件系統(tǒng)掛載時對鏡像進(jìn)行復(fù)用催式。
??所以我們假設(shè) docker build 構(gòu)建出來的鏡像名分別為 image 1 和 image 2,由于兩個 Dockerfile 均基于ubuntu:14.04避归,因此荣月,image 1 和 image 2 這兩個鏡像均復(fù)用了鏡像 ubuntu:14.04。 假設(shè) RUN apt-get update 修改的文件系統(tǒng)內(nèi)容為 20 MB梳毙,最終本地三個鏡像的大小關(guān)系應(yīng)該如下 :
ubuntu:14.04: 200 MB
image 1:200 MB(ubuntu:14.04 的大胁刚)+ 20 MB = 220 MB
image 2:200 MB(ubuntu:14.04 的大小)+ 100 MB = 300 MB
??如果僅僅是單純的累加三個鏡像的大小账锹,那結(jié)果應(yīng)該是:200 + 220 + 300 = 720 MB萌业,但是由于鏡像復(fù)用的存在,實際占用的磁盤空間大小是:200 + 20 + 100 + 320 MB奸柬,足足節(jié)省了 400 MB 的磁盤空間生年。在此,足以證明鏡像復(fù)用的巨大好處廓奕。
由此可以說明docker images 列表下鏡像大小之和并非是鏡像實際硬盤消耗
鏡像的精簡優(yōu)化
1.優(yōu)化基礎(chǔ)鏡像
??基礎(chǔ)鏡像選擇時抱婉,選擇合適的較小的鏡像,常用的 Linux 系統(tǒng)鏡像一般有 Ubuntu档叔、CentOs、Alpine···等
2.串聯(lián) Dockerfile 指令
??在 Dockerfile 中蒸绩, 每一條指令都會創(chuàng)建一個鏡像層衙四,繼而會增加整體鏡像的大小。當(dāng)前層作出的操作修改不會影響上一層患亿。
-用&&串聯(lián)指令(一般是RUN指令)
-安裝完軟件記得clean
具體實例如下:
創(chuàng)建自定義Dockerfile传蹈,
FROM ubuntu:14.04
#基礎(chǔ)源鏡像
MAINTAINER yinjun
#描述鏡像的創(chuàng)建者,名稱和郵箱
WORKDIR /home
RUN dd if=/dev/zero of=50M.file bs=1M count=50
#創(chuàng)建大小為50M的測試文件
RUN rm -rf 50M.file
#刪除該文件
用該文件生成鏡像步藕,執(zhí)行創(chuàng)建鏡像命令:
docker build -t test:A .
查看生成鏡像信息:
docker images
結(jié)果如下:
可以看到生成的鏡像test:A大小為240M卡睦,接下來我們將dockerfile命令進(jìn)行串聯(lián),從而減少層漱抓,具體操作如下:
修改Dockerfile文件表锻,將RUN指令通過&&合并到一起:
FROM ubuntu:14.04
#基礎(chǔ)源鏡像
MAINTAINER yinjun
#描述鏡像的創(chuàng)建者,名稱和郵箱
WORKDIR /home
RUN dd if=/dev/zero of=50M.file bs=1M count=50 && rm -rf 50M.file
#創(chuàng)建文件乞娄,同時在改層刪除該文件
以此創(chuàng)建新鏡像瞬逊,具體操作與以前相同,鏡像名為test:A仪或,同樣查看docker images
如下:
到此可見同樣命令确镊,通過run命令串聯(lián),鏡像大小縮減了240M-188M=52M
注:
??其實我們可以發(fā)現(xiàn)范删,前面例子中的dockerfile中只是簡單執(zhí)行了創(chuàng)建文件蕾域,然后刪除該文件的操作,文件創(chuàng)建后再刪除到旦。常規(guī)我們一般會認(rèn)為這種操作實際沒有占用存儲空間旨巷,這里就是docker 鏡像的不同之處,由上文我們可以得知添忘,dockerfile創(chuàng)建每條指令都是一個layers層采呐,之后layers層的操作不會影響上一層,也就是說即使我們在該RUN層進(jìn)行rm -rf 50M.file
刪除操作搁骑,也只是在本層中起作用斧吐,而上一層創(chuàng)建的文件依然保留,不會受到影響仲器。所有盡可能將操作指令合并到同一個RUN層中煤率,從而達(dá)到精簡鏡像的目的。