Skip to content

Jenkins 2.x 实践指南 2. pipeline 入门

2.1 pipeline 是什么

从某种抽象层次上讲,部署流水线(Deployment pipeline)是指从软件版本控制库到用户手中这一过程的自动化表现形式。
--《持续交付--发布可靠软件的系统方法》

Jenkins 1.x 只能通过界面手动操作来“描述”部署流水线。Jenkins 2.x 终于支持 pipeline as code 了,可以通过“代码”来描述部署流水线。

使用“代码”而不是 UI 的意义:

  • 更好地版本化
  • 更好地协作
  • 更好地重用性

2.2 Jenkinsfile 又是什么

Jenkinsfile 就是一个文本文件,也就是部署流水线概念在 Jenkins 中的表现形式。像 Dockerfile 之于 Docker。

Jenkins 默认不支持 Jenkinsfile,需要安装 pipeline 插件。

我本地安装的是 jenkins-2.179,推荐安装的插件列表见下图,已经包含了 pipeline 插件。

2.3 pipeline 语法的选择

Jenkins 团队在一开始实现 Jenkins pipeline 时, Groovy 语言被选择作为基础来实现 pipeline。

Jenkins pipeline 支持两种语法。pipeline 插件从 2.5 版本开始(当前(2019/06/02)最新是 2.6 版),才同时支持两种格式的语法。

  1. 脚本式(Scripted)语法

    很像是(其实就是)在写 Groovy 代码

    groovy
    node {
        stage('Build') {
            // 执行构建
        }
        stage('Test') {
            // 执行测试
        }
        stage('Deploy') {
            try{
                // 执行部署
            }catch(err){
                currentBuild.result = 'FAILURE'
                mail body: "project build error is here:${env.BUILD_URL}",
                from: 'liujj.oct@outlook.com',
                replyTo: 'liujj.oct@outlook.com',
                subject: 'project build failed',
                to: 'liujj.oct@outlook.com'
                throw err
            }
        }
    }
  2. 声明式(Declarative)语法

    groovy
    pipeline {
        agent any
    
        stages {
            stage('Build') {
                steps {
                    echo 'Building..'
                }
            }
            stage('Test') {
                steps {
                    echo 'Testing..'
                }
            }
            stage('Deploy') {
                steps {
                    echo 'Deploying..'
                }
            }
        }
        post {
            failure {
                mail to: 'liujj.oct@outlook.com', subject: 'The Pipeline failed :('
            }
        }
    }

社区推荐使用声明式语法,该语法更适合人类的阅读习惯、更简单。

2.4 创建第一个 pipeline

在 Jenkins 中文版中其名称为“流水线”。

groovy
pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'Hello JiaJia'
            }
        }
    }
}

2.5 从版本库拉取 pipeline

