[譯]渣翻:Dockerfile最佳實踐

原文地址:blog.docker.com/2019/07/int…java

現在在 github 上已經有超過一百萬的 Dockerfile 文件,但並不是全部的 Dockerfile 都是同個級別的。效率相當重要,本博客系列將介紹 Dockerfile 最佳實踐的以下五個方面,以幫助您編寫更好的 Dockerfile:遞增的構建時間,鏡像大小,可維護性,安全性和可重複性。若是您剛開始使用 Docker,那麼這第一篇博客便很適合你。該系列的下一篇文章將會更進一步。git

重要提示:下面的提示遵循不斷改進 Dockerfile 的過程,以得到基於 Maven 的示例Java 項目。 所以,最後一個 Dockerfile 是推薦的 Dockerfile,而全部中間文件只是爲了說明特定的最佳實踐。github

遞增的構建時間

在開發週期中,構建Docker鏡像,進行代碼更改,而後重構的時候,利用緩存是很重要的。 緩存有助於避免在不須要時再次運行構建步驟。docker

Tip #1:順序對緩存很重要

然而,構建步驟(Dockerfile 指令)的順序很重要,由於當經過更改文件或修改 Dockerfile 中的行來使步驟的緩存無效時,其緩存的後續步驟將會中斷。 從最少到最頻繁更改的步驟進行排序以優化緩存。緩存

Tip #2:更具體的 COPY 限制緩存破滅

只複製所需的內容。 儘量的避免COPY .。將文件複製到鏡像中時,請確保您要複製的內容很是具體。 對正在複製的文件,任何更改都將會破壞緩存。 在上面的示例中,鏡像中只須要預先構建的 jar 應用程序,所以只需複製它。 這樣不相關的文件更改不會影響緩存。安全

Tip #3:識別可緩存的單元,例如 apt-get update&install

每一個RUN 指令均可以看做是可緩存的執行單元。 其中太多多是沒必要要的,而將全部命令連接到一個 RUN 指令可能會輕易破壞緩存,從而損害開發週期。 從包管理器安裝包時,您老是但願更新索引並在同一個 RUN 中安裝包:它們一塊兒造成一個可緩存單元。 不然您可能會安裝過期的軟件包。app

減少鏡像大小

鏡像大小是很重要的,那意味着較小的鏡像等於更快的部署和較小的攻擊面。maven

Tip #4:移除沒必要要的依賴

移除沒必要要的依賴項,不要安裝調試工具。 若是須要,之後能夠隨時安裝調試工具。 某些包管理器(如 apt )會自動安裝由用戶指定的包推薦的包,從而沒必要要地增長佔用空間。 Apt 具備 -no-install-recommendations 標誌,可確保不安裝實際不須要的依賴項。 若是須要,請明確添加。ide

Tip #5:刪除包管理器緩存

包管理器維護本身的緩存,這可能最終出如今鏡像中。 處理它的一種方法是在安裝包的相同RUN指令中刪除緩存。 在另外一個RUN指令中刪除它不會減少圖像大小。工具

還有其餘方法能夠減小圖像大小,例如多階段構建,這將在本博文末尾介紹。 下一組最佳實踐將探討如何優化Dockerfile的可維護性,安全性和可重複性。

可維護性

Tip #6:儘量使用官方鏡像

官方鏡像能夠節省大量維護時間,由於全部安裝步驟都已完成而且應用了最佳實踐。 若是您有多個項目,他們能夠共享這些鏡像,由於它們使用徹底相同的基本鏡像。

Tip #7:使用更具體的 tag

不要使用 latest 標籤。雖然它具備始終可用於Docker Hub上的官方圖像的便利性,但隨着時間的推移可能會發生重大變化。 根據您在沒有緩存的狀況下重建Dockerfile的時間間隔,您可能會構建失敗。

替代的是,對您的基礎鏡像使用更具體的標籤。在此例中,咱們使用 openjdk:8。 還有更多可用的標籤,所以請查看該圖像的Docker Hub文檔,其中列出了全部現有的版本。

Tip #8:尋找最小的 Flavor

這些標籤中的一些具備最小的 flavor,這意味着它們甚至能夠是更小的鏡像。 纖薄的變體基於剝離的Debian,而 alpine 則是基於更小的Alpine Linux分佈鏡像。 一個顯著的區別是debian仍然使用GNU libc而alpine使用musl libc。musl libc 雖然小得多,但在某些狀況下可能會致使兼容性問題。 在openjdk的狀況下,jre風格只包含java運行時,而不是sdk;這也大大減小了鏡像大小。

譯者注: flavor:(物理學)夸克和反夸克的一種

再生性

到目前爲止,上面的 Dockerfiles 假設你的 jar 包是在主機上構建的。 這並不理想,由於您失去了容器提供的一致環境的好處。 例如,若是您的 Java 應用程序依賴於特定庫,則可能會引入不受歡迎的不一致性,而這具體取決於構建應用程序的計算機。

Tip #9:在一致的環境中構建源代碼

源代碼是您想要構建 Docker 鏡像的真實來源。 Dockerfile只是藍圖。

您應該首先肯定構建應用程序所需的全部內容。 咱們簡單的 Java 應用程序須要 Maven 和 JDK,因此讓咱們的 Dockerfile 基於 Docker Hub 中包含 JDK 的特定最小官方 maven 鏡像。 若是須要安裝更多依賴項,能夠在 RUN 步驟中執行此操做。

pom.xmlsrc 文件夾將被複制,由於它們是生成帶有 mvn 包的 app.jar 應用程序的最終 RUN 步驟所需的。 (-e 標誌顯示錯誤,-B 以非交互式名稱「批處理」模式運行)。

咱們解決了環境不一致的問題,但引入了另外一個問題:每次更改代碼時,都會獲取 pom.xml 中的全部依賴項。 所以有了下一個技巧。

Tip #10:在單獨的步驟中獲取依賴項

經過再次考慮可緩存的執行單元,咱們能夠斷定獲取依賴項是一個單獨的可緩存單元,只須要依賴於對 pom.xml 文件而不是源代碼的更改。 兩個 COPY 步驟之間的 RUN 步驟告訴 Maven 只獲取依賴項。

經過在一致的環境中構建引入了另一個問題:咱們的鏡像比之前更大,由於它包含運行時不須要的全部構建時依賴項。

Tip #11:使用多階段構建以移除構建依賴(推薦的Dockerfile)

多階段構建可由多個 FROM 語句識別。 每一個 FROM 開始一個新的階段。 它們能夠用 AS 關鍵字命名,咱們用它來命名咱們的第一階段「builder」,以便稍後引用。 它將在一致的環境中包含全部構建依賴項。

第二階段是咱們的最後階段,將產生最終鏡像。它將包括運行時的嚴格必要條件,在本例中是基於 Alpine 的最小 JRE(Java運行時)。 中間 builder 階段將被緩存但不會出如今最終鏡像中。 要將構建工件添加到最終圖像中,請使用 COPY --from = STAGE_NAME 。 在本例中,STAGE_NAMEbuilder

多階段構建是消除構建時依賴性的首選解決方案。

咱們從不一致地構建臃腫的鏡像,到在一致環境中構建出最小鏡像,同時緩存友好。 在下一篇博客文章中,咱們將更多地介紹多階段構建的其餘用途。

更多

相關文章
相關標籤/搜索