Loading

Jenkins CI&CD 自动化发布项目实战(下篇)

 

 

 

 

 

 

Jenkins CI&CD 自动化发布项目实战(下篇)

 

 

 

 

 

 

 

作者

刘畅

时间

2020-12-04

 

 

实验环境

centos7.5

主机

ip

服务配

gitlab

172.16.1.71

2/4G/60G

dockergitlab

jenkins-master

172.16.1.72

2/4G/60G

dockerjdkmavenjenkins

jenkins-slave01

172.16.1.73

2/2G/60G

jdkmavenansible

java-web01

172.16.1.74

2/2G/60G

jdktomcat

java-web02

172.16.1.75

2/2G/60G

jdktomcat

说明:本文dockergitlab的安装就不赘述了,可以参考其它专题文档。

 

 

 

 

 

 

 

目录

1 Pipeline介绍 1

2 Pipeline语法 1

2.1 声明式流水线语法 1

2.2 脚本式流水线语法 2

2.3 生成Pipeline脚本 2

3 Pipeline指令 3

3.1 指令示例网址 3

3.2 常用指令 3

3.3 流水线脚本与源代码一起版本管理 4

4 流水线发布Java网站项目 4

4.1 前提条件 5

4.2 流水线代码 6

4.3 Build with Parameters 7

5 Gitlab Webhooks自动触发发布 9

5.1 安装gitlab插件 9

5.2 Jenkins项目里配置触发器生成URLToken 9

5.3 gitlab项目Webhooks中配置URLToken 10

5.4 测试 11

6 集成Ansible发布多台服务器及项目回滚 11

6.1 前提条件 11

6.2 发布项目 12

6.3 回滚项目 14

6.4 测试 16

7 Jenkins备份与恢复 17

7.1 方式一、备份数据目录 17

7.2 方式二、Thinbackup 17

8 补充 19

8.1 Blue Ocean 19

8.2 修改jenkins时区的方法 20


1 Pipeline介绍

1 Jenkins Pipeline是一套运行工作流框架,将原本独立运行单个或者多个节点的任务链接起来,实现单个任务难以完成的复杂流程编排和可视化。

2 Jenkins Pipeline是一套插件,支持在Jenkins中实现持续集成和持续交付。

3 Pipeline通过特定语法对简单到复杂的传输管道进行建模。

4 Jenkins Pipeline的定义被写入一个文本文件,称为Jenkinsfile

wps1 

5 安装pipeline插件

wps2 

2 Pipeline语法

2.1 声明式流水线语法

Jenkinsfile(Declarative Pipeline)

pipeline {

    agent any

    stages {

        stage('Build') {

            steps {

                echo 'Build'

            }

        }

        stage('Test') {

            steps {

                echo 'Test'

            }

        }

        stage('Deploy') {

            steps {

                echo 'Deploy'

            }

        }

    }

}

 

说明:

支持大部分Groovy,具有丰富的语法特性,易于编写和设计。

(1) Stages

阶段,是Pipeline中最主要的组成部分,Jenkins将会按照Stages中描述的顺序从上往下的执行。

包含一系列一个或多个stage指令, stages部分是流水线描述的大部分"work" 的位置。

(2) Stage

阶段,一个Pipeline可以划分为若干个 Stage,每个Stage代表一组操作,比如:BuildTestDeploy

(3) Steps

步骤,Steps是最基本的操作单元,可以是打印一句话,也可以是构建一个Docker镜像,由各类Jenkins插件提供,比如命令:sh 'mvn',就相当于我们平时

shell终端中执行mvn命令一样。

steps 部分在给定的 stage 指令中执行的定义了一系列的一个或多个steps

2.2 脚本式流水线语法

Jenkinsfile(Scripted Pipeline)

node {

    stage('Build') {

        echo 'Build'

    }

    stage('Test') {

        echo 'Test'

    }

    stage('Deploy') {

        echo 'Deploy'

    }

}

 

