1. 程式人生 > >【086】部署nodejs程式時,如何把自己用到的npm模組封裝成Docker映象,方便在離線的時候使用?

【086】部署nodejs程式時,如何把自己用到的npm模組封裝成Docker映象,方便在離線的時候使用?

使用場景

在本文開頭,說一下碰到的使用場景。編寫好nodejs程式後,就要封裝成Docker映象。在編譯Dockerfile的時候,系統會從npm的模組倉庫中下載用到的模組。這會碰到兩個問題:

第一,大多數情況下,我們更新程式,只是改了原始碼,沒有修改package.json中的模組配置。每次編譯映象的時候都要從網路上下載模組浪費時間。

第二,生產環境與外網隔離;或者網路環境不穩定。

我圍繞著這兩個問題給出瞭解決方法,並在本文裡寫出了一個例子。

解決方法

首先我們要建立一個nodejs-base映象,用來儲存我們需要用到的npm模組放到這個docker映象裡面。

建立一個node-js專案,因為這個專案主要為了下載npm模組,所以沒什麼程式,結構簡單,如下所示:

nodejs-base
  │
  ├─Dockerfile
  ├─main.js
  └─package.json

Dockerfile

FROM node:8-onbuild

# set timezone as china/shanghai
RUN cp /usr/share/zoneinfo/PRC /etc/localtime

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
#COPY package.json /usr/src/app/

# copy app source
COPY . /usr/src/app RUN npm install CMD ["node","/usr/src/app/main.js"]

main.js

console.log("main")

package.json 把所有專案中用到的模組都寫到這個檔案裡面。為了避免模組自動更新導致出現錯誤,使用了確定版本的寫法。

{
  "name": "train-outline",
  "version": "0.0.1",
  "description": "Learn node.js and express.",
  "main": "main.js",
  "author": "Zhang Chao"
, "license": "MIT", "dependencies": { "body-parser": "1.17.2", "cookie-parser": "1.4.3", "express": "4.15.3", "jade": "1.11.0", "multer": "1.3.0", "superagent": "3.5.2" } }

本地編譯執行正常後,把整個node-base資料夾(node_modules除外)上傳到 linux 伺服器上,通過cd命令進入linux裡面的node-base資料夾,輸入如下命令編譯映象:

docker build -t zhangchao/nodejs-base:v1 .

然後我寫一個應用的例子來試一下。

nodejs-base
  │
  ├─.npmrc
  ├─Dockerfile
  ├─package.json
  ├─server.js
  ├─test.jade
  └─yarn.lock

.npmrc

sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
electron_mirror=https://npm.taobao.org/mirrors/electron/
registry=https://registry.npm.taobao.org

Dockerfile

FROM zhangchao/nodejs-base:v1

WORKDIR /usr/src/app

# copy app source
COPY . /usr/src/app

EXPOSE 18091
CMD ["node","/usr/src/app/server.js"]

package.json

{
  "name": "train-outline",
  "version": "0.0.1",
  "description": "Learn node.js and express.",
  "main": "main.js",
  "author": "Zhang Chao",
  "license": "MIT",
  "dependencies": {
    "body-parser": "1.17.2",
    "cookie-parser": "1.4.3",
    "express": "4.15.3",
    "jade": "1.11.0",
    "multer": "1.3.0",
    "superagent": "3.5.2"
  }
}

server.js

// var express = require('express');
// var http = require('http');
// var app = express();
// app.set('view engine', 'jade'); // 設定模板引擎
// app.set('views', __dirname);  // 設定模板相對路徑(相對當前目錄)

// app.get('/', function(req, res) {
//     res.render('test'); // 呼叫當前路徑下的 test.jade 模板
// })

// var server = http.createServer(app);
// server.listen(3002);


//----------------------------------
var super_request = require('superagent');
var express = require('express');
var app = express();

app.set('view engine', 'jade'); // 設定模板引擎
app.set('views', __dirname);  // 設定模板相對路徑(相對當前目錄)

app.use(express.static('public'));// 靜態檔案


// begin 
app.get('/', function (req, res) {
    var md = "";

    md = "Hello world !!!"
    res.render('test',{
        s:'hello world!',
        md:md
    });

})



var server = app.listen(18091, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("應用例項,訪問地址為 http://%s:%s", host, port)

})

test.jade

doctype html
html
    head
        meta(charset="utf-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0")
        title #{s}
    body
        div #{md}

編寫好了之後,專案除去node_modules資料夾,上傳到Linux伺服器,用cd命令進入專案資料夾,執行下面的命令:

docker build -t zhangchao/app:v1 .

docker run --name app -p 18091:18091 --restart=always -d zhangchao/app:v1

這樣,當只改原始碼不改package.json時候,只要重新編譯 app 這個映象就可以了。只有在需要更新package.json的時候才需要重新編譯 nodejs-base映象。
如果生產環境要求和外網隔離,先找一臺能連線外網的機器編譯 nodejs-base 映象,然後安裝到生產環境即可。

這種部署方式比較適合需要經常更新的產品或者專案。