前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DevOps编程操练:用Jenkins流水线建立代码质量预警机制

DevOps编程操练:用Jenkins流水线建立代码质量预警机制

作者头像
程序员吾真本
修改2023-09-23 16:18:36
2.6K1
修改2023-09-23 16:18:36
举报
文章被收录于专栏:程序员吾真本程序员吾真本

解决痛点

  • 不知如何用docker搭建Jenkins操练环境
  • 不知如何开始为Java代码编写自动化单元测试
  • 不知如何将单元测试运行在Jenkins流水线上
  • 不知如何将繁琐的手工Jenkins流水线配置,简化为编写一个Jenkinsfile脚本,并进行版本控制
  • 当流水线出现故障后,不知如何revert导致故障的代码提交,来解决故障

使用docker搭建Jenkins操练环境

当然也可以不用docker,直接在本机安装Jenkins。但对于操练DevOps技能来说,Docker是一个必修项目。所以本操练使用docker来搭建操练环境

本操练是从“CI搭建兽”到“流水线即代码”的升级版,除了使用docker来运行Jenkins之外,还将 Jenkinsfile的写法,从原来的脚本式(以 node 开头),升级为声明式(以 pipeline开头)

安装docker

参见 Install Docker Engine安装Docker

下面以Ubuntu 20.04为例进行操练,其他操作系统操练步骤类同

安装Kitematic

Kitematic是一个为了方便使用docker而精心设计的图形化工具。参见Kitematic发布页面安装Kitematic

安装Jenkins

在Kitematic里下载jenkins/jenkins的image,启动容器并安装Jenkins

打开Kitematic,在搜索框中输入 jenkins来搜索所有Jenkins的镜像。选择镜像名字第一行和第二行都是jenkins的那个镜像。点击CREATE 按钮下载镜像,并启动容器。参见下图

点击 CREATE 按钮下载镜像,并启动容器

点击左上角 jenkins 容器,然后点击右上角 Settings 页签,将容器改名为jenkins-kata ,参见下图

将容器改名为 jenkins-kata

点击右上角 Home 页签,浏览容器的log,等待jenkins重启

在本机创建文件夹~/OOR/docker-volumes/jenkins-kata,并将其配置为docker的volume,以便保存Jenkins运行后的输出文件,且能同时被docker和本机访问。参见下图

设置docker的volume

点击右上角 Home 页签,浏览容器的log,等待jenkins重启

点击右上角 Settings 页签,再点击下面左侧的 Hostname/Ports页签,记下页面左侧中间第一个带有 localhost 的端口号,如下图所示的localhost:32769,然后打开浏览器,在地址栏中访问这个地址和端口号,就能进入Jenkins安装页面,安装Jenkins。安装第一步所需要的admin管理员密码,能在Home页签中的log内容中找到。安装Jenkins插件时,选择默认的即可。参见下图

查看Jenkins运行的端口号

用spring boot编写一个web应用程序并手工测试

本操练的代码和文档参见

devops-katas-jenkins-pipeline-as-code-kata

start.spring.io 下载web空白应用

下载前的选项,参见下面的列表。其中Dependencies添加Web

  • Group: devops.katas
  • Artifact: adminprovider
  • Name: adminprovider
  • Description: Demo project for Jenkins pipeline as code
  • Dependencies: Web

编写adminprovider的Web应用,可以按id号一次返回一位管理员

将刚才下载的adminprovider.zip解压,用IntelliJ IDEA打开该Maven项目,开始编写一个Web应用

为方便起见,本操练所创建的类,都写在AdminproviderAppication类中

首先创建 AdminController

AdminproviderApplication.java.

代码语言:javascript
复制
@RestController
class AdminController {
        @GetMapping("/admin/{id}")
        Admin admin(@PathVariable int id) {
                return new Admin("firstName [" + id + "]", "lastName [" + id + "]");
        }
}

然后创建 Admin类。其中的两个getter是必须的,否则在运行时会报HttpMessageNotWritableException

AdminproviderApplication.java.

代码语言:javascript
复制
class Admin {

        private final String firstName;
        private final String lastName;

        public Admin(String firstName, String lastName) {
                this.firstName = firstName;
                this.lastName = lastName;
        }

        // The public getters are mandatory to fix the issue "org.springframework.http.converter.
        // HttpMessageNotWritableException: No converter found for return value of type:
        // class devops.katas.adminprovider.Admin"
        public String getFirstName() {
                return firstName;
        }

        public String getLastName() {
                return lastName;
        }
}

最后在 application.properties 文件中,添加该Web应用启动的端口号 8765

application.properties.

代码语言:javascript
复制
server.port=8765

此时,在Intellij IDEA中运行 AdminproviderApplication类。然后用浏览器或 HTTPie工具来访问地址localhost:8765/admin/1 。应该能得到1号管理员的姓和名,参见下图

