- 原文地址:An Exhaustive Guide to Writing Dockerfiles for Node.js Web Apps
- 原文做者:Praveen Durairaj
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:lsvih
- 校對者:Raoul1996, song-han
本文涵蓋了從建立簡單的 Dockerfile 到生產環境多級構建 Node.js Web 應用的例子。如下爲本指南的內容摘要:前端
nodemon
進行熱加載。npm install
。serve
包部署靜態文件(好比 React、Vue、Angular 生成的 bundle)。alpine
進行生產環境下的多級構建,減小最終鏡像文件的大小。init
標識,處理 CTRL-C 等內核信號。若是你須要以上步驟的代碼,請參考 GitHub repo。vue
讓咱們先假設一個名爲 node-app 的應用,一個簡單的目錄結構。在頂級目錄下,包含 Dockerfile
以及 package.json
,node app 的代碼將存於 src
目錄下。爲了簡潔起見,咱們假設 server.js 定義了一個運行於 8080 端口的 node express 服務。node
node-app
├── Dockerfile
├── package.json
└── src
└── server.js
複製代碼
FROM node:carbon
# 建立 app 目錄
WORKDIR /app
# 安裝 app 依賴
# 使用通配符確保 package.json 與 package-lock.json 複製到須要的地方。(npm 版本 5 以上) COPY package*.json ./
RUN npm install
# 若是你須要構建生產環境下的代碼,請使用:
# RUN npm install --only=production
# 打包 app 源碼
COPY src /app
EXPOSE 8080
CMD [ "node", "server.js" ]
複製代碼
咱們將使用最新的 LTS 版本 node:carbon
做爲基礎鏡像。react
在構建鏡像時,docker 會獲取全部位於 context
目錄下的文件。爲了增長 docker 構建的速度,能夠在 context 目錄中添加 .dockerignore
文件來排除不須要的文件與目錄。android
一般,你的 .dockerignore
文件件應該以下所示:ios
.git
node_modules
npm-debug
複製代碼
構建並運行此鏡像:nginx
$ cd node-docker
$ docker build -t node-docker-dev .
$ docker run --rm -it -p 8080:8080 node-docker-dev
複製代碼
你將能在 [http://localhost:8080](http://localhost:8080.)
訪問此 app。使用 Ctrl+C
組合鍵能夠退出程序。git
如今,假設你但願在每次修改代碼(好比在本地部署時)時都運行以上代碼,那麼你須要在啓停 node 服務時將代碼源文件掛載到容器中。github
$ docker run --rm -it -p 8080:8080 -v $(pwd):/app \
node-docker-dev bash
root@id:/app# node src/server.js
複製代碼
nodemon 是一款很受歡迎的包,它在運行時會監視目錄中的文件,當任何文件發生了改變時,nodemon 將會自動重啓你的 node 應用。web
FROM node:carbon
# 建立 app 目錄
WORKDIR /app
# 安裝 nodemon 以實現熱更新
RUN npm install -g nodemon
# 安裝 app 依賴
# 使用通配符確保 package.json 與 package-lock.json 複製到須要的地方。(npm 版本 5 以上)COPY package*.json ./
RUN npm install
# 打包 app 源碼
COPY src /app
EXPOSE 8080
CMD [ "nodemon", "server.js" ]
複製代碼
咱們將構建鏡像並運行 nodemon,以便在 app
目錄下文件發生變更時對代碼進行 rebuild。
$ cd node-docker
$ docker build -t node-hot-reload-docker .
$ docker run --rm -it -p 8080:8080 -v $(pwd):/app \
node-hot-reload-docker bash
root@id:/app# nodemon src/server.js
複製代碼
一切在 app
目錄下的更改都會觸發 rebuild,發生的變化都能在 [http://localhost:8080](http://localhost:8080.)
上實時展現。請注意,咱們已經將文件掛載到了容器中,所以 nodemon 才能正常工做。
在你的 Dockerfile 中,除非你須要自動解壓 tar 文件(參考 Docker 最佳實踐),不然最好使用 COPY 來代替 ADD。
繞過 package.json
的 start
命令,而是直接將 app 「燒錄」至鏡像文件中。所以在 Dockerfile CMD 中不要使用:
$ CMD ["npm","start"]
複製代碼
而應當使用:
$ CMD ["node","server.js"]
複製代碼
來代替。這樣能夠減小在容器中運行的進程數量,同時還能讓 Node.js 進程接收到 SIGTERM
與 SIGINT
等退出信號,如如果 npm 進程則會無視這些信號(參考 Node.js Docker 最佳實踐)。
你還可使用 --init
標誌,用 tini 輕量集初始化系統來包裝你的 Node.js 進程,它們也能響應一些 SIGTERM
(CTRL-C
)之類的內核信號。例如,你可使用:
$ docker run --rm -it --init -p 8080:8080 -v $(pwd):/app \
node-docker-dev bash
複製代碼
前文的 Dockerfile 是假設你運行了由 Node.js 構建的 API 服務。那麼下面說說若是你想要用 Node.js 部署 React.js、Vue.js、Angular.js 應用時該怎麼作。
FROM node:carbon
# 建立 app 目錄
WORKDIR /app
# 安裝 app 依賴
RUN npm -g install serve
# 使用通配符複製 package.json 與 package-lock.json
COPY package*.json ./
RUN npm install
# 打包 app 源碼
COPY src /app
# 將 react、vue、angular 打包構建成靜態文件
RUN npm run build
EXPOSE 8080
# 將 dist 目錄部署於 8080 端口
CMD ["serve", "-s", "dist", "-p", "8080"]
複製代碼
如你所見,當你須要構建 React、Vue、Angular 製做的 UI app 時,使用 npm run build
來壓縮 JS 與 CSS 文件,生成最終的 bundle
包,在這兒咱們使用了 npm 的 [serve](https://www.npmjs.com/package/serve)
包來部署靜態文件。
此外,可使用一些替代方案:1) 在本地構建打包文件,而後使用 nginx docker 來部署這些靜態文件。2) 使用 CI/CD 工做流進行構建。
FROM node:carbon
# 建立 app 目錄
WORKDIR /app
# 安裝 app 依賴
# RUN npm -g install serve
# 使用通配符複製 package.json 與 package-lock.json
COPY package*.json ./
RUN npm install
# 打包 app 源碼
COPY src /app
# 如需對 react/vue/angular 打包,生成靜態文件,使用:
# RUN npm run build
EXPOSE 8080
# 如需部署靜態文件,使用:
#CMD ["serve", "-s", "dist", "-p", "8080"]
CMD [ "node", "server.js" ]
複製代碼
構建並運行這個一體化鏡像:
$ cd node-docker
$ docker build -t node-docker-prod .
$ docker run --rm -it -p 8080:8080 node-docker-prod
複製代碼
因爲底層爲 Debian,構建完成後鏡像約爲 700MB(具體數值取決於你的源碼)。下面探討如何減少這個文件的大小。
使用多級構建時,將在 Dockerfile 中使用多個 FROM
語句,但最後僅會使用最終階段構建的文件。這樣,獲得的鏡像將僅包含生產服務器中所需的依賴,理想狀況下文件將很是小。
# ---- Base Node ----
FROM node:carbon AS base
# 建立 app 目錄
WORKDIR /app
# ---- Dependencies ----
FROM base AS dependencies
# 使用通配符複製 package.json 與 package-lock.json
COPY package*.json ./
# 安裝在‘devDependencies’中包含的依賴
RUN npm install
# ---- Copy Files/Build ----
FROM dependencies AS build
WORKDIR /app
COPY src /app
# 如需對 react/vue/angular 打包,生成靜態文件,使用:
# RUN npm run build
# --- Release with Alpine ----
FROM node:8.9-alpine AS release
# 建立 app 目錄
WORKDIR /app
# 可選命令:
# RUN npm -g install serve
COPY --from=dependencies /app/package.json ./
# 安裝 app 依賴
RUN npm install --only=production
COPY --from=build /app ./
#CMD ["serve", "-s", "dist", "-p", "8080"]
CMD ["node", "server.js"]
複製代碼
使用上面的方法,用 Alpine 構建的鏡像文件大小約 70MB,比以前少了 10 倍。使用 alpine
版本進行構建能有效減少鏡像的大小。
若是你對前面的方法有任何建議,或但願看到別的用例,請告知做者。
加入 Reddit / HackerNews 討論:)
此外,你是否試過將 Node.js web 應用部署在 Hasura 上呢?這實際上是將 Node.js 應用部署於 HTTPS 域名的最快的方法(僅需使用 git push)。嘗試使用 hasura.io/hub/nodejs-… 的模板快速入門吧!Hasura 中全部的項目模板都帶有 Dockerfile 與 Kubernetes 標準文件,你能夠自由進行定義。
感謝 Tanmai Gopal
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。