一、什么是pipeline?

Pipeline,简而言之,就是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排与可视化;
Pipeline 是Jenkins 2.X 的最核心的特性,帮助Jenkins 实现从CI 到 CD 与 DevOps的转变。
Pipeline 是一组插件,让jenkins 可以实现持续交付管道的落地和实施。持续交付管道是将软件从版本控制阶段到交付给用户/客户的完整过程的自动化表现。

二、pipeline的概念

Pipeline 是一个用户定义的 CD 流水线模式。Pipeline 代码定义了通常包含构建、测试和发布步骤的完
整的构建过程。

三、Pipeline任务

3.1、创建Pipeline任务

新增任务,选择pipeline(流水线)

image-20230830150556217

#Pipeline定义有两种方式:
一种是Pipeline Script ,是直接把脚本内容写到脚本对话框中;
另一种是 Pipeline script from SCM (Source Control Management–源代码控制管理,即从gitlab/github/git上获得pipeline脚本–JenkisFile)

image-20230830151910349

3.2 、流水线语法

参考文章

脚本式语法格式:
pipeline{
agent any
stages{
    stage("get code"){
       steps{
           echo "get code from scm"
       }
    }
    stage("package"){
        steps{
            echo "packge code"
        }
    }
}
}
----------------------------------------------------------------------------------------------------
#解读
pipeline: 这是Pipeline脚本的开始,表示你正在定义一个Jenkins Pipeline。
agent any: 这是在Pipeline中定义的一个指令,它指定了运行Pipeline的代理(节点)。any 表示可以在任何可用的代理节点上运行。
stages: 在Jenkins Pipeline中,工作流被组织为一个或多个阶段(stages),每个阶段代表一个特定的构建或部署步骤。
stage("get code"): 这是定义一个名为 "get code" 的阶段。这个阶段将用来获取代码。
steps: 在阶段内部,你可以定义一个或多个步骤(steps),每个步骤执行特定的操作。
echo "get code from scm": 这是一个步骤,它使用 echo 命令在控制台输出文本。在这个例子中,输出的文本是 "get code from scm",表示从源代码管理系统(SCM)获取代码。

3.3、配置Gitlab地址

image-20230830151956362

image-20230830152047143

image-20230830152413741

脚本代码:

pipeline{
agent any
stages{
    stage("下拉代码"){
       steps{
          git 'git@gitlab.driverzeng.com:root/hello.git'
       }
    }
    stage("代码质量检测"){
        steps{
            sh '''/usr/lib/maven/bin/mvn  clean verify sonar:sonar \\
  -Dsonar.projectKey=java \\
  -Dsonar.projectName=\'java\' \\
  -Dsonar.host.url=http://10.0.0.83:9000 \\
  -Dsonar.token=squ_abd87057be010b87265b82779d9342234f3d2065'''
        }
    }
    stage("构建"){
        steps{
           sh '/usr/lib/maven/bin/mvn clean package'
        }
    }
    stage("推送代码"){
        steps{
           sh 'scp ${WORKSPACE}/target/hello-world-war-6.0.0.war root@172.16.1.7:/hello-version'
        }
    }
    stage("远端解压代码"){
        steps{
           sh 'ssh root@172.16.1.7 "unzip -n /hello-version/hello-world-war-6.0.0.war -d /hello-version/hello-world-war-6.0.0"'
        }
    }
    stage("部署代码"){
        steps{
            sh 'ssh root@172.16.1.7 "rm -f /usr/share/tomcat/webapps/ROOT && ln -s /hello-version/hello-world-war-6.0.0 /usr/share/tomcat/webapps/ROOT "'
        }
    }
    stage("重启服务"){
        steps{
           sh 'ssh root@172.16.1.7 systemctl restart tomcat'
        }
    }

}
}
脚本中定义了7个阶段(stage)
运行任务,可以看到分为7个部分,如下图所示:

image-20230830165131943

四、Pipeline script from SCM 通过代码库运行任务

将pipeline代码(Jenkinsfile)保存到代码库中,然后通过指定代码位置(脚本位置)的方式来运行pipeline任务。

1、创建Jenkinsfile,由Groovy语言实现。一般是存放在项目根目录,随项目一起受源代码管理软件控制。

