最佳化 Dockerfile - 活用 cache
今天來看看如何利用 cache 讓 build image 更加順利。
Build image 第一次會正常執行每一個指令,第二次如果發現是同一個 commit 上,執行同一個指令,且結果推測不會變的時候,會把前一次執行結果的 commit 直接拿來用,並標上 Using cache
訊息。
---> Using cache |
有效利用 cache 可以提升開發或測試 build image 的效率,這也是最佳化 Dockerfile 的一環。
延續使用昨天的 Dockerfile:
FROM php:7.3 |
上面這個範例無法有效利用 cache,可以用以下指令做個實驗:
# 先確認 build image 可以抓 cache |
從這個範例可以發現,程式有做任何修改,build image 都會需要全部重跑,浪費時間也浪費網路頻寬。
而根據 cache 生效的規則,我們只要找到第一個沒有 Using cache
的指令,就有機會知道問題在哪。
Step 1/7 : FROM php:7.3 |
從這個輸出資訊來看,是 COPY . .
沒有使用 cache。這是因為 touch 新檔案也包含在 COPY . .
的範圍裡,但新檔案 Docker 也不知道跟 build image 過程有關係,因此會讓 COPY . .
重新執行,接著後面全部都需要一起重新執行。
類似的問題,COPY
是針對 host 檔案,另外還有一個很像的指令是 ADD
,後面可以接下載檔案的端口,如:
ADD https://example.com/download.zip . |
它會在 build image 的時候下載連結的檔案並複製進 container。這功能看似很方便,實際上是會嚴重拖累 build image 時間的。因為一開始有提到:「結果推測不會變的時候」才會使用 cache。上面 ADD
例子的問題點在於,必須要把檔案下載回來才知道檔案內容有沒有被修改過,於是變成每次 build image 都需要下載檔案。
回到範例的 Dockerfile,調整方法很簡單,記住一個原則:
不常變動的 能早做就早做 |
我們把 Dockerfile 分做幾個部分:
- 全域設定
- 安裝環境,如 unzip 指令
- 安裝程式工具,如 composer 指令
- 程式碼
概念上來說,環境與工具會是變動最少的,最常變動的則是程式碼。通常全域設定會放在一開始,偶爾在常調整設定的時候,會放在最後方便測試,最終還是要看使用情境與習慣。
根據上述順序調整如下:
FROM php:7.3 |
用一樣的流程測看看,會看到 Using cache
變多,速度也變快很多。
Step 1/7 : FROM php:7.3 |
但一樣卡在時間花最久的 composer install
,它不能放到 COPY . .
的上面,因為它會需要複製進去的 composer.json
與 composer.lock
。
咦?既然它需要這兩個檔,那就先複製進去再執行 composer install
就好了呀!改法如下:
FROM php:7.3 |
這次會發現 composer install
有用到 cache,而且速度已經快到可以全程錄進 GIF 了。
Sending build context to Docker daemon 501.8kB |
這個 Dockerfile 對 cache 的最佳化就到此結束,從剛實驗看起來,目前改程式重 build image 都非常快速,已達成今天所預期的目標。
不使用 cache
最後補充一點,有些情況會希望 Docker 強制重新 build image 而不要使用 cache,這時可以使用之前提供的 Makefile 裡的 make rebuild
指令:
rebuild: |
相信不需要解釋,--no-cache
正是不使用 cache。
今日自我回顧
今天介紹的最佳化方法,是著重在利用 cache 加速 build image。但不要忘了今天開頭提到的,cache 就是 commit,有時候必須要把它視為 commit 來做最佳化,這將會是明天的主題。
- 了解
Using cache
在 build image 是怎麼運作的 - 練習利用 cache 加速 build image 的方法