默認的 docker 鏡像使用 Linux 來當作基礎鏡像
01. 使用 alpine 鏡像,而不是默認的 linux 鏡像
PS: alpine 譯為高山植物,就是很少的資源就能存活的意思。alpine 裁剪了很多不必要的 linux 功能,使得鏡像體積大幅減小了。
- 比如 FROM node:18 可改為 FROM node:18-alpine3.14
Dockerfile 會給每一行都增加緩存,所以盡可能的復用緩存可以提高速度,另外就是源碼和很多構建的依賴是不需要的,但是現在都保存在了鏡像里。比如 Vue 項目實際上我們只需要構建出來的 ./dist 目錄下的文件還有運行時的依賴。
02. 使用多階段構建
- 例子
FROM node:18-alpine3.14 as build-stageWORKDIR /appCOPY package.json .RUN npm installCOPY . .RUN npm run build#production stage
FROM node:18-alpine3.14 as production-stageCOPY --from=build-stage /app/dist /app
COPY --from=build-stage /app/package.json /app/package.jsonWORKDIR /appRUN npm install --productionEXPOSE 3000CMD ["node", "/app/main.js"]
FROM 后面添加一個 as 來指定當前構建階段的名字。
通過 COPY --from=xxx 可以從上個階段復制文件過來。
然后 npm install 的時候添加 --production,這樣只會安裝 dependencies 的依賴。
docker build 之后,只會留下最后一個階段的鏡像。
也就是說,最終構建出來的鏡像里是沒有源碼的,有的只是 dist 的文件和運行時依賴。
這樣鏡像就會小很多。
03. 使用 ARG 增加構建靈活性
- 例子
FROM node:18-alpine3.14ARG aaa
ARG bbbWORKDIR /appCOPY ./test.js .ENV aaa=${aaa} \bbb=${bbb}CMD ["node", "/app/test.js"]
使用 ARG 聲明構建參數,使用 ${xxx} 來取
然后用 ENV 聲明環境變量。
dockerfile 內換行使用 \
之后構建的時候傳入構建參數:
docker build --build-arg aaa=3 --build-arg bbb=4 -t arg-test -f 333.Dockerfile .
通過 --build-arg xxx=yyy 傳入 ARG 參數的值。
04. CMD 結合 ENTRYPOINT
前面的 CMD 其實可以換成 ENTRYPOINT。
這兩種寫法有什么區別么?
- 用 CMD 的時候,啟動命令是可以重寫的
- ENTRYPOINT 不會也不能重寫命令
05. COPY vs ADD
這倆都可以把宿主機的文件復制到容器內。但有一點區別,就是對于 tar.gz 這種壓縮文件的處理上:
ADD、COPY 都可以用于把目錄下的文件復制到容器內的目錄下。但是 ADD 還可以解壓 tar.gz 文件。
一般情況下,還是用 COPY 居多。
總結下來
Dockerfile 有挺多技巧:
- 使用 alpine 的鏡像,而不是默認的 linux 鏡像,可以極大減小鏡像體積,比如 node:18-alpine3.14 這種
- 使用多階段構建,比如一個階段來執行 build,一個階段把文件復制過去,跑起服務來,最后只保留最后一個階段的鏡像。這樣使鏡像內只保留運行需要的文件以及 dependencies。
- 使用 ARG 增加構建靈活性,ARG 可以在 docker build 時通過 --build-arg xxx=yyy 傳入,在 dockerfile 中生效,可以使構建過程更靈活。如果是想定義運行時可以訪問的變量,可以通過 ENV 定義環境變量,值使用 ARG 傳入。
- CMD 和 ENTRYPOINT 都可以指定容器跑起來之后運行的命令,CMD 可以被覆蓋,而 ENTRYPOINT 不可以,兩者結合使用可以實現參數默認值的功能。
- ADD 和 COPY 都可以復制文件到容器內,但是 ADD 處理 tar.gz 的時候,還會做一下解壓。
ADD方法會解壓壓縮包,但是注意太大的文件不要使用ADD方法。docker build的過程會加載到內存里面去。太大的文件使用ADD存在內存問題。
alpine 鏡像有部分一些鏈接文件缺失的。比如golang打包,alpine 鏡像中可能會缺少一些C語言的依賴文件。這個時候可以通過COPY復制到容器內。也可以FROM別人制作好的鏡像操作。