4.1、准备工作

首先,确保你的 Jenkins 服务器已经搭建好并且可以正常访问。如果你还没搭建 Jenkins服务器,可以参考 官方文档 进行安装

4.2、第一步:创建 JenkinsFile 集中存放仓库

在这个步骤中,我们将创建一个 Git 仓库,用于集中存放所有项目的 JenkinsFile 文件。你可以把这个仓库当成 JenkinsFile 的乐园,各个JenkinsFile 在这里自由地玩耍和交流。

# 创建一个名为 "jenkinsfile" 的仓库
[root@gitlab jenkins-pipelinefile]# git init .
Initialized empty Git repository in /jenkins-pipelinefile/.git/
[root@gitlab jenkins-pipelinefile]# git config --global user.name "Administrator"
[root@gitlab jenkins-pipelinefile]# git config --global user.email "admin@example.com"
[root@gitlab jenkins-pipelinefile]# git remote add origin git@gitlab.driverzeng.com:root/pipeline-file.git
# 创建一个 README.md 文件,简要介绍项目
echo "# Jenkinsfile Collection" > README.md
#创建代码
git add README.md
git commit -m "Initial commit"

4.3、第二步:将各项目 JenkinsFile 放入集中仓库

在这个步骤中,我们将把各个项目的 JenkinsFile 文件放入集中仓库的对应子目录中。这就像把孩子们接到幼儿园,每个孩子有自己的小房间和小床。
假设我们有1个项目:project-a 别有名为:Jenkinsfile-a JenkinsFile 文件。

# 在集中仓库中为每个项目创建子目录
[root@gitlab jenkins-pipelinefile]# mkdir java-maven_pipelin
# 将项目的 JenkinsFile 文件复制到对应子目录/也可另行创建
[root@gitlab jenkins-pipelinefile]# vim java-maven_pipelin/jenkinsline
pipeline {
    agent any
    stages {
        stage("下拉代码") {
            steps {
                git 'git@gitlab.driverzeng.com:root/hello.git'
            }
        }
        stage("代码质量检测") {
            steps {
                script {
                    sh '/usr/lib/maven/bin/mvn clean verify sonar:sonar ' +
                       '-Dsonar.projectKey=java ' +
                       '-Dsonar.projectName=\'java\' ' +
                       '-Dsonar.host.url=http://10.0.0.83:9000 ' +
                       '-Dsonar.token=squ_abd87057be010b87265b82779d9342234f3d2065'
                }
            }
        }
        stage("构建") {
            steps {
                sh '/usr/lib/maven/bin/mvn clean package'
            }
        }
        stage("推送代码") {
            steps {
                sh 'scp ${WORKSPACE}/target/hello-world-war-6.0.0.war root@172.16.1.7:/hello-version'
            }
        }
        stage("远端解压代码") {
            steps {
                sh 'ssh root@172.16.1.7 "unzip -n /hello-version/hello-world-war-6.0.0.war -d /hello-version/hello-world-war-6.0.0"'
            }
        }
        stage("部署代码") {
            steps {
                sh 'ssh root@172.16.1.7 "rm -f /usr/share/tomcat/webapps/ROOT && ln -s /hello-version/hello-world-war-6.0.0 /usr/share/tomcat/webapps/ROOT "'
            }
        }
        stage("重启服务") {
            steps {
                sh 'ssh root@172.16.1.7 systemctl restart tomcat'
            }
        }
    }
}

# 将更改提交到 Git 仓库
[root@gitlab jenkins-pipelinefile]# git add .
[root@gitlab jenkins-pipelinefile]# git commit -m 'pipelinev1.0'
[master c0cc8b3] pipelinev1.0
 1 file changed, 47 insertions(+)
 create mode 100644 java-maven_pipeline/jenkinsline
[root@gitlab jenkins-pipelinefile]# git tag -a 'v1.0' -m 'v1.0'
[root@gitlab jenkins-pipelinefile]# git push --all
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 871 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To git@gitlab.driverzeng.com:root/pipeline-file.git
   e20f7a0..c0cc8b3  master -> master
