目录

    在 CICD 的流程中,需要保存的产物主要有两类,构建产物和缓存。构建产物是最终的执行结果,缓存是为了优化下一次的构建速度。本篇主要描述的是在 Jenkins 中如何对构建产物和缓存进行归档,并结合对象存储进行实践。有部分示例使用的是 在 Kubernetes 上动态创建 Jenkins Slave 进行构建,配置过程可以参考超链接文档。

    1. 部署 Minio 及 S3cmd 使用

    1.1 部署 Minio

    这里使用 docker-compose 编排 Minio 进行部署。

    • 安装 Docker-compose
    yum install -y python3-pip
    pip install docker-compose
    
    • 部署 Minio
    wget https://raw.githubusercontent.com/minio/minio/master/docs/orchestration/docker-compose/docker-compose.yaml
    docker-compose up -d
    
    • 查看 Minio 页面

    选择 9001-9004 任意端口,可以看到 Minio 的页面,使用 minio/minio123 账户登陆。

    1.2 安装使用 S3cmd

    • 安装
    pip3 install s3cmd
    
    • 配置

    编辑 ~/.s3cfg 文件,增加如下内容:

    host_base = remote.dev.chenshaowen.com:9001
    host_bucket = remote.dev.chenshaowen.com:9001
    use_https = False
    
    access_key =  minio
    secret_key = minio123
    
    signature_v2 = False
    

    这里仅用于测试,host_bucket 直接指向部署的服务器。在生产环境中, Bucket 有两种风格:DNS-style 和 Path-style ,可以支持超大规模的分布式存储。

    • 日常操作

    列出全部 Bucket

    s3cmd ls
    
    2020-06-20 21:07  s3://newbucket
    

    创建 Bucket

    s3cmd mb s3://newbucketname/
    

    上传文件

    s3cmd put file.txt s3://newbucketname/
    

    上传文件夹

    s3cmd put -r backup s3://newbucketname/
    

    列出 Bucket 中的数据

    s3cmd ls s3://newbucketname/
    

    下载 Bucket 中的文件

    s3cmd get s3://newbucketname/file.txt
    

    删除 Bucket 中的文件

    s3cmd del s3://newbucketname/file.txt
    

    删除 Bucket

    s3cmd rb s3://newbucketname
    

    2. Jenkins 构建归档

    2.1 本地归档

    新建流水线,内容如下:

    pipeline {
      agent {
        kubernetes {
          yaml """
    apiVersion: v1
    kind: Pod
    spec:
      containers:
      - name: maven
        image: maven:3.6.3-jdk-8-openj9
        command:
        - cat
        tty: true
    """
       }}
       stages {
          stage('Hello') {
             steps {
                container('maven') {
                  sh "echo `date` >> newfile.txt"
                }
             }
          }
       }
       post {
        success {
            archiveArtifacts 'newfile.txt'
        }
      }
    }
    

    查看构建日志,可以看到构建产物成功归档。

    在当次构建的 UI 中,也可以直接查看到归档文件。

    在服务器上,可以查找到归档文件, /var/jenkins_home/jobs/test/builds/43/archive/newfile.txt 。这里 Jenkins 直接将归档的文件保存在 /var/jenkins_home/jobs 文件夹中。

    2.2 对象存储归档

    在 Jenkins 中大部分对象存储插件面向的是 AWS ,而不是 S3 协议。当然,也有云厂商,如 Qiniu ,提供了 Jenkins 存储插件。这里主要使用的是一款开源的对象存储组件 - Minio 。

    • 在插件市场搜索并安装插件 minio

    • 在 Jenkins 配置中,设置 Minio 相关的配置

    • 新建一条自由风格的流水线

    编辑需要执行的 Step ,然后设置构建后需要归档的文件

    • 在构建日志中,可以看到已经归档成功

    与 Jenkins 本地归档不同的是,此时的归档在当次构建页面上,不会展示。

    • 在 Minio 中,查看构建归档的结果

    3. 缓存

    Jenkins 中的缓存主要有两种实践方式,全部流水线共用缓存,每条流水线单独缓存。

    由于采用的是 Kubernetes 动态提供的 Agent ,可以将主机上的 Docker Volume 挂载到 Pod ,提供 Node 级别的缓存,这样全部 Pod 就会共用一个缓存目录。这样处理比较简单,但同时共用一个依赖库文件夹会带来潜在的并发问题。下图是相关的配置:

    另外一种方式是每条流水线一个缓存,这样够精细,但也增加了存储和执行时间的开销。下面主要介绍如何使用 jobcacher 进行缓存。

    • 搜索并安装插件 jobcacher

    • 查看 jobcacher 插件配置

    在 Jenkins 配置中,可以看到 jobcacher 默认使用的是内置的存储,也就是 /var/jenkins_home 下的文件存储。

    如下图,下拉框中,还有另外一个 AWS 的 S3 存储可选。这里仅查看,不做设置和测试。

    • 新建流水线

    新建流水线,内容如下:

    pipeline {
      agent {
        kubernetes {
          yaml """
    apiVersion: v1
    kind: Pod
    spec:
      containers:
      - name: nodejs
        image: node:10-alpine
        command:
        - cat
        tty: true
    """
       }}
       stages {
          stage('checkout') {
             steps {
                git branch: 'master', url: "https://github.com/vuejs/vue"
             }
          }
          stage('install') {
             steps {
                container('nodejs') {
                   cache(caches: [[$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: 'node_modules']], maxCacheSize: 512) {
                         sh "npm install"
                   }
                }
             }
          }
       }
    }
    
    • 首次构建

    可以看到 Jenkins 将设置的目录进行了缓存。在 Jenkins 目录 /var/jenkins_home/jobs/test/cache/3ec03583f8eaec275cb2183db769ff47 中,可以看到相关文件。

    ls /var/jenkins_home/jobs/test/cache/3ec03583f8eaec275cb2183db769ff47
    
    abbrev                                                colors                             flow-remove-types-no-whitespace  lodash._baseclone          require-relative
    accepts                                               combined-stream                    
    ...
    
    • 带缓存构建

    缓存归档之后,再次构建时,下载依赖包的耗时会明显减少。从 31 秒 减少到 7 秒,但增加了拉取缓存、解压等操作的时间。

    • 使用对象存储进行缓存

    由于大部分插件支持的是 AWS ,如果能直接使用 AWS 也是一个不错的选择。使用其他存储,需要厂商插件的支持,或者 fork AWS 的 Jenkins 插件进行二次开发。

    另外一个方向是,提供 s3cmd 命令行,通过 credential 注入秘钥,使用命令行进行上传和下载的管理。下面是简单的流程:

    s3cmd get s3://newbucketname/node_modules.tar.gz
    tar xf ${HOME}/node_modules.tar.gz
    
    # install and build
    
    tar cvfz ${HOME}/node_modules.tar.gz node_modules
    s3cmd del s3://newbucketname/node_modules.tar.gz
    s3cmd put node_modules.tar.gz s3://newbucketname/
    

    4. 参考