在使用Docker部署PHP或者node.js應用時,經常使用的方法是將代碼和環境鏡像打包成一個鏡像而後運行,一些雲廠商提供了很是便捷的操做,只須要把咱們的代碼提交到VCS上,而後它們就會幫咱們拉取代碼並根據代碼包內的Dockerfile構建咱們的鏡像而後部署到集羣裏。node
PHP和node.js都有很是不錯的生態,有各類各樣的包,可是一旦引入的包多了咱們的項目內的文件就會變得很是多,因此在使用VCS協做的時候咱們都會忽略掉依賴包目錄(node_modules / vendor)。可是咱們忽略了包目錄後在構建鏡像的時候就要使用composer或者npm把包從新裝回去,因此Dockerfile大概長這樣docker
FROM node COPY . /src RUN cd /src && npm install
這樣看起來沒什麼問題,可是若是包一旦多起來安裝的時候須要花費很長的時間,修復緊急bug的狀況下等待的時間就是煎熬,那咱們有沒有什麼辦法能讓這個過程更快一些呢?express
咱們知道Docker構建是分層的,一條指令一層,在沒有帶--no-cache=true
指令的狀況下若是某一層沒有改動,Docker就不會從新構建這一層而是會使用緩存,先來看看Docker官方文檔的描述npm
簡單來講就是若是第n層有改動,則n層之後的緩存都會失效,大多數狀況下判斷有無改動的方法是判斷這層的指令和緩存中的構建指令是否一致,可是對於COPY和ADD命令會計算鏡像內的文件和構建目錄文件的校驗和而後作比較來判斷本層是否有改動。json
最理想的狀況下,咱們但願package.json
或者composer.json
變更的時候會從新的安裝包,在沒有變更的狀況下使用緩存縮短構建時間。緩存
瞭解上面的規則後咱們再來看看上面那個Dockerfile,若是咱們不修改任何代碼的話第二次構建也是能使用緩存的,可是若是咱們修改了代碼,COPY . /src
這層的緩存就會失效,同時下一層的緩存也會失效。可是大多數狀況下,從新構建鏡像就意味着代碼有修改,可是package.json
和composer.json
這兩個文件並不會頻繁的修改,因此咱們須要把這兩個文件以及install的操做分離出來,因此有app
FROM node COPY package.json /src/package.json RUN cd /src && npm install COPY . /src
在package.json
裏面寫一個依賴包composer
{ "dependencies": { "express": "^4.16.4" } }
而後再寫一個index.js
ide
const app = require('express')(); app.listen(8080)
而後咱們進行第一次構建,看看docker history
的輸出ui
LIN2UR:~ lin2ur$ docker history demo IMAGE CREATED CREATED BY SIZE COMMENT 3c913c9e997b 6 seconds ago /bin/sh -c #(nop) COPY dir:e3c12f06720cf5f3b… 1.6MB 21373087419a 6 seconds ago /bin/sh -c cd /src && npm install 3MB 64896ee5240d 14 seconds ago /bin/sh -c #(nop) COPY file:87de28b86afd2c1c… 53B
把每一層的IMAGE ID和Dockerfile裏面的指令對應起來就是
64896ee5240d => COPY package.json /src/package.json
21373087419a => RUN cd /src && npm install
3c913c9e997b => COPY . /src
如今咱們來修改一下index.js
模擬咱們業務代碼變更而後再進行構建
LIN2UR:~ lin2ur$ docker history demo IMAGE CREATED CREATED BY SIZE COMMENT 5d697905ad0a 6 seconds ago /bin/sh -c #(nop) COPY dir:d698db67dac047bd2… 1.6MB 21373087419a 4 minutes ago /bin/sh -c cd /src && npm install 3MB 64896ee5240d 4 minutes ago /bin/sh -c #(nop) COPY file:87de28b86afd2c1c… 53B
能夠看到除了最上一層外其餘兩層的IMAGE ID是沒有變化的,再來看看docker build
命令的輸出
LIN2UR:~ lin2ur$ docker build --rm -f "Dockerfile" -t demo . Sending build context to Docker daemon 1.902MB Step 1/4 : FROM node ---> c63e58f0a7b2 Step 2/4 : COPY package.json /src/package.json ---> Using cache ---> 64896ee5240d Step 3/4 : RUN cd /src && npm install ---> Using cache ---> 21373087419a Step 4/4 : COPY . /src ---> 5d697905ad0a Successfully built 5d697905ad0a Successfully tagged demo:latest
能夠看到步驟2和3都使用了緩存,比第一次構建的時間縮短很多。如今咱們在package.json
裏面再加一個包模擬依賴包變更
LIN2UR:~ lin2ur$ docker history demo IMAGE CREATED CREATED BY SIZE COMMENT 020ce95b1987 29 seconds ago /bin/sh -c #(nop) COPY dir:ea4d7afd475895520… 1.6MB d9697dfc7022 31 seconds ago /bin/sh -c cd /src && npm install 3MB 71d8a2fb458a 38 seconds ago /bin/sh -c #(nop) COPY file:87bd25345a96e6b3… 51B
此次底下兩層的IMAGE ID都變了,意味着沒有使用緩存,再來看看docker build
命令的輸出
LIN2UR:~ lin2ur$ docker build --rm -f "Dockerfile" -t demo . Sending build context to Docker daemon 1.902MB Step 1/4 : FROM node ---> c63e58f0a7b2 Step 2/4 : COPY package.json /src/package.json ---> 71d8a2fb458a Step 3/4 : RUN cd /src && npm install ---> Running in ce424d6af936 Step 4/4 : COPY . /src ---> 020ce95b1987 Successfully built 020ce95b1987 Successfully tagged demo:latest
因爲第二層的package.json
改動致使這層及後續的緩存失效,而後從新安裝包,實現了咱們但願的結果。