[root@gitlab jenkins-pipelinefile]# git push --tag
Counting objects: 1, done.
Writing objects: 100% (1/1), 155 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@gitlab.driverzeng.com:root/pipeline-file.git
 * [new tag]         v1.0 -> v1.0

注意:确保每个 JenkinsFile 文件内有正确的构建、测试和发布流程

4.4、第三步:在 Jenkins 中创建 Pipeline 项目

接下来,我们需要在 Jenkins 服务器上创建一个新的 Pipeline 项目,用于驱动集中仓库中的 JenkinsFile
文件执行。这就像请了一个老师来管理这个幼儿园,负责每天的课程和活动。

  • 登录到 Jenkins 服务器,点击左侧的 “New Item”。
  • 输入项目名称,例如 “java-构建-pipeline”,选择 “Pipeline” 类型,然后点击 “OK”。
  • 在项目配置页面的 Pipeline 部分,选择 “Pipeline script from SCM” 选项,并填写 “jenkinsfile-collection” 项目的仓库地址。

image-20230830172547501

image-20230830173213583

image-20230830173517455

4.5、构建测试

image-20230830174320800

五、pipeline参数化构建

5.1、参数添加

image-20230831164534100

image-20230830203121152

5.2、脚本编写

获取Git仓库路径:

image-20230830203350406

image-20230830203413935

image-20230830203604145

image-20230830203809129

代码如下:

pipeline{
    agent any
    stages{
        stage("下拉代码"){
            steps{
                checkout([$class: 'GitSCM', branches: [[name: "${gittag}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[url: 'git@gitlab.driverzeng.com:root/hello.git']]])
            }
        }
        stage("代码质量检测"){
            steps{
                sh '''/usr/lib/maven/bin/mvn clean verify sonar:sonar \\
                    -Dsonar.projectKey=java \\
                    -Dsonar.projectName='java' \\
                    -Dsonar.host.url=http://10.0.0.83:9000 \\
                    -Dsonar.token=squ_abd87057be010b87265b82779d9342234f3d2065'''
            }
        }
        stage("构建"){
            input {
                message "是否继续构建?"
                ok "构建"
            }
            steps{
                sh '/usr/bin/sh -x /var/lib/jenkins/scripts/pipeline.sh'
            }
        }
    }
}

脚本内容:

[root@jenkins scripts]# vim /var/lib/jenkins/scripts/pipeline.sh
#!/bin/bash
#-----------------------------变量定义-------------------
#版本号
version=$(awk -F '[<> ]' 'NR==6{print $3}' ${WORKSPACE}/pom.xml)
#历史版本目录
his='/hello-version'
#测试:user ip
test_user=root
test_ip=172.16.1.7
#开发:user ip
dev_user=root
dev_ip=172.16.1.8
#生产:user ip
pord_user=root
pord_ip=172.16.1.9

#-----------------------------函数定义---------------------
pull(){
# 检查解压后的目录是否存在同名文件
file_exists=$(ssh $1 "ls ${his}/hello-world-war-${version}")
if [ -z "$file_exists" ]; then
    #文件不存在进入workspacemul 推送至下拉机器
    scp ${WORKSPACE}/target/hello-world-war-${version}.war $1:${his}
    #远端解压
    ssh $1 "unzip -n ${his}/hello-world-war-${version}.war -d ${his}/hello-world-war-${version}"
    sleep 5
    ssh $1 "rm -f /usr/share/tomcat/webapps/ROOT"
    ssh $1 "ln -s ${his}/hello-world-war-${version} /usr/share/tomcat/webapps/ROOT"
    ssh $1  "systemctl restart tomcat"
else
    #跳过解压操作
        sleep 5
    ssh $1 "rm -f /usr/share/tomcat/webapps/ROOT"
    ssh $1 "ln -s ${his}/hello-world-war-${version} /usr/share/tomcat/webapps/ROOT"
    ssh $1  "systemctl restart tomcat"
fi
}

#-----------------------------代码运行----------------------

if [[ $env == test ]]; then
    pull ${test_user}@${test_ip}
elif [[ $env == dev ]]; then
    pull ${dev_user}@${dev_ip}
elif [[ $env == pord ]]; then
    pull ${pord_user}@${pord_ip}
else
    exit
fi

5.3、验证测试

image-20230831170304487

image-20230831170316139