用HTTPie工具访问

编写AdminService的自动化单元测试

为了让Jenkins流水线起到质量预警的作用,必须在上面运行自动化测试,来检测每一次代码push是否有缺陷。让我们先从单元测试开始。

目前要测试的单元,是根据 id 号生成 Admin 对象。这段逻辑写在了AdminController

类中,而这个设计是不好的。因为Controller类本来的用途,是起“传达室”的作用,即将用户的请求,分配给相应的服务来处理。所以良好的设计,应该是把这段逻辑交给AdminService 来处理。而对这段逻辑的单元测试,也就是对 AdminService的单元测试。

第一步,先把上述逻辑交给 AdminService 来处理

AdminproviderApplication.java.

代码语言:javascript
复制
@Configuration
class AdminConfiguration {
        @Bean
        AdminService adminService() {
                return new AdminService();
        }
}

class AdminService {
        public Admin retrieveAdmin(int id) {
                return new Admin("firstName [" + id + "]", "lastName [" + id + "]");
        }
}

@RestController
class AdminController {
        @Autowired
        AdminService adminService;

        @GetMapping("/admin/{id}")
        Admin admin(@PathVariable int id) {
                return adminService.retrieveAdmin(id);
        }

}

第二步,为 AdminService 编写单元测试

AdminServiceTest.java.

代码语言:javascript
复制
class AdminServiceTest {
    @Test
    public void should_retrieve_an_admin_with_correct_names() {
        AdminService adminService = new AdminService();

        Admin admin = adminService.retrieveAdmin(4);

        BDDAssertions.then(admin.getFirstName()).isEqualTo("firstName [4]");
        BDDAssertions.then(admin.getLastName()).isEqualTo("lastName [4]");
    }

}

在IntelliJ IDEA中运行单元测试,应该运行通过

现在可以把上述代码push到码云中,以便后面操练中的Jenkins流水线读取代码来运行自动化测试

可以在码云自己的帐号中,创建一个名为devops-katas-jenkins-pipeline-as-code-kata

的空的代码库。然后在代码根目录中,使用下述命令push代码

代码语言:javascript
复制
git init
git add .
git commit -m "AdminService with a test"
git remote add origin https://gitee.com/wubin28/devops-katas-jenkins-pipeline-as-code-kata.git
git push -u origin master

本文代码的码云地址为 https://gitee.com/wubin28/devops-katas-jenkins-pipeline-as-code-kata.git

下面的任务,就是要把上述单元测试,运行在Jenkins流水线上

在Jenkins界面上编写流水线脚本并运行流水线

虽然本操练的最终目标,是要用Jenkinsfile脚本来定义流水线,但为了调试脚本方便,所以先在Jenkins界面上把脚本调试好,然后再把这些脚本写入Jenkinsfile

创建文件夹

为方便管理操练内容,首先在Jenkins主页上创建jenkins-pipeline-as-code-kata文件夹,以后的操作都在该文件夹中

点击 New Item

点击 New Item

创建文件夹

创建文件夹

不需要配置,直接点 Save

不需要配置,直接点 Save

文件夹创建完毕

文件夹创建完毕

确认Maven与git都已经在Jenkins中配置好

因为运行流水线需要Maven和Git这两个工具,所以需要事先在Jenkins里配置好

进入 Global Tool Configuration 页面

进入 Global Tool Configuration 页面

把Maven命名为M3

把Maven命名为M3

把git命令在Jenkins容器里的路径设置为 /usr/bin/git。这一点可以通过执行命令 docker container exec -it jenkins-katas bash进入容器内部查看,查看有按 Ctrl + PQ 退出

把git命令的路径设置为 /usr/bin/git

创建名为adminprovider的流水线

进入jenkins-pipeline-as-code-kata文件夹,点击 New Item ,创建名为adminprovider 的流水线

创建名为 adminprovider 的流水线

修改流水线的脚本

在流水线配置页面的底部, script 输入框的右上角try sample Pipeline... ,选择 GitHub + Maven

流水线样例脚本,作为修改的基础

选择 GitHub + Maven流水线样例脚本,作为修改的基础

将第13行的git代码库的地址改为本操练的代码库的地址 https://gitee.com/wubin28/devops-katas-jenkins-pipeline-as-code-kata.git

将第13行的git代码库的地址改为本操练的代码库的地址

将第16行的mvn命令,改为./mvnw clean package'。mvnw命令能够在没有安装maven的情况下,运行maven命令。之后,点击 `Save按钮保存

将第16行的mvn命令,改为 ‘./mvnw clean package’

点击 Build Now 手工触发流水线构建。点击左下角 #1 左侧的小圆点,能够跳转到控制台输出页面,观察运行结果。

点击 Build Now 手工触发流水线构建

