使用场景
在本文开头,说一下碰到的使用场景。编写好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 镜像,然后安装到生产环境即可。
这种部署方式比较适合需要经常更新的产品或者项目。