# 十四.进行服务运维
前言
通常来说,项目构建完成之后,就成为待发布的版本,因此版本管理需要考虑,甚至做成自动化的,然后,最新的代码需要部署到线上机器才能让所有用户访问到,部署环节涉及到服务的启动、重启、日志管理等需要考虑。
下面我们介绍 npm script 在服务运维时的几个用途:
# 1. 版本管理
每次构建完的代码都应该有新的版本号,修改版本号直接使用 npm 内置的 version 自命令即可,如果是简单粗暴的版本管理,可以在 package.json 中添加如下 scripts:
"release:patch": "npm version patch && git push && git push --tags",
"release:minor": "npm version minor && git push && git push --tags",
"release:major": "npm version major && git push && git push --tags",
"precommit": "lint-staged",
2
3
4
这 3 条命令遵循 semver (opens new window) 的版本号规范来方便你管理版本,patch 是更新补丁版本,minor 是更新小版本,major 是更新大版本。在必要的时候,可以通过运行 npm run version:patch 来升补丁版本,运行输出如下:
如果要求所有的版本号不超过 10,即 0.0.9 的下个版本是 0.1.0 而不是 0.0.10,可以编写简单的 shell 脚本来实现(注意这样会破坏 semver 的约定),具体步骤如下:
首先,在 scripts 目录下新增 bump.sh(别忘了文件的可执行权限:chmod a+x scripts/bump.sh):
#!/usr/bin/env bash
# get major/minor/patch version to change
version=`cat package.json| grep version | grep -v release | awk -F\" '{print $4}'`
components=($(echo $version | tr '.' '\n'))
major=${components[0]}
minor=${components[1]}
patch=${components[2]}
release='patch';
# decide which version to increment
if [ $patch -ge 9 ]; then
if [ $minor -ge 9 ]; then
release='major'
else
release='minor'
fi
else
release='patch'
fi
echo "major=$major, minor=$minor, patch=$patch, release=$release"
# upgrade version
npm run release:$release
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
然后,在 package.json 中新增 bump 子命令:
"release:major": "npm version major && git push && git push --tags",
"bump": "scripty",
"precommit": "lint-staged",
2
3
在必要的时候执行 npm run bump,输出示例如下:
# 2. 服务进程和日志管理
在生产环境的服务进程和日志管理领域,pm2 (opens new window) 是当之无愧的首选,功能很强大,使用简单,开发环境常用的是 nodemon (opens new window)。
在我们的项目中使用 npm script 进行服务进程和日志管理的基本步骤如下:
# 1. 准备 http 服务
在使用 npm script 作为构建流水线的基础上,我们在项目中引入了 express (opens new window) 和 morgan (opens new window),并使用如下脚本启动 http 服务器方便用户访问我们的网页(morgan 使用来记录用户的访问日志的):
先安装依赖:
npm i express morgan -D
# npm install express morgan --save-dev
# yarn add express morgan -D
2
3
然后在根目录下创建文件 server.js,内容如下:
const express = require('express');
const morgan = require('morgan');
const app = express();
const port = process.env.PORT || 8080;
app.use(express.static('./dist'));
app.use(morgan('combined'));
app.listen(port, err => {
if (err) {
console.error('server start error', err); // eslint-disable-line
process.exit(1);
}
console.log(`server started at port ${port}`); // eslint-disable-line
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 2. 准备日志目录
为简单起见,我们项目中创建日志存储目录 logs,有些公司可能不会把日志存在项目部署目录下:
mkdir logs
touch logs/.gitkeep
git add logs/.gitkeep
git commit -m 'add logs folder'
2
3
4
并且设置该目录为 git 忽略的,再改动 .gitignore:
dist
logs
2
TIP#21:这里加 logs/.gitkeep 空文件的目的是为了能把 logs 目录提交到 git 里面,但是我们故意忽略 logs 目录里面的内容,这是在 git 中提交目录结构而忽略其中内容的常见做法。
# 3. 安装和配置 pm2
安装 pm2 作为依赖:
npm i pm2 -D
# npm install pm2 --save-dev
# yarn add pm2 -D
2
3
然后添加服务启动配置到项目根目录下 pm2.json,更多配置项可以参照文档 (opens new window):
{
"apps": [
{
"name": "npm-script-workflow",
"script": "./server.js",
"out_file": "./logs/stdout.log",
"error_file": "./logs/stderr.log",
"log_date_format": "YYYY-MM-DD HH:mm:ss",
"instances": 0,
"exec_mode": "cluster",
"max_memory_restart": "800M",
"merge_logs": true,
"env": {
"NODE_ENV": "production",
"PORT": 8080
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
上面的配置指定了服务脚本为 server.js,日志输出文件路径,日志时间格式,进程数量 = CPU 核数,启动方式为 cluster,以及两个环境变量。
# 4. 配置服务部署命令
在没有集成 CI 服务之前,我们的部署命令应该是下面这样的:
"release:major": "npm version major && git push && git push --tags",
+ "predeploy": "yarn && npm run build",
+ "deploy": "pm2 restart pm2.json",
"bump": "scripty",
2
3
4
即在部署前需要安装最新的依赖,重新构建,然后使用 pm2 重新启动服务即可,如果你有多台机器跑通 1 个服务,建议有个集中的 CI 服务器专门负责构建,而部署时就不需要运行 build 了。
每次需要部署服务时只需要运行 npm run deploy 就行了,运行成功输出如下:
# 5. 配置日志查看命令
至于日志,虽然 pm2 提供了内置的 logs 管理命令,如果某台服务器上启动了多个不同的服务进程,那么 pm2 logs 会展示所有服务的日志,个人建议使用如下命令查看当前服务的日志:
+ "logs": "tail -f logs/*",
"bump": "scripty",
2
需要查看日志时,直接运行 npm run logs,运行输入如下:
当然如果你有更复杂的日志查看需求,直接用 cat、grep 之类的命令好了。
← 十三.构建流水线