構建 Docker 映象的 N 個小技巧,運維工程師看過來

網路通訊頻道發表於2022-11-15

構建映象的幾個小技巧

構建上下文

執行 docker build 命令時,當前的工作目錄被稱為構建上下文。預設情況下,Dockerfile 就位於該路徑下。也可以透過 -f 引數來指定 dockerfile ,但 docker 客戶端會將當前工作目錄下的所有檔案傳送到 docker 守護程式進行構建。

所以來說,當執行 docker build 進行構建映象時,當前目錄一定要 乾淨 ,切記不要在家裡錄下建立一個 Dockerfile 緊接著 docker build 一把梭 。

正確做法是為專案建立一個資料夾,把構建映象時所需要的資源放在這個資料夾下。比如這樣:

也可以透過 .dockerignore 檔案來忽略不需要的檔案傳送到 docker 守護程式

基礎映象

使用體積較小的基礎映象,比如 alpine 或者 debian:buster-slim,像 openjdk 可以選用 openjdk:xxx-slim,由於 openjdk 是基於 debian 的基礎映象構建的,所以向 debian 基礎映象一樣,後面帶個 slim 就是基於 debian:xxx-slim 映象構建的。

不過需要注意的是,alpine 的 c 庫是 musl libc ,而不是正統的 glibc,另外對於一些依賴 glibc 的大型專案,像 openjdk 、tomcat、rabbitmq 等都不建議使用 alpine 基礎映象,因為 musl libc 可能會導致 JVM 一些奇怪的問題。這也是為什麼 tomcat 官方沒有給出基礎映象是 alpine 的 Dockerfile 的原因。

國內軟體源

使用預設的軟體源安裝構建時所需的依賴,對於絕大多數基礎映象來說,可以透過修改軟體源的方式更換為國內的軟體源映象站。目前國內穩定可靠的映象站主要有,華為雲、阿里雲、騰訊雲、163 等。

對於 alpine 基礎映象修改軟體源

debian 基礎映象修改預設原件原始碼

Ubuntu 基礎映象修改預設原件原始碼

對於 CentOS ???

你確定要用 220MB 大小的基礎映象?

建議這些命令就放在 RUN 指令的第一條,update 以下軟體源,之後再 install 相應的依賴。

時區設定

由於絕大多數基礎映象都是預設採用 UTC 的時區,與北京時間相差 8 個小時,這將會導致容器內的時間與北京時間不一致,因而會對一些應用造成一些影響,還會影響容器內日誌和監控的資料。

因此對於東八區的使用者,最好在構建映象的時候設定一下容器內的時區,以免以後因為時區遇到一些 bug。

可以透過環境變數設定容器內的時區。在啟動的時候可以透過設定環境變數 -e TZ=Asia/Shanghai 來設定容器內的時區。

alpine

但對於 alpine 基礎映象無法透過 TZ 環境變數的方式設定時區,需要安裝 tzdata 來配置時區。

對於 alpine 基礎映象,可以在 RUN 指令後面追加上以下命令

透過 tzdate 設定時區

debian

透過啟動時設定環境變數指定時區

也可以再構建映象的時候複製時區檔案設定容器內時區

ubuntu

透過啟動時設定環境變數指定時區,發射失敗 ,只能透過時區檔案來設定時區了。

在這裡有個命令執行的小技巧,透過脫字元 ^ 來替換上一條命令中的 debian 為 ubuntu 然後執行相同的命令。

透過時區檔案來設定時區

儘量使用 URL 新增原始碼

如果不採用分階段構建,對於一些需要在容器內進行編譯的專案,最好透過 git 或者 wegt 的方式將原始碼打入到映象內,而非採用 ADD 或者 COPY ,因為原始碼編譯完成之後,原始碼就不需要可以刪掉了,而透過 ADD 或者 COPY 新增進去的原始碼已經用在下一層映象中了,是刪不掉滴啦。

也就是說 git & wget source 然後 build,最後 rm -rf source/ 這三部放在一條 RUN 指令中,這樣就能避免原始碼新增到映象中而增大映象體積啦。

下面以 FastDFS 的 Dockerfile 為例:

專案官方的 Dockerfile

經過本人最佳化後的 Dockerfile

構建之後的對比

使用專案預設的 Dockerfile 進行構建的話,映象大小接近 500MB,而經過一些的最佳化,將所有的 RUN 指令合併為一條,最終構建出來的映象大小為 30MB。

使用虛擬編譯環境

對於只在編譯過程中使用到的依賴,我們可以將這些依賴安裝在虛擬環境中,編譯完成之後可以一併刪除這些依賴,比如 alpine 中可以使用 apk add --no-cache --virtual .build-deps,後面加上需要安裝的相關依賴。

構建完成之後可以使用 apk del .build-deps 命令,一併將這些編譯依賴全部刪除。

需要注意的是,.build-deps 後面接的是編譯時以來的軟體包,並不是所有的編譯依賴都可以刪除,不要把執行時的依賴包接在後面,最好單獨 add 一下。

最小化層數

docker 在 1.10 以後,只有 RUN、COPY 和 ADD 指令會建立層,其他指令會建立臨時的中間映象,但是不會直接增加構建的映象大小了。

前文提到了建議使用 git 或者 wget 的方式來將檔案打入到映象當中,但如果我們必須要使用 COPY 或者 ADD 指令呢?

還是拿 FastDFS 為例:

多個檔案需要新增到容器中不同的路徑,每個檔案使用一條 ADD 指令的話就會增加一層映象,這樣戲曲就多了 12 層映象 。

其實大可不必,我們可以將這些檔案全部打包為一個檔案為 src.tar.gz 然後透過 ADD 的方式把檔案新增到當中去,然後在 RUN 指令後使用 mv 命令把檔案移動到指定的位置。這樣僅僅一條 ADD 和 RUN 指令取代掉了 12 個 ADD 指令。

其他最小化層數無非就是把構建專案的整個步驟弄成一條 RUN 指令,不過多條命令合併可以使用 && 或者 ; 這兩者都可以,不過據我在 docker hub 上的所見所聞,使用 ; 的居多,尤其是官方的 Dockerfile。

來自 “ https://blog.k8s.li/dockerfile-tips.html ”, 原文作者:reimu;原文連結:https://blog.k8s.li/dockerfile-tips.html,如有侵權,請聯絡管理員刪除。

相關文章