缓存目录

最近更新时间:2024-06-12 11:59:41

我的收藏
本文为您介绍如何使用缓存目录功能。

前提条件

设置 CODING 持续集成中构建环境前,您的腾讯云账号需要开通 CODING DevOps 服务,详情请参见 开通服务

进入项目

1. 登录 CODING 控制台,单击团队域名进入 CODING 使用页面。
2. 进入目标项目后,选择左侧导航栏的持续集成。

功能介绍

本地项目在按安装依赖包时会把下载的文件缓存起来,以供下次安装使用。例如使用 npm install 命令后会在项目中生成 ./node_modules,缓存储存在 ~/.npm 目录,后者体积更小,更通用。
默认构建节点
CODING 会为每个构建计划自动分配计算资源,构建完毕即销毁,每次构建都会自动重新分配一台构建节点,因此需要指定缓存目录用于加速下次构建。
自定义构建节点
若选择自行接入计算资源,并在构建计划中选择通过自定义构建节点执行任务,那么构建完毕不会销毁服务器,故无需指定缓存目录。
如果在持续集成中使用 Docker 时需要把缓存目录挂载至 Docker 中。

默认构建节点

1. CODING 为构建计划提供基础的任务计算资源,每次任务都会分配一台云服务器,构建环境为 Linux 系统、分配 root 用户权限,缓存目录如下:
包管理工具
缓存目录
Maven
/root/.m2/
Gradle
/root/.gradle/
npm
/root/.npm/
composer
/root/.cache/composer/
yarn
/usr/local/share/.cache/yarn/
2. 您可以在构建计划设置中的变量与缓存中勾选缓存目录,如果未找到目标目录还支持自行录入。




Docker 构建环境

若在构建计划中使用 Docker 环境,那么需先行前往变量与缓存中勾选缓存目录,再挂载至 Docker 中。

Jenkinsfile

pipeline {
agent any
stages {
stage('检出') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
])
}
}
stage('Java 缓存') {
agent {
docker {
image 'adoptopenjdk:11-jdk-hotspot'
args '-v /root/.gradle/:/root/.gradle/ -v /root/.m2/:/root/.m2/'
reuseNode true
}
}
steps {
sh './gradlew test'
}
}
stage('npm 缓存') {
steps {
script {
docker.image('node:14').inside('-v /root/.npm/:/root/.npm/') {
sh 'npm install'
}
}
}
}
}
}

自定义构建节点

在自定义构建节点中使用 Docker 环境时需按照服务器用户名找到对应的缓存目录,例如当 Ubuntu 服务器的默认用户名为 ubuntu 时,缓存目录为 /home/ubuntu/.npm/,那么对应的代码为:
docker.image('node:14').inside('-v /home/ubuntu/.npm/:/root/.npm/') {
sh 'npm install'
}

缓存 Docker 基础镜像

1. 如果每次构建都需要拉取 Docker 基础镜像,例如 Dockerfile 基础镜像、CI agent 镜像,那么通常会耗费大量时间,此时就可以通过缓存进行加速。
参考以下 Jenkinsfile,修改镜像名称即可复用:
pipeline {
agent any
environment{
DOCKER_CACHE_EXISTS = fileExists '/root/.cache/docker/php-8.0-cli.tar'
}
stages {
stage('加载缓存') {
when { expression { fileExists(DOCKER_CACHE_PATH).equals(true) } }
steps {
sh 'docker load -i /root/.cache/docker/php-8.0-cli.tar || true'
}
}
stage('使用镜像(请修改此段)') {
agent {
docker {
image 'php:8.0-cli'
args '-v /root/.cache/:/root/.cache/'
reuseNode 'true'
}
}
steps {
sh "php -v"
}
}
stage('生成缓存(仅运行一次)') {
when { expression { DOCKER_CACHE_EXISTS == 'false' } }
steps {
sh 'mkdir -p /root/.cache/docker/'
sh 'docker save -o /root/.cache/docker/php-8.0-cli.tar php:8.0-cli'
}
}
}
}
2. 在缓存目录处增加/root/.cache/ 路径,此时第二次的构建耗时明显更短,说明缓存已生效:



