點燈坊

學而時習之,不亦悅乎

如何將 Node 打包成 Docker Image ?

Sam Xiao's Avatar 2019-08-11

Node 本身已提供 HTTP 服務,可用來開發 API,可自行擴充 Yarn Script,最後只要下 yarn docker 就可一鍵建立 Docker Image。

Version

macOS Mojave 10.14.5
WebStorm 2019.2
Node 12.8
Express 4.17.1

Node Project

在根目錄下新增以下檔案:

  • dockerfile
  • app.js
  • package.json
  • docker-compose.yml

express000

dockerfile

FROM node:alpine
WORKDIR /usr/src/app
COPY package.json ./package.json
RUN yarn install
COPY app.js .
CMD [ "node", "app.js" ]

須先建立 dockerfile,才能產生 image。

第 1 行

FROM node:alpine

使用最新版 nginx:alpine 為基底建立 image。

建議使用 node:alpine 為 production image,size 會小很多,以 Node 12.7 為例,node:latest 為 907 MB,node:alpine 為 79.3 MB

第 2 行

WORKDIR /usr/src/app

設定 image 內的 /usr/src/app 為工作目錄。

第 3 行

COPY package.json ./package.json

package.json 複製進 image。

第 4 行

RUN yarn install

根據 image 內的 package.json 執行 yarn install 安裝 Node 所需的 Express。

第 5 行

COPY app.js .

app.js 複製進 image。

第 6 行

CMD [ "node", "app.js" ]

最後將使用 Node 執行 app.js 啟動 Express。

app.js

let express = require('express');

let app = express();

app.get('/api/hello-world', (req, res) => res.send('Hello World'));

app.listen(3000, () => console.log('app listening on port 3000!'));

Node 的啟動檔,由此啟動 Express。

第 1 行

let express = require('express');

Import express module。

第 3 行

let app = express();

建立 app Express instance。

第 5 行

app.get('/api/hello-world', (req, res) => res.send('Hello World'));

建立 /api/hello-world GET,回傳 Hello World

第 7 行

app.listen(3000, () => console.log('app listening on port 3000!'));

啟動 Express 在 3000 port。

package.json

{
  "name": "express-get",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "express": "^4.17.1"
  },
  "scripts": {
    "docker": "docker build -t oomusou/node-express:0.0.1 ."
  }
}

設定 Node 所需的 dependency 的 package.json

第 5 行

"dependencies": {
  "express": "^4.17.1"
},

安裝 express package。

第 9 行

"docker": "docker build -t oomusou/node-express:0.0.1 ."

新增 Yarn script,只要執行 yarn docker 就會執行 docker build 建立 Docker image。

  • -t:加上 tag,其中 : 左側為 image 名稱,右側為版號;/ 左側為 Docker ID,右側為 image 名稱

docker-compose.yml

version: "3"
services:
  express:
    image: oomusou/node-express:0.0.1
    restart: always
    ports:
      - "3000:3000"

設定 express service:

  • image:使用剛建立的 oomusou/node-express:0.001 image
  • restart:當 container crash 時,會自動重啟
  • ports:container 內的 3000 port,對應到外部的 3000 port

Build Image

$ yarn docker

執行 docker build 產生 image。

express001

Start Container

$ docker-compose up -d

使用 docker-compose up 啟動 container。

express002

Postman

express003

使用 Postman 針對 http://localhost/api/hello-world GET 測試,可成功回傳 Hello World

Stop Container

$ docker-compose down

使用 docker-compose down 結束 container。

express004

Conclusion

  • 在 microservice 架構下,同一類型的 API 會包成單獨 service,甚至連前端也會包成獨立 service

Sample Code

完整範例可在我的 GitHub 上找到