概述
在構建 Docker 映像時,往往會不經意地增加容量。大部分原因在於 不必要生成的層。這篇文章使用 docker history 指令來檢查映像的'家譜',並分享我透過這個方法進行實際的映像輕量化經驗。
利用這個命令可以準確找到讓映像變重的原因,並製作出更高效的映像。
docker history: 檢查映像的家譜
docker history 是一個顯示特定映像如何生成及其組成歷史的指令。您可以查看 Dockerfile 中每個指令是堆疊為什麼 層(layer),以及每個層生成的時間和容量。
基本用法非常簡單。
docker history [選項] <映像名稱:標籤>
例如,檢查本地的 my-app:latest 映像歷史的命令如下:
docker history my-app:latest
從輸出結果可以看到從映像的最上層(最新)到基礎映像(最舊)按順序展示。
IMAGE CREATED CREATED BY SIZE
a6215f271958 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f28242cf608f6... 7.81MB
-
CREATED BY: 創建此層的 Dockerfile 指令
-
SIZE: 該層佔用的容量
有用的提示: 使用 --no-trunc 查看完整命令
docker history 的基本輸出會在 CREATED BY 欄位的命令過長時中途截斷。此時,若使用--no-trunc 選項,則可以不被截斷地查看所有命令,這對於精確分析非常重要。
docker history --no-trunc my-app:latest
為什麼層分析很重要: 實際優化經驗
Docker 映像基本原則是每個 Dockerfile 的 一行指令產生一層。每層則是堆疊在上一層上的'變更'。
問題在於,若不必要地拆分層,會驟增映像容量。
案例: COPY 和 RUN chown 的陷阱
在撰寫 Dockerfile 時,常常需要將專案檔案拷貝到容器中(COPY),接著將這些檔案的所有權改為特定用戶(例如: appuser)。
低效率的方法: 2 個層
最初,我是這樣撰寫 Dockerfile 的:
# 1. 將檔案複製過來(以 root 擁有權複製)
COPY . .
# 2. 改變所有權(以不同命令執行)
RUN chown -R appuser:appgroup /app
查詢 docker history 生成的映像歷史後,發現創建了兩個層。
IMAGE CREATED BY SIZE
<layer_id_2> /bin/sh -c chown -R appuser:appgroup /app 150MB <-- (問題!)
<layer_id_1> /bin/sh -c #(nop) COPY dir:abc in /app 150MB
這裡出現了嚴重的問題。
-
COPY . .命令將 150MB 的檔案添加到層 1。 -
RUN chown命令則是將層 1 的 150MB 檔案直接複製,然後僅變更所有權資訊並新存入層 2。
檔案內容相同,但一個屬於 root,另一個屬於 appuser,各自存儲在不同的層中。結果,這兩個層僅使映像總容量達到 300MB(150MB + 150MB)
有效的方法: 1 個層
這個問題可以通過將 COPY 命令的 --chown 標誌使用來簡單解決。
# 1. 同時指定所有權
COPY --chown=appuser:appgroup . .
修改後的 Dockerfile 後,重新查詢 docker history。
IMAGE CREATED BY SIZE
<layer_id_1> /bin/sh -c #(nop) COPY --chown=appuser... dir:abc 150MB
僅生成了一個層,映像的總容量減少至150MB。只是將兩行命令合併成一行,卻使映像容量減少近一半。
結論
docker history 不僅僅是查看映像的生成歷史,它是映像優化的核心分析工具。
修改 Dockerfile 之後,習慣性使用 docker history --no-trunc 來檢查是否按照預期生成了層,是否存在佔用不必要容量的層,這種小習慣可以創造出輕量且高效的映像。
目前沒有評論。