Multi-Stage Build
什麼是多階段構建?
多階段構建(Multi-Stage Build) 是 Dockerfile 提供的一種最佳化技術,可以減少映像檔大小,並確保最終的映像檔只包含必要的執行環境,而不會帶有開發工具或額外的檔案。
在多階段構建中,Dockerfile 會定義多個階段(Stages),前面的階段負責編譯與打包,最後的階段則負責執行應用程式。
為什麼需要多階段構建?
在一般的 Dockerfile 中,我們可能會:
- 下載依賴(Install Dependencies)
- 編譯應用程式(Build Application)
- 執行應用程式(Run Application)
這樣做的問題是:
- 最終的映像檔可能會包含開 發工具(如編譯器、測試工具)
- 映像檔會變得很大,占用大量空間
- 安全性較低(因為開發工具不應該出現在生產環境)
沒有使用多階段構建的 Dockerfile
FROM golang:1.21 AS base
WORKDIR /app
COPY . .
RUN go build -o myapp
CMD ["./myapp"]
這樣的問題是:映像檔內包含整個 Go 開發環境,即使執行時不需要 Golang,仍然佔用空間。
多階段構建範例
我們可以使用多階段構建來解決這個問題,讓映像檔變得更小、更快、更安全。
使用 Multi-Stage Build
# === 第一階段:編譯應用程式(Build Stage) ===
FROM golang:1.21 AS builder
# 設定工作目錄
WORKDIR /app
# 複製專案程式碼
COPY . .
# 初始化 Go 模組(如果沒有 go.mod)
RUN go mod init mygoapp && go mod tidy
# 編譯程式(靜態編譯,讓執行時不依賴 Go 環境)
RUN CGO_ENABLED=0 go build -o myapp && chmod +x myapp
# === 第二階段:最小化執行環境(Run Stage) ===
FROM alpine:latest
# 安裝必要的函式庫
RUN apk --no-cache add ca-certificates
# 設定工作目錄
WORKDIR /root/
# 複製第一階段的執行檔
COPY /app/myapp .
# 開放 Port 8080
EXPOSE 8080
# 執行應用程式
CMD ["./myapp"]
多階段構建的運作方式
第一階段(Builder Stage)
- 使用
golang:1.21
作為基礎映像檔 - 設定
/app
為工作目錄,並將專案程式碼複製到容器內 - 初始化 Go 模組(
go mod init
),並下載所需依賴(go mod tidy
) - 編譯 Go 應用程式(使用
CGO_ENABLED=0
來確保靜態編譯) - 設定執行權限(
chmod +x myapp
)
第二階段(Run Stage)
- 使用
alpine:latest
(更小的 Linux 映像檔)作為執行環境 - 安裝
ca-certificates
(若應用程式需要 HTTPS 請求) - 僅複製已編譯的
myapp
可執行檔(不包含 Go 編譯器、測試工具) - 開放 8080 端口,供外部存取應用程式
- 設定
CMD ["./myapp"]
,讓容器啟動時執行應用程式
優勢比較
方法 | 映像檔大小 | 安全性 | 執行效能 |
---|---|---|---|
單階段構建 | 大(包含完整開發環境) | 低(可能包含不必要的工具) | 慢(更多依賴) |
多階段構建 | 小(只保留執行檔) | 高(無多餘工具) | 快(精簡執行環境) |
多階段構建適用的情境
- ✅ Golang、Rust、C++、Java 等需要編譯的語言
- ✅ Node.js、Python 等有大量依賴的應用程式
- ✅ 任何希望減少映像檔大小、提升安全性與效能的應用
總結
- 多階段構建可讓最終映像檔變小,因為不會保留開發工具與不必要的檔案。
- 提高安全性,因為只包含最小的執行環境,不會帶入開發工具。
- 提升執行效能,減少啟動時間與依賴。
- 適用於所有需要編譯的應用(特別適用於 Go、C++、Rust、Java)。
使用 Multi-Stage Build,可以讓 Docker 映像檔更輕量、更快、更安全! 🚀