精簡為王:Docker鏡像體積詳解

welwit 8年前發布 | 32K 次閱讀 Docker WildFly Fedora

 

不知道大家讀過使用Docker容器的十大誤區(沒讀過的可以戳這個鏈接 http://www.baiduhome.net/lib/view/open1463108483467.html )如果讀過,相信大家已經對跑Docker容器時的幾個注意事項有了大概的了解了。不過文中關于“不要把鏡像體積建得很大”這一點講得不是很詳細,還有這一句:“千萬不要在鏡像中安裝些沒必要的東西,在構建鏡像的時候要避免使用yum這種update命令,免得系統自動下載很多不相干的文件到新鏡像層中”,大家可能還有一些問題。比方說,為什么簡簡單單一句“yum update”命令就會構建出一個超大體積的鏡像?可能很多人都還不清楚其中的原理。為了幫助大家理解這個問題,下面我們就來深入探討一下docker鏡像的構建機制,此外還有一些小技巧,可以幫助大家在不影響鏡像內容更新的條件下,縮減鏡像的體積。

本文用到的基礎鏡像是最新版的 Fedora 23(用RHEL也可以),大家可以用 docker pull fedora:23 命令來pull這個鏡像。

Pull下來之后運行 docker images ,可以看到鏡像大小是204.7MB。然后我們用從GitHub下載的Dockerfile來創建一個包含JDK 1.8好WildFly 9.0.2.Final的自定義鏡像,大家可以自己去GitHub下載Dockerfile。

鏡像創建完以后體積已經達到了567.3 MB,大家可以運行一下“docker history <鏡像名>”,查看每個層的大小。我的鏡像里面,JDK 1.8有203.5MB,WildFly有159.1 MB,體積相當大。

這還不算完,創建這個鏡像之后,我們最終肯定是要升級到WildFly 10.0.0.Final版的,如果不想重新安裝 JDK 1.8的話,很多人都會選擇在現有鏡像的基礎上,用10.0.0.Final替換WildFly 9.0.2.Final。如果你以為升級下來鏡像大小還是567 MB的話,那就大錯特錯了,實際上升級后的鏡像體積是728.1 MB。就算你在往鏡像中添加WildFly 10.0.0.Final之前先刪除掉WildFly 9.0.2.Final,最后得到的鏡像還是要比原先大160MB。文件體積的增大并不是因為WildFly版本之間的差異造成的。

寫入時拷貝

那么為什么鏡像文件會增大呢?原因就在于Docker容器的文件系統采用了寫入時拷貝技術,這項技術的作用是加快容器的啟動時間,跟一般的虛擬機相比,容器的啟動速度確實非常快。雖然該技術在很大程度上提升了docker容器的運行效率,但是也會增加磁盤讀寫方面的開銷。所以,為了避免文件體積過大,有幾個問題需要我們在構建鏡像的時候注意一下。

這里要先說一下,每次在Dockerfile中執行RUN命令的時候系統都會在鏡像中新建一個層,每個鏡像層都會占用一定的磁盤空間,所以,在upgrade WildFly的時候我們其實是創建了一個新的層。因此為了盡量減少鏡像的層數,最好把移動、提取、刪除等所有文件操作都寫在同一行RUN命令下。

大家可以參照下面的命令行寫法,這個命令把WildFly 10.0.0.Final的安裝、下載、提取、移動和清理命令都寫在一行里,這樣創建下來的鏡像體積就只有569.1 MB:

"cd /tmp && curl -O https://download.jboss.org/wildfly/ $WILDFLY_VERSION/wildfly-$WILDFLY_VERSION.tar.gz && tar xf wildfly-$WILDFLY_VERSION.tar.gz && mv /tmp/wildfly-$WILDFLY_VERSION /opt/jboss/wildfly && rm /tmp/wildfly-$WILDFLY_VERSION.tar.gz"

如果我們每寫一條命令都執行一次RUN的話,鏡像就會多出4個層,最后得到的鏡像大小將是867.1 MB。如下圖所示,我們可以用“docker history”命令來查看鏡像的層以及每個層的大小:

Yum Update

那么問題來了,“yum update”到底是做什么用的呢?為了幫助大家更好地理解“yum update”的作用,我建了fedora:22和fedora:23兩個鏡像。這兩個自定義鏡像都是用 RUN dnf -y update 命令從Dockerfile創建的,fedora:22 的大小是531.2 MB,fedora:23是358.2 MB。

在這個命令下,Fedora:22會自動更新到跟Fedora 23一樣的版本,因此會下載安裝很多文件,最后的體積也要大些。所以在構建鏡像的時候,如果能用現有平臺上最新的基礎鏡像(比如說構建的時候用Fedora 23,不要用Fedora 22)來建的話,就可以避免往中間層寫入很多額外的文件,這樣做不僅能加快鏡像創建速度,還可以縮減鏡像大小。

總之我想說的就是,執行“updates”命令的時候會下載一些新的rpm包,所以對鏡像文件的改動還是蠻大的。雖然之前的鏡像層無法修改,但rpm cache是可以清理的。我們只需要以寫“RUN dnf -y update && dnf clean all”命令就可以清理cache了,執行該命令后,鏡像大小從358.2 MB變到了216.2 MB,之比原來的fedora:23鏡像大11.5MB。這個辦法很好用,大家在執行update之后,一定要記得做清理,這樣就能最大限度地節省空間。

綜上,“yum/dnf update”命令本身并沒有什么問題,導致鏡像文件過大的原因主要還是因為我們對docker的分層式文件系統不太了解,很多人都不知道這種文件系統會對鏡像體積造成很大的影響。如果我們只有幾個容器的話,這些都還算可以忍受,但如果是在集群里面部署大量容器的話,鏡像體積過大就會很麻煩,但是我們又不可能完全不使用update命令,不然我們的linux容器就會產生bug或者安全漏洞等等問題。

最好的解決辦法就是把update和清理命令都放在同一行RUN底下,在執行update的同時釋放多余的空間,這樣我們就可以有效地縮減鏡像體積。

via: http://dockone.io/article/1302

 本文由用戶 welwit 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!