上一节决定在Jenkins中采用Docker作为构建环境,于是就可以为所欲为的使用各种node版本编译我们的项目。解决了版本切换问题。然而,Docker设计的目的就是纯净的执行环境,因此每次运行docker容器都相当于一个新的系统,所以就不会有缓存。而npm install需要下载大量的依赖,我们总不能每次都去下载吧。而且,node-sass的下载速度总是让人以为卡死了。作为CI,每天即便达不到成千上万次构建也算很频繁了。
经调研google, 复制node_modules可以快速加载依赖,但可操作性太差,需要定制脚本。复用npm cache基本可以解决离线缓存,减少联网下载的次数。
创建volume通过如下方式可以在docker磁盘上创建一个磁盘卷npm_cache
sudo docker volume create npm_cache > sudo docker volume ls DRIVER VOLUME NAME local 0cf39840bd652ef744137b177537357b1ce18a1b55521e381524501996db2ea2 local npm_cache初始化是空的,位置在
> sudo docker volume inspect npm_cache [ { "CreatedAt": "2019-07-26T14:17:29+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/data/docker/volumes/npm_cache/_data", "Name": "npm_cache", "Options": {}, "Scope": "local" } ]使用volume, 这里通过-v指令在运行容器时挂载:
sudo docker run -d -v npm_cache:/root/.npm -v `pwd`:/tmp node上述命令的含义是:
运行node容器,挂载磁盘npm_cache到/root/.npm, 挂载当前项目路径到/tmp. 这样就可以在/tmp目录下构建本项目。
测试构建时间比如如下依赖,分别采用cache和不采用cache的构建时间比较
"dependencies": { "axios": "^0.19.0", "element-ui": "^2.11.0", "vue": "^2.6.10", "vue-router": "^3.0.7", "vuex": "^3.1.1" }, "devDependencies": { "babel-core": "^6.26.3", "node-sass": "^4.12.0" }不挂载.npm
added 220 packages from 163 contributors and audited 756 packages in 268.127s
found 0 vulnerabilities
挂载.npm并已有cache
added 220 packages from 163 contributors and audited 756 packages in 9.38s
found 0 vulnerabilities
同时,可以在本地磁盘看到缓存的依赖
root@ryan-computer:/data/docker/volumes/npm_cache/_data# tree -L 2 . ├── anonymous-cli-metrics.json ├── _cacache │ ├── content-v2 │ ├── index-v5 │ └── tmp ├── _locks └── node-sass └── 4.12.0 Jenkins中使用首先,安装Docker Pipeline Plugin.
使用Jenkinsfile构建流水线。
在Jenkinsfile中添加stage
stage('Build') { echo "2. Build" try { docker.image('node:12.6.0-buster').inside(" -v npm_cache:/home/node/.npm") { sh 'npm install --registry=https://registry.npm.taobao.org;' sh 'npm run test:ci --registry=https://registry.npm.taobao.org' } } catch (Exception ex) { updateGitlabCommitStatus name: 'build', state: 'failed' throw ex; } updateGitlabCommitStatus name: 'build', state: 'success' }上述脚本将会在node中构建我们的项目并执行test. 本质上,上述命令会转换为
docker run -t -d -u 1000:1000 -v npm_cache:/home/node/.npm -w /data/opt/jenkins/workspace/dbrest-web_master -v /data/opt/jenkins/workspace/dbrest-web_master:/data/opt/jenkins/workspace/dbrest-web_master:rw,z -v /data/opt/jenkins/workspace/dbrest-web_master@tmp:/data/opt/jenkins/workspace/dbrest-web_master@tmp:rw,z -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** node:12.6.0-buster cat因此,workspace下node项目就会被编译。如果不喜欢使用Jenkins docker插件,也可以直接使用docker命令。
复用cache前后的对比
使用cache后时间reduce是分钟级别的。
以下来自官方文档:
设计流水线的目的是更方便地使用 Docker镜像作为单个 Stage或整个流水线的执行环境。 这意味着用户可以定义流水线需要的工具,而无需手动配置代理。 实际上,只需对 Jenkinsfile进行少量编辑,任何 packaged in a Docker container的工具, 都可轻松使用。
Jenkinsfile (Declarative Pipeline) pipeline { agent { docker { image 'node:7-alpine' } } stages { stage('Test') { steps { sh 'node --version' } } } }当流水线执行时, Jenkins 将会自动地启动指定的容器并在其中执行指定的步骤:
[Pipeline] stage [Pipeline] { (Test) [Pipeline] sh [guided-tour] Running shell script + node --version v7.4.0 [Pipeline] } [Pipeline] // stage [Pipeline] } 容器的缓存数据许多构建工具都会下载外部依赖并将它们缓存到本地以便于将来的使用。 由于容器最初是由 "干净的" 文件系统构建的, 这导致流水线速度变慢, 因为它们不会利用后续流水线运行的磁盘缓存。 on-disk caches between subsequent Pipeline runs.