Freetao's Blog

Node.js 项目持续集成实践

前端开发流程( 语法检查、编译、重载)的自动化我们在工作中已经用得比较溜了,这篇文章主要介绍 Node.js 应用部署到服务端过程(编译、测试)的自动化。

这里以开源的 API Mock 系统 AMP 的部署为例( https://iffe.leanapp.cn ),通过这套系统提供的 mock 服务,前端可以在接口定义完毕后就着手开发,与后端接口开发并行以提升项目整体效率。接口支持 CORS 跨域访问、支持 HTTPS 访问,为前端开发,尤其是移动端开发带来便利。

实现的效果

本地开发代码,提交到 gitlab 的 master 分支后自动测试和编译,并将编译结果提交到可部署生产的 built 分支,需要的时候一键发布生产。

实现细节

这里用到 gitlab.com 提供的私有代码托管和 git-ci 服务,以及 leancloud 的云引擎。gitlab.com 提供的服务可以使用自己搭建的 gitlab 替换。提供与 leancloud 类似云引擎功能的网站,市面上也不少,这里因为其免费策略合理所以采用,拿它们举例适用性较广。

首先我们要在项目根目录添加 gitlab-ci.yml 文件,用于描述持续集成的过程,分三个阶段:

测试

只需要执行 Node.js 应用的测试命令: npm test

1
2
3
test:
script:
- npm test

构建

执行 Node.js 应用的构建命令: npm run build

1
2
3
build:
script:
- npm run build

部署

1
2
3
4
deploy:
stage: deploy
script:
- . deploy.sh # 为了方便脚本执行上下文控制,我们将命令写到 deploy.sh 中

deploy.sh 脚本完成两件事:

  1. 执行编译命令
  2. push 编译代码到 built 分支

完整配置如下:

1
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
27
28
29
30
31
32
33
34
35
36
# .gitlab-ci.yml
image: node:6
# 缓存安装后的 node_modules ,以加速下次构建
cache:
paths:
- node_modules/
before_script:
- npm i -D # 所有任务执行前都会执行该脚本,用于安装所有依赖包
# 添加 ‘build' 任务,描述构建任务的执行
build:
stage: build # 定义所属阶段
script:
- npm run build # 需要运行的脚本
only:
- build # 'build' 任务仅影响 'build' 分支
# 添加 'test' 任务, 描述测试任务的执行
test:
stage: test # 定义所属阶段
script:
- npm run test # 需要运行的脚本
except:
- master # 'test' 任务影响除 'master' 分支之外的所有分支
# 添加 'deploy' 任务, 完成构建和部署
deploy:
stage: deploy
script:
- . deploy.sh # 需要运行的脚本
only:
- master # 'deploy' 任务仅影响 'master' 分支

由于测试任务由除 master 之外的分支的 push 触发,而部署任务完成后,将编译结果 push 到 built 分支。所以我们 push 到 master 后,会先执行部署任务,部署任务完成后,执行测试任务(如下图)

push 操作触发部署、测试任务

任务执行结果:

执行结果

有了构建好的代码,就可以部署到 leancloud 了,部署前我们需要告诉 leancloud 代码库地址,并将 deploy key 信息保存到 gitlab 的项目配置中。这样以后 leancloud 就可以凭 deploy key 向 gitlab 库拉取代码。

在 leancloud 上的“常规设置“中填写代码库地址,并获取 `deploy key`

在 gitlab 上项目的“Deploy Keys“中填写上一步获取的 `deploy key`

两边信息配置完毕,就可以开始部署,在“部署”面版填写“分支或版本号“为 built 即可。

在 leancloud 云引擎中选择 built 分支部署

如果一切顺利,部署成功后就可以访问应用了。

部署完成访问应用

(请注意:演示系统虽然功能 ok,但是运行环境为 leancloud 免费版云引擎,配额受限,请 不要 在实际项目中使用, 请使用大师在内网环境部署的。)

解决工作中场景中哪些痛点

  1. 无缝版本切换,实现“为跑道上飞驰的赛车更换零件”——在 leancloud 部署应用到生产环境的过程中发现一个有意思的细节,就是新版本构建出问题并不影响线上服务。大致过程类似于在一台新服务器上运行好版本代码,然后把流量从上运行上一版本代码的服务器切过来,在此之前会检测配置的端口是否正常相应请求,如果不是就终止切换,并提示发版失败,发版成功则把“旧版服务器”做存档,以供后续版本回退。有了这一机制,发版本就可以选择最适合业务的时机,而不是非要等到用户量最低的时候,“他好我也好” 😝

  2. 提前暴露编译配置的问题,实际项目中更改生产构建配置,往往改完当时验证没问题后就不太会留意,而等到真正发版前的一段时间项目文件变动可能产生预料外的问题,这时发现再解决就占用了本已紧张的发版时间,而且需要定位产生问题的代码,这问题在多人协作以及长周期的版本尤其突出。而引入持续集成后,每次 push 将会触发测试环节,在这里加上构建测试,通过测试结果即可及时发现问题并处理。

  3. 提升开发体验,将一部分消耗资源、重复的、机械性的任务如全量编译,交由持续集成服务器完成,以节约开发机资源,让开发者专注于开发而不受打断。能有空伸个懒腰,发发呆不再是奢求。

思考

探索“云计算”、”微服务”这些新热技术在前端开发领域的应用场景,对理解“小而美”产品(快速迭代、小步快跑的同时保持新集成特性的稳定输出)存在的基础(支撑点),有推导和借鉴意义。

短期内切换应用部署方案显然并不现实,但这并不构成拒绝拥抱变化的充分条件,毕竟技术的发展不因主观意愿而转移,而去中心化和原子化(把功能和服务内聚为模块)显然是日益突显的两个特征。实际上下半年组内在一些项目中切换 git 做版本管理,并将暴露的问题解决得七七八八已是一个不错的开端。


“ 我觉得套路和扯皮救不了中(cheng)国(xu)人(yuan),但技术储备可以 ”

我没说过这句话——鲁迅