注意:
缓存镜像会逐渐过时,建议定时清除,与官方更新保持一致。

保存 Dockerfile

在持续集成中使用 Dockerfile 作为构建环境,需要运行 docker build命令用以初始化,较为不便。可以将已构建的 Docker 镜像保存到仓库,方便二次拉取复用。
Jenkinsfile
// 创建 CODING Docker 制品库,获取用户名、密码和仓库地址
sh "docker login -u $DOCKER_USER -p $DOCKER_PASSWORD my-team-docker.pkg.coding.net"

// 使用 Dockerfile 的 md5 做 tag
md5 = sh(script: "md5sum Dockerfile | awk '{print \\$1}'", returnStdout: true).trim()
imageFullName = "my-team-docker.pkg.coding.net/my-project/my-repo/my-app:dev-${md5}"

// 检查镜像是否已存在远端仓库
dockerNotExists = sh(script: "docker manifest inspect $imageFullName > /dev/null", returnStatus: true)
def testImage = null
if (dockerNotExists) {
testImage = docker.build("$imageFullName", "--build-arg APP_ENV=testing ./")
sh "docker push $imageFullName"
} else {
testImage = docker.image(imageFullName)
}

// 使用镜像进行自动化测试
testImage.inside("-e 'APP_ENV=testing'") {
stage('test') {
echo 'testing...'
sh 'ls'
echo 'test done.'
}
}
代码解释:在 shell 中执行下列命令,通过返回值可以判断镜像是否已经存在。
$ docker manifest inspect ecoding/foo:bar
no such manifest
$ echo $?
1

缓存也是加速构建的最好方式之一,但是不同工具和语言的方案各不相同,接下来将会枚举几种常见的场景和加速方案。

默认节点使用缓存

对于持续集成默认节点来说,如果直接在宿主机上进行构建,Maven 和 Gradle 会将构建的依赖下载到 /root/.m2 和 /root/.gradle 中, Npm 也是同理的依赖会下载到 /root/.npm 中。

Docker 自定义构建环境使用缓存

您可以参考Dockerfile 实践教程。该文档是 Docker 的官方文档,文档中提出了一些措施帮助我们编写优秀的 Dockerfile。

对 FROM 的镜像进行抽象

如果您有多个服务,每个 Dockerfile 里面都需要 apt-get 安装一些工具,此时您应该抽象出您的 FROM 镜像安装好必要的工具,将其作为 FROM 镜像给 Dockerfile 使用。对于团队来说,基础镜像的管理是非常有必要的,不光可以减少构建耗时,还可以统一的修复安全漏洞,增加内置的工具,可以很大程度上减少开发和运维同学的维护成本。

自定义构建环境使用缓存

持续集成除了使用官方提供的构建环境, 还可以使用 Docker 自定义构建环境。自定义构建环境就相当于 docker run 出了一个 container,构建的指令在这个环境中执行。
举例: 假如需要用 Java18 和 Maven 构建程序:
pipeline {
agent {
docker {
reuseNode 'true'
registryUrl 'https://coding-public-docker.pkg.coding.net'
image 'public/docker/openjdk:18-2022'
args '-v /root/.m2:/root/.m2 -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock'
}
}
stages {
stage('检出') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
extensions: [[$class: 'CloneOption', depth: 1, noTags: false, shallow: true]],
userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
])
}
}
stage('编译') {
steps {
sh "mvn clean install"
}
}
stage('push ') {
steps {
sh "echo password | docker login xxx-docker.pkg.coding.net -u xxx --password-stdin "
sh "docker build -t myjava:latest ."
sh "docker push myjava:latest "
}
}
}
}
请注意到 args '-v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock -v /root/.m2:/root/.m2 '
-v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock,将 docker 和 docker.sock 挂载到自定义环境的容器中,可以在后续的 stage 和 step 中使用 docker。
-v /root/.m2:/root/.m2,将宿主机的 /root/.m2 和自定义构建环境的容器的 /root/.m2 进行一个映射,在自定义构建环境容器中执行 mvn clean install 下载的 maven 一来会下载到容器的 /root/.m2。
勾选上变量与缓存中 Maven,这样下次构建就会利用上这个缓存。