Jenkinsfile流水线构建教程

前言

Jenkins 是目前使用非常广泛的自动化流程的执行工具, 我们目前的一些自动化编译, 自动化测试都允许在 Jenkins 上面. 在 Jenkins 的术语里面, 一些自动化工作联合起来称之为流水线, 比如拉取代码, 编译, 运行自动化测试等.

本文的主要目的是引导你快速熟悉 Jenkinsfile 结构和语义, 让你读完之后可以自己写出一个 Jenkinsfile.

Jenkins 流水线分为脚本式的和声明式的. 脚本式流水线比较灵活, 可以嵌入一些 groovy 语言编程,功能比较强大, 但是对于新手而言上手比较困难, 有一定的学习门槛. 声明式流水线更具结构化, 简单直白, 减少了对 groovy 语言的依赖, 对新用户更友好.

Jenkinsfile 是什么

在 Jenkins 2 中, 流水线配置可以从 Jenkins 中分离出来. Jenkinsfile 允许你将配置文件和执行步骤以代码的形式保存, 这样就可以做到像管理 源代码一样管理 Jenkins 任务, 支持历史追溯, 差异对比等.

Jenkins2 推荐使用名为 'Jenkinsfile'的文件保存任务配置和流水线信息, 不同的项目和分支都有自己 的 Jenkinsfile, 其内容各不相同.

Jenkinsfile 基本功能

让我们先从一个简单的 Jenkinsfile 开始, 逐步了解 Jenkinsfile 的功能和用法.

Jenkinsfile Hello world

jenkinsfile 复制代码
pipeline {
    agent any

    stages {
        stage('Source') {
            steps {
                echo 'hello world'
            }
        }
    }
}
  • 第 1 行声明这是一个流水线.
  • 第 2 行指定了执行该流水线的 agent, agent 可以理解为一个执行环境, 可以是 docker, k8s, 也可以是当前机器环境
  • 第 4 行指定了执行该流水线所需要的步骤, stages 里面可以保护多个 stage
  • 第 5 行指定了一个名字叫做'Source'stage
  • 第 6 行指定了该 stage 内需要执行的 steps
  • 第 7 行调用 echo 内置函数打印了一句'hello world'

执行 shell 脚本

