前言
基本上docker 會在我們建立image的時候, 自動cache每一層layer, 當下次執行 docker build的時後, docker 會去找cache來用, 縮短建image的時間以Node.js的程式來說, 通常會有一層layer用來執行npm install, 隨著dependency module越來越多, 作完npm install的時間也越來越久, 若少了cache機制, 等於是每次建image都重跑npm install
但並不是所有情況docker 都會去使用cache, 下面的範例就是這種情況, 每當資料夾內檔案有任何變化時(包含新增, 修改, 刪除), npm install都會重跑一遍
FROM node
ADD . /app
WORKDIR /app
RUN npm install
Root Cause
最主要的原因是, docker build會照順序執行Dockerfile裡的指令, 而在執行的過程中會去看一下cache可不可用(ADD, COPY會去檢查檔案有沒有變, 有變cache就會變成無效的狀態), 如果執行到某一層指令發現cache不能用, 從那層之後接下來的指令也就不會去用cache了因為 ADD . /app 發現檔案變了所以接下來的指令都不會去用cache
WORKDIR /app
RUN npm install
若想要完美的使用到cache, Dockerfile可以改成如下
FROM node
ADD package.json /app/
WORKDIR /app
RUN npm install
ADD . /app
把會常變動的layer移到npm install之後
Step 2.
在npm install之前建立一層layer把不常動的package.json複製進來(npm install 需要package.json)
這樣作的話就能保證在執行RUN npm install之前cache都是有效的狀態
Gitlab
由於CI的環境不一定會有cache可以用, 但我們可以把前一版image拉下來, 然後在docker build的指令裡加上--cache-from的參數, 告訴docker可以去指定的image找cache
docker build --cache-from myregistry/node:latest
.gitlab-ci.yml 可以這樣寫
stages:
- build
docker-build:
stage: build
script:
- docker pull $MY_CACHE_IMAGE:latest || true
- docker build --cache-from $MY_CACHE_IMAGE:latest --tag $MY_CACHE_IMAGE:latest .
- docker login -u $REGISTRY_USER -p $REGISTRY_PASS
- docker push $MY_CACHE_IMAGE:latest
Ref:
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
https://andrewlock.net/caching-docker-layers-on-serverless-build-hosts-with-multi-stage-builds---target,-and---cache-from/
https://testdriven.io/blog/faster-ci-builds-with-docker-cache/
https://blog.callr.tech/building-docker-images-with-gitlab-ci-best-practices/
https://www.aptible.com/documentation/deploy/tutorials/faq/dockerfile-caching/npm-dockerfile-caching.html
留言
張貼留言