推荐从版本库获取 pipeline 并执行。

  1. 首先需要安装 Git 插件

  2. 将 SSH 的私钥放到 Jenkins

    进入 Jenkins凭据(Credentials)系统(System)全局凭证(Global creentials)添加凭证

    • 类型(Kind)SSH Username with private key

    • 范围(Scope)全局 (Jenkins, nodes, items, all child items, etc)

    • ID:内部的唯一 ID,留空时会自动生成一个 ID

    • Username:自定义一个当前凭证的名字,在 Job 的配置页面看到的就是这个值

    • Private Key:这里填入 Git 私钥,也就是 id_rsa 文件中的全部内容,包括起始行和尾行的备注;

      r
      -----BEGIN OPENSSH PRIVATE KEY-----
      b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
      NhAAAAAwEAAQAAAgEA......
      -----END OPENSSH PRIVATE KEY-----
    • Passphrase:私钥密码。没有密码时留空即可。

  3. 从 Git 仓库获取 Jenkinsfile

    • SCMGit

      另一个选项是 Subversion

      Specify where to obtain a source code repository containing your Groovy script. It will be checked out somewhere on the Jenkins master and used to load your Pipeline script. (If you wish to use other files from the same repository during your Pipeline, you will need to check them out separately on some slave; this checkout cannot be reused.)

    • Repositories

      • Repository URLgit@192.168.0.113:liujiajia/jenkinsfiles.git

        Specify the URL of this remote repository. This uses the same syntax as your git clone command.

      • Credentials:选择上一步创建的凭证

    • Branches to build

      • Branch Specifier (blank for 'any'):*/master

        Specify the branches if you'd like to track a specific branch in a repository. If left blank, all branches will be examined for changes and built.

    • 源码库浏览器

      Adds links in "changes" views within Jenkins to an external system for browsing the details of those changes. The "Auto" selection attempts to infer the repository browser from other jobs, if supported by the SCM and a job with matching SCM details can be found.

    • 脚本路径02/pipeline-hello-jiajia-git

      默认值是 Jenkinsfile。填入实际的文件的地址就可以了。

      Relative location (/-separated regardless of platform) within the checkout of your Pipeline script. Note that it will always be run inside a Groovy sandbox. Jenkinsfile is conventional and allows you to switch easily to a multibranch project (just use checkout scm to retrieve sources from the same location as is configured here).

    • 轻量级检出

      If selected, try to obtain the Pipeline script contents directly from the SCM without performing a full checkout. The advantage of this mode is its efficiency; however, you will not get any changelogs or polling based on the SCM. (If you use checkout scm during the build, this will populate the changelog and initialize polling.) Also build parameters will not be substituted into SCM configuration in this mode. Only selected SCM plugins support this mode.

  4. 保存设置之后构建(Build now)

    bash
    Started by user 刘佳佳
    Obtained 02/pipeline-hello-jiajia-git from git git@192.168.0.113:liujiajia/jenkinsfiles.git
    Running in Durability level: MAX_SURVIVABILITY
    [Pipeline] Start of Pipeline
    [Pipeline] node
    Running on Jenkins in D:\Program Files (x86)\Jenkins\workspace\pipeline-hello-jiajia-git
    [Pipeline] {
    [Pipeline] stage
    [Pipeline] { (Declarative: Checkout SCM)
    [Pipeline] checkout
    using credential JiaJia
    > git.exe rev-parse --is-inside-work-tree # timeout=10
    Fetching changes from the remote Git repository
    > git.exe config remote.origin.url git@192.168.0.113:liujiajia/jenkinsfiles.git # timeout=10
    Fetching upstream changes from git@192.168.0.113:liujiajia/jenkinsfiles.git
    > git.exe --version # timeout=10
    using GIT_SSH to set credentials
    > git.exe fetch --tags --force --progress git@192.168.0.113:liujiajia/jenkinsfiles.git +refs/heads/*:refs/remotes/origin/*
    > git.exe rev-parse "refs/remotes/origin/master^{commit}" # timeout=10
    > git.exe rev-parse "refs/remotes/origin/origin/master^{commit}" # timeout=10
    Checking out Revision 35eba1dd0fd860dcb7cefca9d5deccd52a555ff4 (refs/remotes/origin/master)
    > git.exe config core.sparsecheckout # timeout=10
    > git.exe checkout -f 35eba1dd0fd860dcb7cefca9d5deccd52a555ff4
    Commit message: "删除 .gitkeep"
    > git.exe rev-list --no-walk 35eba1dd0fd860dcb7cefca9d5deccd52a555ff4 # timeout=10
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] withEnv
    [Pipeline] {
    [Pipeline] stage
    [Pipeline] { (Build)
    [Pipeline] echo
    Hello JiaJia
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] }
    [Pipeline] // withEnv
    [Pipeline] }
    [Pipeline] // node
    [Pipeline] End of Pipeline
    Finished: SUCCESS

2.6 使用 Maven 构建 Java 应用

Maven 是非常流行的一个 Java 应用构建工具。Jenkins 默认支持 Maven。

  1. 首先创建一个 Maven 项目

  2. 在 Jenkins 上安装 JDKMaven

    • Manage JenkinsGlobal Tool ConfigurationMaven新增 Maven

      选中 Install automatically 后选择对应需要安装的版本就行了

    • Manage JenkinsGlobal Tool ConfigurationMaven新增 JDK

      选中 Install automatically 时貌似需要 Oracle 账号了。

      如果本机已经安装过 JDK,取消选中 Install automatically,然后直接指定 JAVA_HOME 的路径就可以了(如 C:\Program Files\Java\jdk1.8.0_111)。

  3. Jenkinsfile 内容

    下面第一段是书上的脚本,第二段是我实际使用的脚本。区别如下:

    • tools 中增加了 jdk 'jdk-8u111' 指令,否则会报错

      Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project OctopusESCommon: Compilation failure
      No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

    • sh 更改为 bat。Windows 操作系统,需要使用 bat 命令。

    • 删除了 spring-boot:repackage。因为项目中没有配置 repackage goal。

    • 删除了 printenv 指令。因为 windows 中没有该命令。

    groovy
    pipeline {
        agent any
    
        tools {
            maven 'mvn-3.6.1'
        }
    
        stages {
            stage('Build') {
                steps {
                    sh "mvn clean package spring-boot:repackage"
                    sh "printenv"
                }
            }
        }
    }

    修改后的 Jenkinsfile:

    groovy
    pipeline {
        agent any
    
        tools {
            jdk 'jdk-8u111'
            maven 'mvn-3.6.1'
        }
    
        stages {
            stage('Build') {
                steps {
                    bat "mvn clean package"
                }
            }
        }
    }
  4. 构建

    成功执行结束的话其日志如下:

    bash
    Started by user 刘佳佳
    Lightweight checkout support not available, falling back to full checkout.
    Checking out git git@192.168.0.113:liujiajia/octesservices.git into D:\Program Files (x86)\Jenkins\workspace\OctESServices@script to read Jenkinsfile_win
    using credential JiaJia
    > git.exe rev-parse --is-inside-work-tree # timeout=10
    Fetching changes from the remote Git repository
    > git.exe config remote.origin.url git@192.168.0.113:liujiajia/octesservices.git # timeout=10
    Fetching upstream changes from git@192.168.0.113:liujiajia/octesservices.git
    > git.exe --version # timeout=10
    using GIT_SSH to set credentials 
    > git.exe fetch --tags --force --progress git@192.168.0.113:liujiajia/octesservices.git +refs/heads/*:refs/remotes/origin/*
    > git.exe rev-parse "refs/remotes/origin/1.2.0^{commit}" # timeout=10
    > git.exe rev-parse "refs/remotes/origin/origin/1.2.0^{commit}" # timeout=10
    Checking out Revision 4b3ba46f71baa7684a7c13923bcf9586e0f1a920 (refs/remotes/origin/1.2.0)
    > git.exe config core.sparsecheckout # timeout=10
    > git.exe checkout -f 4b3ba46f71baa7684a7c13923bcf9586e0f1a920
    Commit message: "更新 Jenkinsfile_win"
    > git.exe rev-list --no-walk f5de2eabf824f9c26775d80a18ba6f47881dfe4d # timeout=10
    Running in Durability level: MAX_SURVIVABILITY
    [Pipeline] Start of Pipeline
    [Pipeline] node
    Running on Jenkins in D:\Program Files (x86)\Jenkins\workspace\OctESServices
    [Pipeline] {
    [Pipeline] stage
    [Pipeline] { (Declarative: Checkout SCM)
    [Pipeline] checkout
    using credential JiaJia
    > git.exe rev-parse --is-inside-work-tree # timeout=10
    Fetching changes from the remote Git repository
    > git.exe config remote.origin.url git@192.168.0.113:liujiajia/octesservices.git # timeout=10
    Fetching upstream changes from git@192.168.0.113:liujiajia/octesservices.git
    > git.exe --version # timeout=10
    using GIT_SSH to set credentials 
    > git.exe fetch --tags --force --progress git@192.168.0.113:liujiajia/octesservices.git +refs/heads/*:refs/remotes/origin/*
    > git.exe rev-parse "refs/remotes/origin/1.2.0^{commit}" # timeout=10
    > git.exe rev-parse "refs/remotes/origin/origin/1.2.0^{commit}" # timeout=10
    Checking out Revision 4b3ba46f71baa7684a7c13923bcf9586e0f1a920 (refs/remotes/origin/1.2.0)
    > git.exe config core.sparsecheckout # timeout=10
    > git.exe checkout -f 4b3ba46f71baa7684a7c13923bcf9586e0f1a920
    Commit message: "更新 Jenkinsfile_win"
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] withEnv
    [Pipeline] {
    [Pipeline] stage
    [Pipeline] { (Declarative: Tool Install)
    [Pipeline] tool
    [Pipeline] envVarsForTool
    [Pipeline] tool
    [Pipeline] envVarsForTool
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] withEnv
    [Pipeline] {
    [Pipeline] stage
    [Pipeline] { (Build)
    [Pipeline] tool
    [Pipeline] envVarsForTool
    [Pipeline] tool
    [Pipeline] envVarsForTool
    [Pipeline] withEnv
    [Pipeline] {
    [Pipeline] bat
    
    D:\Program Files (x86)\Jenkins\workspace\OctESServices>mvn clean package 
    [INFO] Scanning for projects...
    [INFO] ------------------------------------------------------------------------
    [INFO] Reactor Build Order:
    [INFO] 
    [INFO] OctopusESServices                                                  [pom]
    [INFO] OctopusESCommon                                                    [jar]
    [INFO] OctopusESApiModel                                                  [jar]
    [INFO] OctopusESDao                                                       [jar]
    [INFO] OctopusESApiServices                                               [jar]
    [INFO] OctopusESJob                                                       [jar]
    [INFO] OctopusESApi                                                       [jar]
    [INFO] 
    [INFO] -------------------< com.octopus:OctopusESServices >--------------------
    [INFO] Building OctopusESServices 1.0-SNAPSHOT                            [1/7]
    [INFO] --------------------------------[ pom ]---------------------------------
    [INFO]
    [INFO] --- maven-clean-plugin:3.0.0:clean (default-clean) @ OctopusESServices ---
    [INFO] 
    [INFO] --------------------< com.octopus:OctopusESCommon >---------------------
    [INFO] Building OctopusESCommon 1.0-SNAPSHOT                              [2/7]
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO] ......
    [INFO] ------------------------------------------------------------------------
    [INFO] Reactor Summary for OctopusESServices 1.0-SNAPSHOT:
    [INFO] 
    [INFO] OctopusESServices .................................. SUCCESS [  0.188 s]
    [INFO] OctopusESCommon .................................... SUCCESS [  2.171 s]
    [INFO] OctopusESApiModel .................................. SUCCESS [  1.165 s]
    [INFO] OctopusESDao ....................................... SUCCESS [  0.877 s]
    [INFO] OctopusESApiServices ............................... SUCCESS [  2.574 s]
    [INFO] OctopusESJob ....................................... SUCCESS [  1.388 s]
    [INFO] OctopusESApi ....................................... SUCCESS [  0.920 s]
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  9.682 s
    [INFO] Finished at: 2019-06-02T16:26:06+08:00
    [INFO] ------------------------------------------------------------------------
    [Pipeline] }
    [Pipeline] // withEnv
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] }
    [Pipeline] // withEnv
    [Pipeline] }
    [Pipeline] // withEnv
    [Pipeline] }
    [Pipeline] // node
    [Pipeline] End of Pipeline
    Finished: SUCCESS

参考