说明:

遵循与Groovy相同语法。

2.3 生成Pipeline脚本

1 创建Pipeline项目,在底部生成示例。

2 最后使用生成器生成Pipeline片段,完善Pipeline脚本。

wps3 

3 Pipeline指令

3.1 指令示例网址

https://www.jenkins.io/zh/doc/book/pipeline/syntax/#parameters-example

3.2 常用指令

指令

描述

定义位置

生成方法(Declarative Directive Generator)

agent

指定流水线的执行节点

pipeline块的顶层被定义

agent: Agent

options

流水线选项,一般用于设置阶段超时时间

pipeline块的顶层或stage定义

options: Options

environment

定义所有步骤的环境变量,或者特定步骤

pipeline块的顶层被定义

environment: Environment

parameters

触发流水线时提供的参数列表

pipeline块的顶层被定义

parameters: Parameters

triggers

自动化触发

pipeline块的顶层被定义

triggers: Triggers

tools

使用配置的工具,只支持mavenjdkgradle

pipeline块的顶层被定义

tools: Tools

input

用户交互输入

stage定义

input: Input

post

流水线执行完成后执行

pipeline块的底层被定义

post: Post Stage or Build Conditions

 

指令

描述

定义位置

生成方法(片段生成器)

script

使用脚本式语法

steps定义

script: Run arbitrary Pipeline script

sh

shell命令

steps定义

sh: Shell Script

withCredentials

从凭据中读取数据并赋值变量

steps定义

withCredentials: Bind credentials to variables

checkout

从版本仓库种拉取代码

steps定义

checkout: Check out from version control

ansiblePlaybook

 

 

ansiblePlaybook: Invoke an ansible playbook

sshPublisher

通过ssh方式拷贝构建文件到远程服务器

steps定义

sshPublisher: Send build artifacts over SSH

 

(1) pipeline引用变量一定要使用双引号,与shell中引用变量方法相同"$变量名"

(2) pipeline配置的parameters参数会将功能解析到页面上显示。

(3) scriptif语句在括号内引用变量时可以不加$

(4) 流水线写好后第一次构建(pipeline初始化)时可能因没有构建参数可选,会出现构建错误,第二次

再构建时就好了。

(5) pipeline shell命令中,如果自己定义了变量,在引时,$需要进行转义,引用jenkins中的

变量不需要加转义。

3.3 流水线脚本与源代码一起版本管理

Jenkinsfile文件建议与源代码一起版本管理,实现流水线即代码(Pipeline as Code)

这样做的好处:

(1) 自动为所有分支创建流水线脚本。

(2) 方便流水线代码复查、追踪、迭代。

(3) 可被项目成员查看和编辑。

wps4 

4 流水线发布Java网站项目

基于ssh远程拷贝项目文件发布到远程服务器

wps5 

4.1 前提条件

1 配置通过免交互,秘钥方式连接远程应用服务器(公钥要发送到远程应用服务器上)

Manage Jenkins -> Configure System -> Publish over SSH

wps6 

 

2 配置连接gitlab的的全局凭证(用户名、密码方式)

Manage Jenkins -> Manage Credentials -> 凭据

wps7 

 

3 创建项目名为java-mall-pipelinejenkins项目,gitlab依然使用上篇实验的java项目。

4.2 流水线代码

