GITLAB CI/CD 前端缓存优化

4,550 阅读3分钟

GITLAB CI/CD 前端缓存优化

什么是CI/CD

CI是Continuous Integration的缩写,表示持续集成,CD则是Continuous Deployment 的缩写,表示持续交付或部署,在前端这么百花齐放的情况下,怎么能不自动化这一过程呢,有了ci/cd,前端只需要专注与开发代码,代码的lint,部署,推送,全部交给机器自动化去处理。

一开始接入gitlab的ci/cd的时候,觉得挺新鲜的,因为终于解放了双手,接入的方式也很简单,在项目的根目录增加.gitlab-ci.yml文件即可,里面有很多用法,网上有很多优秀的文章介绍,这里只简单介绍下

名称用途
imagerunner镜像
stages定义每一个job
cache缓存
artifacts定义工件,不同job之间传递
script执行的脚本

项目部分配置如下: image.png

随着构建越来越慢,开始思考起gitlab的ci优化,随着构建次数增多,gitlab由开始的三分多钟变成了现在的7分钟多,慢得我是着急得很,于是就有了下面的探索。

cache + artifacts缓存

查阅gitlab的ci文档后,发现cache可以做缓存优化,尝试之,因为项目是多分支的,所以利用gitlab的变量CI_COMMIT_REF_SLUG去缓存不同分支的项目代码,同时项目由npm安装依赖切换到了yarn,实在是本地测试过,yarn重复安装依赖只需要一秒不到,npm则需要差不多8s左右,差距不是一点点

此处是yarn的重复构建耗时,npm的测试太多了,所以弄丢了,数值大概是20秒起。 image.png

优化后,可以发现ci的时间从8分钟

image.png

到现在的5分钟,而且我还把job拆开了,要知道job它会默认拉取缓存和artifacts,是耗时的 image.png

由于我拆分了job,在第一个job就做了打包的工作,但是呢,每个阶段都是独立的,第一阶段的东西无法与第二阶段共享,所以用artifacts,去传递。

后来测试了几次,发现时间都是在5分钟左右,发现其实还是有值得优化的点的,比如

  1. 能不能不安装依赖,直到package.json变更才去重新安装一次
  2. 既然每个job都会执行restore cache,save cache, upload artifacts的操作,这些操作是io操作,那能不能只用一个job去做就好了呢
  3. 能不能取消它自动save cache和artifacts的操作呢

手动缓存node_modules + job合并

网上查阅到文档,gitlab本身的cache似乎是比较耗时的,那能不能自己去做缓存呢,自己想法如下

  1. 利用gitlab的only changes去做,当package变动时才去重新安装代码,但这个又得拆分job
  2. 自行监测package.json的变化,将node_module打成压缩包,注意,需要将gitlab的runner挂载到宿主主机
# unique hash of required dependencies
PACKAGE_HASH=($(md5sum package.json))
# path to cache file
DEPS_CACHE=/cache/dependencies_${PACKAGE_HASH}.tar.gz
# Check if cache file exists and if not, create it
if [ -f $DEPS_CACHE ];
then
  echo '使用缓存'
  tar zxf $DEPS_CACHE;
else
  echo '不使用缓存'
  #find /tmp/dependencies_* -mtime +1 -type f -delete 
  #npm install --quiet;
  yarn install --pure-lockfile
  tar zcf - ./node_modules > $DEPS_CACHE;
fi

这里网上查的md5sum能监测到文件变化,测试过新增,删除,改版本都有效

同时将job合并成一个,安装依赖,构建都同时做了,最后ci时间

image.png

三分钟以内了,安装依赖方面其实基本都在20s内了,构建方面,vue-cli默认帮我们做了很多了,我能做的只有抽取大文件,因为我需要source-map,所以我并没有生产环境去掉source-map,不然估计能更快点?

结论

探索ci优化看着只有上面那么点,但实际上差不多花了一天时间,希望自己永远不要停止探索精神,同时希望有大佬有更好的方案可以指点一下,不知道有一天前端能不能像php,node那样,直接推送代码就可以访问呢