7.13 ONBUILD 為他人作嫁衣裳

7.13.1 基本語法

ONBUILD <其它指令>

ONBUILD 是一個特殊的指令,它後面跟的是其它指令 (如 RUNCOPY 等),這些指令 在當前映象建立時不會執行,只有當以當前映象為基礎映象去建立下一級映象時才會被執行。


7.13.2 為什麼需要 ONBUILD

ONBUILD 主要用於製作 語言棧基礎映象框架基礎映象

場景:維護 Node.js 專案

假設你有多個 Node.js 專案,它們的建立流程都一樣:

  1. 建立目錄
  2. 複製 package.json
  3. 執行 npm install
  4. 複製原始碼
  5. 啟動應用

如果不使用 ONBUILD,每個專案的 Dockerfile 都要重複這些步驟,且透過 COPY 複製檔案時,基礎映象無法預知子專案的檔案名。

使用 ONBUILD 的解決方案

基礎映象 (my-node-base)

FROM node:22-alpine
WORKDIR /app

## 這些指令將在子映象建立時執行

ONBUILD COPY package*.json ./
ONBUILD RUN npm install
ONBUILD COPY . .

CMD ["npm", "start"]

子專案 Dockerfile

FROM my-node-base

## 只需要一行!

## 建立時會自動執行 COPY 和 RUN

...

7.13.3 執行機制

基礎映象建立:
Dockerfile (含 ONBUILD) ──build──> 基礎映象 (記錄了 ONBUILD 觸發器)
                                    (指令未執行)

子映象建立:
FROM 基礎映象 ──build──> 讀取基礎映象觸發器 ──> 執行觸發器指令 ──> 繼續執行子 Dockerfile

7.13.4 常見使用場景

1. 自動處理依賴安裝

## Python 基礎映象

ONBUILD COPY requirements.txt ./
ONBUILD RUN pip install -r requirements.txt

2. 自動編譯程式碼

## Go 基礎映象

ONBUILD COPY . .
ONBUILD RUN go build -o app main.go

3. 處理靜態資源

## Nginx 靜態網站基礎映象

ONBUILD COPY dist/ /usr/share/nginx/html/

7.13.5 注意事項

1. 繼承性限制

ONBUILD 指令 只會繼承一次

  • 映象 A (含 ONBUILD)
  • 映象 B (FROM A) -> 觸發 ONBUILD
  • 映象 C (FROM B) -> 不會 再次觸發 ONBUILD

2. 建立上下文

子映象建立時,ONBUILD COPY . . 中的 . 指的是 子專案 的建立上下文,而不是基礎映象的上下文。

3. 不允許級聯

ONBUILD ONBUILD 是非法的。你不能寫 ONBUILD ONBUILD COPY ...

4. 可能會導致建立失敗

由於 ONBUILD 實際上是在子映象中執行指令,如果子專案的上下文不滿足要求 (例如缺少 package.json),會導致子映象建立失敗,且錯誤訊息可能比較隱晦。


7.13.6 最佳實踐

1. 命名規範

建議在映象標籤中新增 -onbuild 字尾,明確告知使用者該映象包含觸發器。

node:22-onbuild
python:3.12-onbuild

2. 避免執行耗時操作

儘量不要在 ONBUILD 中執行過於耗時或不確定的操作 (如更新系統軟件),這會讓子映象建立變得緩慢且不可控。

3. 清理工作

如果 ONBUILD 指令產生了臨時檔案,最好在同一個指令鏈中清理,或者提供機制讓子映象清理。


第 62 页,共 196 页
使用 mdPress 构建