Key Results

docker image 縮小約一半的空間,

情境

過去對於 docker file 並沒有花太多時間深入了解,而且產生的 output 也沒發現太多問題,因此也錯過了學習的機會。直到有一天,在捷運的路上,看到一篇 twitter 在介紹 node.js docker file best practices,於是開始認真檢視先前在專案中的 docker file 的內容。

這一篇主要是將重點以條列方式凸顯,內容包含了一個簡單的例子。同時在文章結尾處附上一些不錯的文章提供大家參考,有興趣的人可以動手做一遍,即可產生一份有品質的 docker file。

FROM node:14.17.0-alpine

RUN apk --update --no-cache add python build-base

WORKDIR /usr/src/app
COPY .npmrc package*.json ./
RUN npm install --only=production
COPY . .
EXPOSE 4001
CMD ["npm", "start"]

這一份簡單的 docker file 暴露了幾個問題:

它沒有採用 multi-stage builds,因此在 node build 的過程中產生了很多不必要的檔案,既浪費了空間,影響到執行 container 的速度,額外不必要的程式存在 image 中,更是增加了暴露安全性漏洞的機會。

安全性方面,在執行此程式時,採用 root 的最大權限更是致命傷。比較理想的方式是限制檔案與授予足夠執行程式的權限即可。

最後,關於 node 有許多小細節也沒有注意到。關於這些細節,在官方的 best practices 都有提及,有興趣的人可以花時間了解。

解決方法

透過以下的方式不僅讓 docker image 縮小約一半的空間,同時也提升了安全性,避免賦予 root 的權限,同時在選擇 base image 時,可以了解其 vulnerability。

使用 multi-stage builds

安裝 production 所需套件即可

避免在 container 中賦予 root 權限

命令執行的順序影響是否可以重複利用 layer

先執行 run (package installation) 在執行 copy 可減少因為 source code 的修改而造成 layer 無法重複利用

RUN --mount=type=cache,target=/usr/src/app/.npm \\
  npm set cache /usr/src/app/.npm && \\
# "--omit=dev" not necessary since ENV NODE_ENV production is set
# We make it obvious here
  npm ci --omit=dev
COPY . .

Node 相關