众所周知,缓存是性能优化一个重要手段。在 CI 领域,利用好缓存能极大提升流水线构建速度!
下面以前端 NodeJS 为例,介绍两种有效的利用缓存提升构建速度的方法。
我们先准备一份 package.json
,里面有这些模块:
{
"dependencies": {
"angular": "^1.8.3",
"eslint": "^9.15.0",
"jest": "^29.7.0",
"koa": "^2.15.3",
"next": "^15.0.3",
"nuxt": "^3.14.159",
"react": "^18.3.1",
"vue": "^3.5.13",
"webpack": "^5.96.1"
}
}
在流水线上执行 npm install
,流水线配置文件:
main:
push:
"no-cache":
docker:
image: node:22-alpine
stages:
- name: npm install
script: npm install
执行效果:
由于没有 cache,会从网络下载资源,耗时约 23s。
云原生构建
利用 Docker 的 volumes
功能,可在配置文件中通过声明 pipeline.docker.volumes,
将构建机上目录 mount 到容器中。构建任务可将下载好的依赖放入构建机缓存,供后续流水线使用。
Node 流水线配置文件:
main:
push:
"volume-cache":
docker:
image: node:22-alpine
volumes:
- node_modules:copy-on-write
stages:
- name: npm install
script: npm install
多执行几次,命中缓存后执行效果:
可以看到前面截图中 added 1973 packages from 1072 contributors
字样消失了,增加了 up to date
字样,无需从网络下载资源,耗时降为 13s。
volumes
的缺点是,缓存只在当前构建机有效。云原生构建
会根据项目构建并发情况,动态在几台构建机上分配一台作为当前流水线构建机,后续流水线分配了其他无缓存的构建机,仍会重新从网络下载资源。
Maven 流水线配置文件:
main:
push:
- docker:
# 可以去 dockerhub 上 https://hub.docker.com/_/maven 找到您需要 maven 和 jdk 版本
image: maven:3.8.6-openjdk-8
volumes:
- /root/.m2:cow
stages:
- name: build
script: mvn clean package
Gradle 流水线配置文件:
master:
push:
- docker:
# 可以去 dockerhub 上 https://hub.docker.com/_/gradle 找到您需要 gradle 和 jdk 版本
image: gradle:6.8-jdk8
volumes:
- /root/.gradle:copy-on-write
stages:
- name: build
script: ./gradlew bootJar
云原生构建
还提供了一种 cache 方式:在一个镜像中 npm install
好依赖,然后缓存这个镜像在当前构建机,并推送到远端镜像源。
后续流水线使用时,若构建机有镜像缓存,则直接使用。若构建机无镜像缓存,则会从远端镜像源拉取下来。
docker:cache
内置任务使用示例:
master:
push:
- stages:
- name: build cache image
type: docker:cache
options:
dockerfile: cache.dockerfile
by:
- package.json
- package-lock.json
versionBy:
- package-lock.json
exports:
name: DOCKER_CACHE_IMAGE_NAME
- name: use cache
image: $DOCKER_CACHE_IMAGE_NAME
commands:
- cp -r "$NODE_PATH" ./node_modules
cache.dockerfile 示例:
# 选择一个 Base 镜像
FROM node:16
# 设置工作目录
WORKDIR /space
# 将 by 中的文件列表 COPY 过来
COPY . .
# 根据 COPY 过来的文件进行依赖的安装
RUN npm ci
# 设置好需要的环境变量
ENV NODE_PATH=/space/node_modules
无镜像,需要构建并推送镜像的效果:
可以看到耗时同直接 npm install
接近,约 31.5s。
后续构建,构建机无镜像,需要 pull 的效果,待补充
后续构建,若构建机有镜像,直接使用的效果:
耗时降到 2.7s,效果非常明显!
volumes
:缓存在构建机,效果好docker:cache
:缓存在构建机和远端,效果好volumes
:配置简单,清晰易懂docker:cache
:配置复杂,涉及配置文件、dockerfile,有一定理解、使用成本volumes
:同一个构建机中,可跨流水线共享缓存,不可跨构建机docker:cache
:流水线执行过程中,流水线独享。缓存镜像构建完成、推送到远端后,可跨流水线、跨构建机使用volumes
:可控制读写权限,适用更多场景docker:cache
:重新构建缓存镜像并推送到远端,其他构建机需重新拉取。参见 .cnb.yml
具体效果对比,可于本仓库的云原生构建列表页查看流水线,或 fork 后自行尝试。