点击左下角 #1左侧的小圆点,能够跳转到控制台输出页面

如果一切正常,那么构建应该成功。这表明在界面上编写的脚本没有问题。下面可以把这些脚本写到

Jenkinsfile文件中,以便让Jenkins读取该文件中的流水线配置信息。从而实现用Jenkinsfile脚本文件来定义流水线,减轻配置的工作量。

根据脚本创建Jenkinsfile,并配置Jenkins,使其读取Jenkinsfile来运行流水线

因为流水线脚本要从git版本库中读取,需要重新配置,所以现在创建一个名为adminprovider-from-scm新的流水线

创建名为adminprovider-from-scm的流水线

准备好Jenkinsfile

在流水线配置页面的底部, script 输入框的右上角 try sample Pipeline... ,选择 GitHub + Maven

流水线样例脚本,将其内容复制粘贴到代码根目录下新创建的Jenkinsfile文件中,并把其中的git版本库地址和maven命令如上所示更改过来。为了验证Jenkins确实从Jenkinsfile读取了流水线配置,在 steps 第一句增加了 echo 'hello from scm。修改完Jenkinsfile后,就可以点击流水线配置页面底部的 Save按钮,保存配置。

Jenkinsfile.

代码语言:javascript
复制
pipeline {
    agent any

    tools {
        // Install the Maven version configured as "M3" and add it to the path.
        maven "M3"
    }

    stages {
        stage('Build') {
            steps {
                echo 'hello from scm'
                // Get some code from a GitHub repository
                git 'https://gitee.com/wubin28/devops-katas-jenkins-pipeline-as-code-kata.git'

                // Run Maven on a Unix agent.
                sh "./mvnw clean package"

                // To run Maven on a Windows agent, use
                // bat "mvn -Dmaven.test.failure.ignore=true clean package"
            }

            post {
                // If Maven was able to run the tests, even if some of the test
                // failed, record the test results and archive the jar file.
                success {
                    junit '**/target/surefire-reports/TEST-*.xml'
                    archiveArtifacts 'target/*.jar'
                }
            }
        }
    }
}

使用以下命令,将代码push到git版本库

代码语言:javascript
复制
git add .
git commit -m "add Jenkinsfile"
git pull --rebase
git push -u origin master

配置Jenkins使其读取代码库中的Jenkinsfile来配置流水线

进入刚刚创建的流水线 adminprovider-from-scm 配置页面,在页面底部的

Pipeline 配置区域,点击 Definition 下拉框,选择

Pipeline script from SCM

选择Pipeline script from SCM

SCM 下拉框中,选择 Git。在 Repository URL中,填入Jenkinsfile所在的代码库的地址

https://gitee.com/wubin28/devops-katas-jenkins-pipeline-as-code-kata.git。确保Branch Specifier 中填写了 */masterScript Path 中填写了Jenkinsfile 。点击 Save 保存

选择 Git,填写代码库地址

点击 Build Now

手工触发流水线构建,让Jenkins读取代码库中的Jenkinsfile。

点击 Build Now手工触发流水线构建

点击左下角 #1

左侧的小圆点,能够跳转到控制台输出页面,观察运行结果中包含了上面添加的那句 hello from scm 。说明Jenkins确实读取了Jenkinsfile

观察运行结果中包含了上面添加的那句 hello from scm

触发流水线

现在Jenkins能从代码库中读取Jenkinsfile了。这意味着流水线的配置,都可以用有版本控制的脚本来完成。但如果想让Jenkins定时轮询代码库,以便做到频繁小批地构建代码,从而尽早频繁小批地定位代码质量问题,更容易地修复问题,这该如何用脚本实现呢?(当然,使用web hook会比轮询更有优势——能实现代码库一旦有代码push上来,就能通知Jenkins进行构建,从而把频繁小批构建做到极致。有关web hook的操练,我们以后再做)

在jenkinsfile中配置轮询

为了验证Jenkins对代码库的轮询,确实来自Jenkinsfile,可以先打开流水线配置页面中的build

trigger配置,确认没有任何选项被勾选了

打开流水线配置页面中的build trigger配置,确认没有任何选项被勾选了

在Jenkinsfile中的 agent any 下面,添加五个星号的 cron,表示Jenkins每隔1分钟就轮询一次代码库,无论是否有新代码,都会执行构建

代码语言:javascript
复制
triggers {
  cron('* * * * *')
}

使用以下命令,将代码push到git版本库

代码语言:javascript
复制
git commit -am "add triggers with 5 stars into Jenkinsfile"
git pull --rebase
git push -u origin master

点击 Build Now手工触发流水线构建,让Jenkins读取代码库中的Jenkinsfile

确认流水线配置页面中的Build Triggers配置区域中,Build periodically已经被勾选,且五个星出现在 Schedule输入框中。这表明Jenkins确实读取了Jenkinsfile

