## 🐳 [[Docker]] 映像檔瘦身之旅的開端:透過 `docker history` 揭開其「家譜」 {#sec-168deae1dd0f} 明明只啟動了一個輕量級應用程式,檢查映像檔大小卻發現它輕鬆超過了 1GB。您可能會疑惑:「我到底加了什麼?」感到不知所措。這時候,我們就需要揭開映像檔的「家譜」,一探究竟。 ![Docker 層次瘦身](/media/whitedec/blog_img/de42f6f1949c4e91bc6defa030f10ea5.webp) ## 「你到底吃了什麼,怎麼變得這麼胖?」 {#sec-5eaafdc2833e} Docker 映像檔就像一層層堆疊的洋蔥皮(層次)。`docker history` 這個指令就像是 X 光機,能夠一層層剝開這些「洋蔥皮」,找出讓映像檔臃腫的元兇。 其基本用法非常簡單。 ```bash # 基本用法 docker history [選項] <映像檔名稱:標籤> # 範例:查看我的應用程式歷史記錄 docker history my-app:latest ``` 執行此指令後,會從映像檔的最新層次開始,一直追溯到基礎映像檔,以逆序方式完整呈現。 ```text IMAGE CREATED CREATED BY SIZE a6215f271958 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B 7 weeks ago /bin/sh -c #(nop) ADD file:f28242cf608f6... 7.81MB ``` 請仔細觀察其中的 **SIZE** 欄位。如果應該是 0B 的地方卻顯示數百 MB,那麼它就是我們瘦身的目標。憑經驗來看,總會有些「可疑之處」。 > **💡 有用提示:`--no-trunc`** > > 預設輸出會截斷過長的指令。此時,加上 `--no-trunc` 選項,就能完整顯示整個指令,這對於精確分析至關重要。 > > `docker history --no-trunc my-app:latest` *** ## 實戰案例:「兇手就是 `chown`」 {#sec-036665971432} 讓我分享一個我親身經歷的真實案例。當時我建置了一個 150MB 的專案檔案,但映像檔大小卻異常地超過了 300MB。而元兇,竟然是 Dockerfile 中兩行看似再普通不過的程式碼。 **[低效率做法:產生 2 個層次]** ```dockerfile # 1. 先複製檔案 (預設以 root 權限複製) COPY . . # 2. 為安全性考量變更所有權 (以獨立指令執行) RUN chown -R appuser:appgroup /app ``` 在建置完畢後,我用 `docker history` 檢查,結果發現了以下內容: ```text IMAGE CREATED BY SIZE /bin/sh -c chown -R appuser:appgroup /app 150MB <-- (問題所在!) /bin/sh -c #(nop) COPY dir:abc in /app 150MB ``` 這就揭示了 Docker 層次的可怕之處。在第一步中,複製 150MB 的檔案會產生一個層次。然而,當在第二步執行 `chown` 時,Docker 會想:「咦?檔案資訊(所有權)變了?那麼,我必須在變更後的狀態下再建立一個層次!」於是,它會直接複製原有的 150MB 內容,堆疊出一個新的層次。 結果,內容物完全相同,卻因為所有權不同,導致檔案重複儲存了兩次,映像檔大小也隨之翻倍。 *** ## 解決方案:一行程式碼搞定瘦身! {#sec-b564ee91d4d9} 解決方案很簡單。只要在複製檔案時,一開始就指定好所有權,將層次合併為一個即可。 **[高效做法:產生 1 個層次]** ```dockerfile # 複製檔案的同時,也指定所有權! COPY --chown=appuser:appgroup . . ``` 將 Dockerfile 修改成這樣後,再次執行 `docker history`,結果將會是戲劇性的。 ```text IMAGE CREATED BY SIZE /bin/sh -c #(nop) COPY --chown=appuser... dir:abc 150MB ``` 看到了嗎?只產生了一個層次,映像檔大小也恢復到輕盈的 150MB。僅僅將兩行指令合併成一行,容量就減少了一半。 *** ## 結論:建置後務必檢查「歷史記錄」! {#sec-74645a10d229} 請務必記住,[[Docker]] 映像檔的原則是**每執行一行指令,就產生一個層次**。 就像編寫程式碼後需要進行測試一樣,建置完成後,請養成習慣執行 `docker history --no-trunc`。當您不斷追問「這個 `apt-get` 為什麼這麼臃腫?」「這個層次為什麼要特意分開?」這些問題時,不知不覺中,您將會建構出一個極其輕巧且高效的系統。 因為不必要的層次,正是系統效能的敵人! *** **這篇文章對您有幫助嗎?** 如果有,請不吝點個讚! 也請閱讀相關文章。 **相關文章** [徹底理解 Docker 共享記憶體 (shm_size 與 ipc)](/ko/whitedec/2025/11/5/docker-shm-size-ipc/) [Docker:不共享網路,透過主機埠實現容器間通訊](/ko/whitedec/2025/11/4/docker-host-port-container-communication/) [Docker 磁碟區 (Volume) 複製,為何必須這樣做?](/ko/whitedec/2025/11/10/docker-volume-copy-reason/)