在 steps 块中使用sh来执行. 多行命令可以用"""(三个双引号) 或者 "'(三个单引号). 区别在于双引号里面引用 的变量会被计算展开. 例如:

groovy 复制代码
steps {
    // 单行shell命令
    sh 'echo "Hello world"'

    // 多行shell命令, 以连续的三个'或者"包围
    sh '''#!/bin/bash
    # multi line shell script
    cd project
    mkdir build && cd build
    cmake .. && cmake --build .
    '''
}

指定工作目录

dir指令的功能是设定命令执行时的工作目录, 如果该目录不存在则创建它.

groovy 复制代码
steps {
    dir('project/build') {
        sh "echo `pwd`"
    }
}

拉取 GitHub/Bitbucket 代码

声明式流水线的 git 检出代码非常简单直白. 如下:

groovy 复制代码
steps {
    dir('code_repo') {
        git credentialsId: "${BITBUCKET_CREDENTIALS_ID}",
            url: 'ssh://git@git.company.com/code_repo.git',
            branch: 'master'
    }
}

需要说明几点:

  1. git指令会检出到当前的目录. 如果你需要检出到子目录则需要使用dir指令.
  2. credentialsId这块引用了一个环境变量, 该变量保存着仓库服务器的 credential. 定义环境变量的方法见后.
  3. branch 指定使用该仓库的哪个分支, 如果是 master 那可以省略.

定义环境变量

环境变量在 pipeline 的environment块中定义.

groovy 复制代码
pipeline {
    agent none

    environment {
        // credentials for other service, you can find it at
        BITBUCKET_CREDENTIALS_ID = 'bitbucket.company.com'
        REGISTRY_CREDENTIALS_ID = 'jenkins-harbor'
    }
}

使用 docker 容器

这里有两种办法.

docker 插件提供的方法

在 agent 中指定 docker 环境. 这种方法适合安装了 docker 的 Jenkins.

groovy 复制代码
stage ('SetupEnv') {
    agent {
        docker {
            alwaysPull true
            image 'hub.company.com/jenkins/ubuntu:24_04'
            registryCredentialsId "${REGISTRY_CREDENTIALS_ID}"
            registryUrl 'https://hub.company.com'
            reuseNode true
        }
    }

    steps {
        // 这里的代码运行在上面的docker container环境
        sh '''#!/bin/bash
            set -xeu
            cd code_repo
            ./setup_env.sh 64
        '''
    }
}

此时 steps 块中的命令都是在 docker 环境中执行的.

Docker Template

本方法适用于在 k8s 集群上面部署的 Jenkins, 并且已经设置了全局的 Docker Template 文件. 如果想使用 自己设定的 yaml 文件, 请参考下一节. label 是指定 k8s 有相应标签属性的 pod, 而container 则是指定选取特定的 docker images.

groovy 复制代码
pipeline {
    agent {
        kubernetes {
            label 'jenkins-streaming'
        }
    }

    stages {
        stage('stage1') {
            steps{
                container('ubuntu'){
                    sh 'lsb_release -a'
                }
            }
        }
    }
}

指定自己的 k8s yaml 文件

本方法适用于 k8s 环境下部署的 Jenkins. 特点在于可以由使用者配置 Docker Template.

groovy 复制代码
pipeline {
    agent {
        kubernetes {
            yaml libraryResource('co/company/project_pod.yaml')
        }
    }

    stages {
        stage('show') {
            steps{
                container('ubuntu'){
                    sh 'lsb_release -a'
                }
            }
        }
    }
}

yaml 文件如果在本地仓库, 则可以使用

groovy 复制代码
yamlFile 'path/to/local/pod/file.yaml'

指定 agent

一个 pipeline 可以指定一个或者多个agent. 指定一个全局通用 agent 的方法是在 pipeline 开始的地方指定.

groovy 复制代码
pipeline {
    agent any
}

pipeline {
    agent {
        docker {
            // docker images settings
        }
    }
}

pipeline {
    agent {
        kubernetes {
            // k8s settings
        }
    }
}

如果需要在不同的 stage 使用不同的 agent, 则在开始处指定为none, 然后在各个 stage 分别指定.

groovy 复制代码
pipeline {
    agent none

    stages {
        stage('Source') {
            agent any
        }

        stage('Compile') {
            agent {
                image: 'hub.company.com/jenkins/ubuntu:2404'
            }
        }
    }
}

Artifactory 上传下载

中间产物文件需要上传到 Artifactory 的, 可以参考下面步骤:

groovy 复制代码
stage ('Upload Files to Artifactory') {
    steps {
        rtUpload (
            serverId: "${ARTIFACTORY_SERVER_ID}",

            spec: """
            {
                "files": [
                    {
                        "pattern": "/build/library.a",
                        "target": "your_repo",
                        "props": "gcc_version=4.8;branch=your_branch_name"
                    },
                    {
                        "pattern": "/build/executable.a",
                        "target": "your_repo",
                        "props": "gcc_version=4.8;branch=your_branch_name"
                    }
                ]
            }
            """
        )
    }
}

关于 spec 的详细信息可以参考: Upload

SonarQube 集成

SonarQube 提供了代码审计, 漏洞检查的功能. 目前可以集成 clang-tidy, cppcheck 静态检查结果, 以及 gcov 的覆盖率分析结果.

同时能提供新增代码的质量检查, 确保新 merge 的代码符合质量要求.

groovy 复制代码
stage('Analysis') {
    steps {
        withSonarQubeEnv('SonarQubeServerID') {
            container("sonar-scanner-image") {
                sh '''#!/bin/bash
                set -eu
                cd your/project
                sonar-scanner -X \
                    -Dsonar.projectKey=ProjectName
                '''
            }

        }
    }
}

一般而言, 我们会在执行 sonar-scanner 的目录里面存放一个名为sonar-project.properties

的文件, 用以指定更多的 sonar 配置. 示例的配置如下:

properties 复制代码
sonar.projectVersion=3.0.0
sonar.language=c++
# 指定源文件目录
sonar.sources=.
sonar.sourceEncoding=UTF-8
# 指定排除的文件/目录
sonar.exclusions=\
    build/** \
    doc/** \
    script/** \
    libs/** \
    test/**
# 指定排除覆盖率的文件
sonar.coverage.exclusions=**/*_test.cpp
# cppcheck 报告文件
sonar.cxx.cppcheck.reportPath=./cppcheck_report.xml
# clang tidy报告文件
sonar.cxx.clangtidy.reportPath=./clang-tidy-report.txt
sonar.cxx.coverage.reportPath=./bullseye_report.xml

总结

在这篇文章中, 我们深入探讨了 Jenkinsfile 的基础与高级用法, 从最简单的"Hello World"示例到复杂的 Docker 容器集成, Kubernetes 部署, Artifactory 上传下载以及 SonarQube 代码质量检查. 通过这些内容的学习, 可以帮你掌握如何创建一个基本的流水线, 并且了解了如何扩展这个基础以适应更复杂的需求.

参考资料

Jenkins 2: Up and Running

相关推荐
学海无涯,行者无疆5 小时前
使用Jenkins实现Windows服务器下C#应用程序发布
windows·c#·jenkins·.net·cicd·自动发布·一键发布
令狐少侠20118 小时前
devops-Jenkins一键部署多台实例
运维·jenkins·devops
但老师1 天前
Jenkins垃圾清理指南
java·运维·jenkins
m0_748257181 天前
Java进阶(ElasticSearch的安装与使用)
java·elasticsearch·jenkins
一张假钞2 天前
Jenkins protoc: command not found
运维·jenkins
老友@2 天前
Docker 部署 Jenkins持续集成(CI)工具
运维·ci/cd·docker·云原生·容器·jenkins·自动化部署