确认流水线配置页面中的Build Triggers配置区域中,Build periodically已经被勾选,且五个星出现在 Schedule 输入框中

在流水线上引入一个编译错误,并revert来解决问题

现在操练一下当流水线遇到编译错误时,会报什么错

在测试代码中,加一句 abc(); ,然后push代码到代码库

AdminServiceTest.java.

代码语言:javascript
复制
class AdminServiceTest {
    @Test
    public void should_retrieve_an_admin_with_correct_names() {
        abc();
        AdminService adminService = new AdminService();

        Admin admin = adminService.retrieveAdmin(4);

        BDDAssertions.then(admin.getFirstName()).isEqualTo("firstName [4]");
        BDDAssertions.then(admin.getLastName()).isEqualTo("lastName [4]");
    }
}

等1分钟后,流水线被轮询程序自动触发。把鼠标放到有提交的出错构建处,能看到导致这次构建失败的提交人和提交信息。点击相应提交左边的小圆球,能看到具体的错误信息

等1分钟后,流水线被轮询程序自动触发。把鼠标放到有提交的出错构建处,能看到导致这次构建失败的提交人和提交信息

点击相应提交左边的小圆球,能看到具体的错误信息

使用下述命令来查看上次提交的hash号,revert刚才引起流水线故障的提交

代码语言:javascript
复制
git log
git revert 131f54ebb5554aef43fc823d5d8d6fb7aaa8898c
git push

revert并且push,1分钟后,流水线自动构建,故障消失

revert并且push,1分钟后,流水线自动构建,故障消失

在流水线上引入一个自动化单元测试失败,并revert来解决问题

现在操练一下当流水线遇到测试失败时,会报什么错

在测试代码中,将断言中的 firstName [4] 改为 firstName [40],然后push代码到代码库

AdminServiceTest.java.

代码语言:javascript
复制
class AdminServiceTest {
    @Test
    public void should_retrieve_an_admin_with_correct_names() {
        AdminService adminService = new AdminService();

        Admin admin = adminService.retrieveAdmin(4);

        BDDAssertions.then(admin.getFirstName()).isEqualTo("firstName [40]");
        BDDAssertions.then(admin.getLastName()).isEqualTo("lastName [4]");
    }

}

等1分钟后,流水线被轮询程序自动触发。把鼠标放到有提交的出错构建处,能看到导致这次构建失败的提交人和提交信息。点击相应提交左边的小圆球,能看到具体的错误信息

等1分钟后,流水线被轮询程序自动触发。把鼠标放到有提交的出错构建处,能看到导致这次构建失败的提交人和提交信息

点击相应提交左边的小圆球,能看到具体的错误信息

可以使用上面提到的命令来查看上次提交的hash号,revert刚才引起流水线故障的提交

将Jenkinsfile中的cron改为不那么频繁地构建

每分钟构建一次十分耗费资源,所以可以把轮询次数改为工作时间每2小时构建一次

Jenkinsfile.

代码语言:javascript
复制
pipeline {
    agent any

    triggers {
        cron('H H(8-15)/2 * * 1-5')
    }

push代码,1分钟后自动构建,Jenkins会把修改后的轮询配置自动更新到配置页面

作业

操练到此结束。现在该轮到你操练了。可以换一个业务场景操练一下。比如可以将根据id号获取管理员的业务场景,换成根据id号获取学生,从头到尾操练一遍。愿你有所收获

反馈

为了让下次DevOps编程操练让你更有收获,不妨花2分钟填写4个问题

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 解决痛点
  • 使用docker搭建Jenkins操练环境
    • 安装docker
      • 安装Kitematic
        • 安装Jenkins
        • 用spring boot编写一个web应用程序并手工测试
          • 从 start.spring.io 下载web空白应用
            • 编写adminprovider的Web应用,可以按id号一次返回一位管理员
            • 编写AdminService的自动化单元测试
            • 在Jenkins界面上编写流水线脚本并运行流水线
              • 创建文件夹
                • 确认Maven与git都已经在Jenkins中配置好
                  • 创建名为adminprovider的流水线
                    • 修改流水线的脚本
                    • 根据脚本创建Jenkinsfile,并配置Jenkins,使其读取Jenkinsfile来运行流水线
                      • 准备好Jenkinsfile
                        • 配置Jenkins使其读取代码库中的Jenkinsfile来配置流水线
                        • 触发流水线
                          • 在jenkinsfile中配置轮询
                          • 在流水线上引入一个编译错误,并revert来解决问题
                          • 在流水线上引入一个自动化单元测试失败,并revert来解决问题
                          • 将Jenkinsfile中的cron改为不那么频繁地构建
                          • 作业
                          • 反馈
                          相关产品与服务
                          容器镜像服务
                          容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档