pipeline {

    agent {

        label 'jenkins-slave01'

    }

    environment {

        gitlab_address = "http://172.16.1.71/java-project/java-mall.git"

        gitlab_auth = "c1ba4aa8-f310-45e7-9939-bc1967a32d79"

        publish_host = "java-web01"

    }

    parameters {

        gitParameter branch: '', branchFilter: 'origin/(.*)', defaultValue: 'master', description: '请选择要发布的分支名称', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH'

    }

    stages {

        stage('拉取代码') {

            steps {

                checkout([$class: 'GitSCM', branches: [[name: "${params.Branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${gitlab_auth}", url: "${gitlab_address}"]]])

            }

        }

        stage('编译构建') {

            steps {

                sh "/usr/local/maven/bin/mvn clean package -Dmaven.test.skip=true"

            }

        }

        stage('拷贝构建文件到远程主机并部署') {

            steps {

                sshPublisher(publishers: [sshPublisherDesc(configName: "${publish_host}", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''#!/bin/bash

                # 备份已部署的程序

                tomcat=/usr/local/tomcat/webapps

                BACKUP_DIR=/data/backup

                [ ! -d $BACKUP_DIR ] && mkdir -p $BACKUP_DIR

                [ -f $tomcat/*.war ] && mv $tomcat/*.war $BACKUP_DIR/$(date +"%F_%T")_ROOT.war

                # 部署新程序并重启Tomcat

                [ -d $tomcat/ROOT ] && rm -rf $tomcat/ROOT

                mv /tmp/$JOB_NAME/*.war $tomcat/ROOT.war

                pid=$(ps -ef |grep $tomcat |egrep -v \'grep\' |awk \'{print $2}\')

                [ -n "$pid" ] && kill -9 $pid

                export JAVA_HOME=/usr/local/jdk

                /usr/local/tomcat/bin/startup.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'tmp/$JOB_NAME', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/*.war')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])

            }

        }

    }

}

 

 

// 说明:

// 以上脚本只要修改环境变量(environment)中的内容即可。

4.3 Build with Parameters

wps8 

 

4.4 查看控制台输出

wps9 

5 Gitlab Webhooks自动触发发布

5.1 安装gitlab插件

wps10 

5.2 Jenkins项目里配置触发器生成URLToken

java-mall-pipeline项目

wps11 

5.3 gitlab项目Webhooks中配置URLToken

java-mall项目

wps12 

 

报错说明:

wps13 

解决办法:

管理中心 -> 设置 -> 网络 -> 外发请求

wps14 

5.4 测试

gitlab中修改java-mall项目的代码并提交后,发现jenkinsjava-mall-pipline项目自动进行

构建及发布项目的操作,说明配置成功。

 

构建历史显示为gitlab推送

wps15 

6 集成Ansible发布多台服务器及项目回滚

wps16 

6.1 前提条件

1 配置通过免交互,秘钥方式连接远程应用服务器(公钥发送到远程应用服务器)的凭据,供ansiable使用,在172.16.1.73节点上安装ansiable

wps17 

2 配置连接gitlab的全局凭证(用户密码方式),方便连接gitlab

wps18 

3 配置连接jenkins的全局凭证(用户密码方式),方便应用服务器发送代码版本文件。

wps19 

4 远程应用服务器上要安装sshpass包,方便应用服务器免交互发送代码版本文件

6.2 发布项目

1 说明:

创建项目名为java-mall-pipelinejenkins项目,gitlab依然使用上篇实验的java项目。

 

2 pipeline脚本

pipeline {

    agent {

        label "jenkins-slave01"

    }

    environment {

        gitlab_address = "http://172.16.1.71/java-project/java-mall.git"

        // gitlab的地址

        gitlab_auth = "c1ba4aa8-f310-45e7-9939-bc1967a32d79"

        // 连接gitlab的凭证

        ansible_ssh_auth = "d0651139-bbea-403a-9543-4f404e4778dd"

        // ansiable免交互连接远程服务的凭证

        jenkins_auth = "4061843c-c6dd-4b97-b986-94cbaa72fa3e"

        // 远程服务器向jenkins发送代码版本的凭证

    }

    parameters {

        gitParameter branch: '', branchFilter: 'origin/(.*)', defaultValue: 'master', description: '请选择要发布的分支名称', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH'

        choice choices: ['java-web01', 'java-web02'], description: '''请选择要发布的服务器组

        [java-web01]

        172.16.1.74

        [java-web02]

        172.16.1.75''', name: 'Servers'

    }

    stages {

        stage('拉取代码') {

            steps {

                checkout([$class: 'GitSCM', branches: [[name: "${params.Branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${gitlab_auth}", url: "${gitlab_address}"]]])

            }

        }

        stage('编译构建') {

            steps {

                sh "/usr/local/maven/bin/mvn clean package -Dmaven.test.skip=true"

            }

        }

        stage('拷贝构建文件到远程主机并部署') {

            steps {

                // 读取连接Jenkins服务器用户名和密码

                withCredentials([usernamePassword(credentialsId: "${jenkins_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {

                // ===========================================

                sh """

###################### 主机清单文件 ############################

cat > /opt/jenkins_home/.hosts << EOF

[java-web01]

172.16.1.74

[java-web02]

172.16.1.75

EOF

###################### Playbook文件 ############################

cat > /opt/jenkins_home/.playbook.yaml << "EOF"

- hosts: $Servers       # Jenkins参数化变量

  gather_facts: no

  vars:             # 定义playbook变量,下面{{}}引用这里的变量

    workspace: $WORKSPACE   # WORKSPACEBUILD_NUMBER引用Jenkins变量

    job_name: $JOB_NAME

    tomcat_dir: "/usr/local/tomcat/webapps"  # 自定义变量

    tomcat: "/usr/local/tomcat"

    backup_dir: "/data/backup"

    backup_filename: "{{ job_name }}_ROOT_\$(date +%F)_${BUILD_NUMBER}.war"  # 格式:项目名_文件名_日期_构建编号

    jenkins_ip: "172.16.1.72"

    username: $username

    password: $password

  tasks:

  - name: 在远程服务器上创建项目目录

    file:

      dest: /tmp/{{ job_name }}

      state: directory

  - name: 推送部署包到远程服务器

    copy: src="{{ item }}" dest=/tmp/{{ job_name }}

    with_fileglob:

      - "{{ workspace }}/target/*.war"

  - name: 部署新程序并重启Tomcat

    shell: |

      # 备份已部署的程序

      [ ! -d {{ backup_dir }} ] && mkdir -p {{ backup_dir }}

      [ -f {{ tomcat_dir }}/*.war ] && mv {{ tomcat_dir }}/*.war {{ backup_dir }}/{{ backup_filename }}

      # 部署新程序并重启Tomcat

      [ -d {{ tomcat_dir }}/ROOT ] && rm -rf {{ tomcat_dir }}/ROOT

      mv /tmp/{{ job_name }}/*.war {{ tomcat_dir }}/ROOT.war

      pid=\$(ps -ef |grep {{ tomcat }} |egrep -v 'grep' |awk '{print \$2}')

      [ -n "\$pid" ] && kill -9 \$pid

      export JAVA_HOME=/usr/local/jdk

      nohup /usr/local/tomcat/bin/startup.sh &

      ls {{ backup_dir }} |sort -t '_' -k 4 -rn |head -n5 |awk 'BEGIN{printf "version="}{printf \$0","}' > /tmp/{{ job_name }}/backup_version.txt

      sshpass -p{{ password }} scp -o StrictHostKeychecking=no -p /tmp/{{ job_name }}/backup_version.txt {{ username }}@{{ jenkins_ip }}:/opt/jenkins_home

EOF

                """

                // ===========================================

                }

              ansiblePlaybook(

                  playbook: '/opt/jenkins_home/.playbook.yaml',

                  inventory: '/opt/jenkins_home/.hosts',

                  credentialsId: "${ansible_ssh_auth}"

                )

            }

        }

    }

}

 

 

// 说明:

// 以上脚本只要修改环境变量(environment)中的内容和要发布的主机组清单即可。

 

3 Build with Parameters

wps20 

6.3 回滚项目

1 说明:

创建项目名为java-mall-pipeline_rollbackjenkins项目,回滚的是备份目录/data/backup下的备

份代码。

 

2 pipeline脚本

pipeline {

    agent {

        label "jenkins-slave01"

    }

    environment {

        ansible_ssh_auth = "d0651139-bbea-403a-9543-4f404e4778dd"

        // ansiable免交互连接远程服务的凭证

    }

    parameters {

      extendedChoice description: '请选择回滚的备份版本', multiSelectDelimiter: ',', name: 'BackupVersion', propertyFile: '/var/jenkins_home/backup_version.txt', propertyKey: 'version', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_SINGLE_SELECT', visibleItemCount: 5

    choice choices: ['java-web01', 'java-web02'], description: '''请选择要回滚的服务器组

         [java-web01]

         172.16.1.74

         [java-web02]

         172.16.1.75''', name: 'Servers'

    }

    stages {

        stage('回滚') {

            steps {

                sh """

###################### 主机清单文件 ############################

cat > /opt/jenkins_home/.hosts << EOF

[java-web01]

172.16.1.74

[java-web02]

172.16.1.75

EOF

###################### Playbook文件 ###########################

cat > /opt/jenkins_home/.playbook.yaml << "EOF"

- hosts: $Servers

  gather_facts: no

  vars:

    tomcat_dir: "/usr/local/tomcat/webapps"

    tomcat: "/usr/local/tomcat"

    backup_dir: "/data/backup"

    rollbak_dir: "/data/backup/rollback"

    backup_filename: $BackupVersion

  tasks:

  - name: 使用备份文件重新部署

    shell: |

      # 备份已部署的程序

      [ ! -d {{ rollbak_dir }} ] && mkdir -p {{ rollbak_dir }}

      mv {{ tomcat_dir }}/ROOT.war {{ rollbak_dir }}/ROOT-\$(date +%F-%T).war

      # 部署备份程序并重启Tomcat

      [ -d {{ tomcat_dir }}/ROOT ] && rm -rf {{ tomcat_dir }}/ROOT

      cp {{ backup_dir }}/{{ backup_filename }} {{ tomcat_dir }}/ROOT.war

      pid=\$(ps -ef |grep {{ tomcat }} |egrep -v 'grep' |awk '{print \$2}')

      [ -n "\$pid" ] && kill -9 \$pid

      export JAVA_HOME=/usr/local/jdk

      nohup {{ tomcat }}/bin/startup.sh &

EOF

                """

                // ===========================================

            ansiblePlaybook(

                  playbook: '/opt/jenkins_home/.playbook.yaml',

                  inventory: '/opt/jenkins_home/.hosts',

                  credentialsId: "${ansible_ssh_auth}"

                )

            }

        }

    }

}

 

 

// 说明:

// 以上脚本只要修改环境变量(environment)中的内容和要发布的主机组清单即可。

 

3 Build with Parameters

wps21 

6.4 测试

1 发布项目

先发布两次项目(第一次因为webapps中没有项目,所以/data/backup目录下没有备份项目)

2 回滚项目

可以看到参数化构建中有备份的项目可供选择。

7 Jenkins备份与恢复

7.1 方式一、备份数据目录

1 如果是基于jenkins war包安装的jenkins,备份目录为"/root/.jenkins/"

2 如果是基于docker方式安装的jenkins,备份目录为jenkins的持久化家目录(/opt/jenkins_home/)

7.2 方式二、Thinbackup

1 安装插件

wps22 

 

2 Manage Jenkins -> ThinBackup

wps23 

 

3 备份设置(Settings)

创建jenkins的备份目录,该目录必须存在

# mkdir -p /opt/jenkins_home/backup

wps24 

jenkins备份的主要是"系统配置""job""jenkins插件"即可。

参考文档:https://wiki.jenkins.io/pages/diffpagesbyversion.action?pageId=49512461&originalVersion=19&revisedVersion=48

 

4 备份测试

(1) 点击Backup Now手动进行备份

(2) 查看备份内容

# ls -ld /opt/jenkins_home/jenkins_backup/

drwxr-xr-x 6 root root 4096 Dec  3 14:35 FULL-2020-12-03_14-35

(3) 还原备份到新的jenkins服务器上

1) thinBackup插件中设置备份文件所在的目录。

2) 点击Restore还原备份(注意:要耐心等待备份的完成)

wps25 

3) 备份还原后重启jenkins后生效,jenkins的系统设置和创建的jenkins项目都在。

重启:Manage Jenkins -> Reload Configuration from disk

注意:

A 此时jenkins-slave可能会出现断联的状态,需要进行从新配置连接。

B 插件可能会报依赖问题,安装缺少的依赖。

C 拉取gitlab代码的配置会报如下错误,需要重新配置gitlab的全局用户凭证信息即可。wps26

以上jenkins备份后还原到的是新的jenkins服务器,如果是还原到原有的jenkins服务器上不会

出现以上注意点。

8 补充

8.1 Blue Ocean

1 安装插件

wps27 

2 什么是Blue Ocean

https://www.jenkins.io/zh/doc/book/blueocean/

(1) Blue Ocean 重新思考Jenkins的用户体验,从头开始设计Jenkins Pipeline, 但仍然与自由式作业兼容,Blue Ocean减少了混乱而且进一步明确了团队中每个成员。

(2) Blue Ocean 的主要特性包括

1) 持续交付(CD)Pipeline的复杂可视化,可以让您快速直观地理解管道状态。

2) Pipeline 编辑器 - 引导用户通过直观的、可视化的过程来创建Pipeline,从而使Pipeline的创建变得平易近人。

3) 个性化以适应团队中每个成员不同角色的需求。

4) 在需要干预或出现问题时精确定位。 Blue Ocean展示Pipeline中需要关注的地方,简化异常处理,提高生产力。

5) 本地集成分支和合并请求, 在与GitHubBitbucket中的其他人协作编码时实现最大程度的开发人员生产力。

 

3 视图

wps28 

8.2 修改jenkins时区的方法

查看系统设置:http://172.16.1.72:8080/systemInfo

jenkins默认使用UTC时间,想要修改为CST时间,按如下步骤操作:

1 临时生效

(1) 打开【系统管理】->【脚本命令行】运行下面的命令

(2) System.setProperty('org.apache.commons.jelly.tags.fmt.timeZone', 'Asia/Shanghai')

 

2 永久生效

docker run ... -e JAVA_OPTS=-Duser.timezone=Asia/Shanghai

示例:

docker run -d --name jenkins -p 8080:8080 -p 50000:50000 -u root \

-v /opt/jenkins_home:/var/jenkins_home \

-v /var/run/docker.sock:/var/run/docker.sock \

-v /usr/bin/docker:/usr/bin/docker \

-v /usr/local/maven:/usr/local/maven \

-v /usr/local/jdk:/usr/local/jdk \

-v /etc/localtime:/etc/localtime \

--restart=always \

-e JAVA_OPTS=-Duser.timezone=Asia/Shanghai \

--name jenkins jenkins/jenkins:lts

 

3 补充

(1) 通过jenkins RPM包安装的jenkins

# vim /etc/sysconfig/jenkins

JENKINS_JAVA_OPTIONS="-Duser.timezone=Asia/Shanghai"

 

(2) 通过jenkins war包安装的jenkins

# vim /usr/local/tomcat/bin/catalina.sh

wps29 

JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

补充:

# jenkinsroot用户运行,也可以不写

export JENKINS_USER="root"

 

(3) 通过系统设置时区

参考文档:https://www.jenkins.io/doc/book/using/change-time-zone/

# 您可能需要更改显示的时区以匹配您自己的时区。通过转到用户配置页面,可以将

# 设置User Defined Time Zone为与您自己的匹配。

wps30 

 

wps31 

posted @ 2021-04-26 12:35  云起时。  阅读(350)  评论(0编辑  收藏  举报