onBUILD 是一個特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而這些指令,在當(dāng)前鏡像構(gòu)建時并不會被執(zhí)行。只有當(dāng)以當(dāng)前鏡像為基礎(chǔ)鏡像,去構(gòu)建下一級鏡像的時候才會被執(zhí)行。
ONBUILD命令格式
onBUILD <其它指令>
假設(shè)我們要制作 Node.js 所寫的應(yīng)用的鏡像。我們都知道 Node.js 使用 npm 進(jìn)行包管理,所有依賴、配置、啟動信息等會放到 package.json 文件里。在拿到程序代碼后,需要先進(jìn)行 npm install 才可以獲得所有需要的依賴。然后就可以通過 npm start 來啟動應(yīng)用。因此,一般來說會這樣寫 Dockerfile:
FROM node:slim
RUN mkdir /app
WORKDIR /app
COPY ./package.json /app
RUN [ "npm", "install" ]
COPY . /app/
CMD [ "npm", "start" ]
把這個 Dockerfile 放到 Node.js 項目的根目錄,構(gòu)建好鏡像后,就可以直接拿來啟動容器運行。但是如果我們還有第二個 Node.js 項目也差不多呢?那就再把這個 Dockerfile 復(fù)制到第二個項目里。那如果有第三個項目呢?再復(fù)制么?文件的副本越多,版本控制就越困難,讓我們繼續(xù)看這樣的場景維護(hù)的問題。
如果第一個 Node.js 項目在開發(fā)過程中,發(fā)現(xiàn)這個 Dockerfile 里存在問題,比如敲錯字了、或者需要安裝額外的包,然后開發(fā)人員修復(fù)了這個 Dockerfile,再次構(gòu)建,問題解決。第一個項目沒問題了,但是第二個項目呢?雖然最初 Dockerfile 是復(fù)制、粘貼自第一個項目的,但是并不會因為第一個項目修復(fù)了他們的 Dockerfile,而第二個項目的 Dockerfile 就會被自動修復(fù)。
那么我們可不可以做一個基礎(chǔ)鏡像,然后各個項目使用這個基礎(chǔ)鏡像呢?這樣基礎(chǔ)鏡像更新,各個項目不用同步 Dockerfile 的變化,重新構(gòu)建后就繼承了基礎(chǔ)鏡像的更新?好吧,可以,讓我們看看這樣的結(jié)果。那么上面的這個 Dockerfile 就會變?yōu)椋?/p>
FROM node:slim
RUN mkdir /app
WORKDIR /app
CMD [ "npm", "start" ]
這里我們把項目相關(guān)的構(gòu)建指令拿出來,放到子項目里去。假設(shè)這個基礎(chǔ)鏡像的名字為 my-node 的話,各個項目內(nèi)的自己的 Dockerfile 就變?yōu)椋?/p>
FROM my-node
COPY ./package.json /app
RUN [ "npm", "install" ]
COPY . /app/
基礎(chǔ)鏡像變化后,各個項目都用這個 Dockerfile 重新構(gòu)建鏡像,會繼承基礎(chǔ)鏡像的更新。
那么,問題解決了么?沒有。準(zhǔn)確說,只解決了一半。如果這個 Dockerfile 里面有些東西需要調(diào)整呢?比如 npm install 都需要加一些參數(shù),那怎么辦?這一行 RUN 是不可能放入基礎(chǔ)鏡像的,因為涉及到了當(dāng)前項目的 ./package.json,難道又要一個個修改么?所以說,這樣制作基礎(chǔ)鏡像,只解決了原來的 Dockerfile 的前4條指令的變化問題,而后面三條指令的變化則完全沒辦法處理。
onBUILD 可以解決這個問題。讓我們用 onBUILD 重新寫一下基礎(chǔ)鏡像的 Dockerfile:
FROM node:slim
RUN mkdir /app
WORKDIR /app
onBUILD COPY ./package.json /app
onBUILD RUN [ "npm", "install" ]
onBUILD COPY . /app/
CMD [ "npm", "start" ]
這次我們回到原始的 Dockerfile,但是這次將項目相關(guān)的指令加上 ONBUILD,這樣在構(gòu)建基礎(chǔ)鏡像的時候,這三行并不會被執(zhí)行。然后各個項目的 Dockerfile 就變成了簡單地:
FROM my-node
當(dāng)在各個項目目錄中,用這個只有一行的 Dockerfile 構(gòu)建鏡像時,之前基礎(chǔ)鏡像的那三行 onBUILD 就會開始執(zhí)行,成功的將當(dāng)前項目的代碼復(fù)制進(jìn)鏡像、并且針對本項目執(zhí)行 npm install,生成應(yīng)用鏡像。








