同步操作将从 wubin28/devops-kata-jenkins-pipeline-as-code 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
代码上线故障多
不知如何用docker搭建Jenkins操练环境
不知如何开始为Java代码编写自动化单元测试
不知如何将单元测试运行在Jenkins流水线上
不知如何将繁琐的手工Jenkins流水线配置,简化为编写一个Jenkinsfile脚本,并进行版本控制
当流水线出现故障后,不知如何revert导致故障的代码提交,来解决故障
下载前的选项,参见下面的列表。其中Dependencies添加Web
Group: devops.katas
Artifact: adminprovider
Name: adminprovider
Description: Demo project for Jenkins pipeline as code
Dependencies: Web, Lombok
因为把maven中的Java版本设置为11后,在Jenkins里运行会报错,所以需要把pom.xml文件中的 java.version
从 11
改为 1.8
将刚才下载的adminprovider.zip解压,用IntelliJ IDEA打开该Maven项目,开始编写一个Web应用
为方便起见,本操练所创建的类,都写在AdminproviderAppication类中
首先创建 AdminController
类
@RestController
class AdminController {
@GetMapping("/admin/{id}")
Admin admin(@PathVariable int id) {
return new Admin("First" + id, "Last" + id);
}
}
然后创建 Admin
类。
@Data
@AllArgsConstructor
class Admin {
private String firstName;
private String lastName;
}
最后在 application.properties
文件中,添加该Web应用启动的端口号 8765
server.port=8765
此时,在Intellij IDEA中运行 AdminproviderApplication
类。然后用浏览器或 HTTPie工具来访问地址 localhost:8765/admin/1
。应该能得到1号管理员的姓和名,参见下图
为了让Jenkins流水线起到质量预警的作用,必须在上面运行自动化测试,来检测每一次代码push是否有缺陷。让我们先从单元测试开始。
目前要测试的单元,是根据 id
号生成 Admin
对象。这段逻辑写在了 AdminController
类中,而这个设计是不好的。因为Controller类本来的用途,是起“传达室”的作用,即将用户的请求,分配给相应的服务来处理。所以良好的设计,应该是把这段逻辑交给 AdminService
来处理。而对这段逻辑的单元测试,也就是对 AdminService
的单元测试。
第一步,先把上述逻辑交给 AdminService
来处理
@Configuration
class AdminConfiguration {
@Bean
AdminService adminService() {
return new AdminService();
}
}
class AdminService {
public Admin retrieveAdmin(int id) {
return new Admin("First" + id, "Last" + id);
}
}
@RestController
class AdminController {
@Autowired
AdminService adminService;
@GetMapping("/admin/{id}")
Admin admin(@PathVariable int id) {
return adminService.retrieveAdmin(id);
}
}
第二步,为 AdminService
编写单元测试
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("First4");
BDDAssertions.then(admin.getLastName()).isEqualTo("Last4");
}
}
在IntelliJ IDEA中运行单元测试,应该运行通过
在命令行上运行命令 mvn clean test
,单元测试也应该运行通过
当然也可以不用docker,直接在本机安装Jenkins。但对于操练DevOps技能来说,Docker是一个必修项目。所以本操练使用docker来搭建操练环境
本操练是 从“CI搭建兽”到“流水线即代码” 的升级版,除了使用docker来运行GitLab和Jenkins之外,还将 Jenkinsfile
的写法,从原来的脚本式(以 node
开头),升级为声明式(以 pipeline
开头)
实测表明,如果将GitLab和Jenkins同时运行在同一台电脑的两个docker容器里,无论电脑的内存是8G还是16G,两者都会运行很慢。所以推荐把Jenkins和GitLab分别运行在两台电脑的docker容器中,且每台电脑的内存至少8G
本操练使用ubuntu和mac这两台电脑,其中
ubuntu电脑(ip地址:192.168.71.244)的容器中安装了GitLab
mac电脑(ip地址:192.168.71.243)的容器中安装了Jenkins
下面以Ubuntu 20.04及Mac为例进行操练,其他操作系统操练步骤类同
参见 Install Docker Engine ,在两台电脑上安装Docker
Kitematic是一个为了方便使用docker而精心设计的图形化工具。参见 Kitematic发布页面 ,在两台电脑上安装Kitematic
安装好docker后,在mac电脑的命令行运行以下命令,就能下载并启动jenkins容器。其中 ~/docker-volumes/jenkins
文件夹是我的个人目录,需要替换成你的本机某个目录。 Bins-MacBook-Pro.local
是我的电脑的主机名,也需要换成你的主机名
docker run --detach --hostname Bins-MacBook-Pro.local --publish 8080:8080 --publish 50000:50000 --name jenkins -v ~/docker-volumes/jenkins:/var/jenkins_home jenkins/jenkins
打开Kitematic,查看jenkins是否已经运行起来。如果已经运行起来,就可以在浏览器中访问 http://localhost:8080/
,进入Jenkins安装页面,安装Jenkins。安装第一步所需要的admin管理员密码,能在Kitematic的 Home
签中的log内容中找到。安装Jenkins插件时,选择默认的即可。
由于GitLab运行所需要的80端口已经被ubuntu上的apache2占用了,所以需要运行命令 sudo service apache2 stop
先把apache2停掉
在ubuntu电脑的命令行运行以下命令,就能下载并启动GitLab容器。其中以 ~/docker-volumes/gitlab/
开头的文件夹是我的个人目录,需要替换成你的本机某个目录。 ben-ZenBook-UX393EA-UX3000EA
是我的电脑的主机名,也需要换成你的主机名
docker run --detach --hostname ben-ZenBook-UX393EA-UX3000EA --publish 443:443 --publish 80:80 --publish 22:22 --name gitlab -v ~/docker-volumes/gitlab/etc:/etc/gitlab -v ~/docker-volumes/gitlab/var-log:/var/log/gitlab -v ~/docker-volumes/gitlab/var-opt:/var/opt/gitlab gitlab/gitlab-ce:latest
安装完成后,在浏览器中访问 http://localhost:80/
,就能进入GitLab页面,设置 root用户密码。然后注册一个用户,并以该用户身份登录GitLab
登录GitLab后,进入用户的 Settings
页面,创建 Access Token
,并记录下来,以便后面设置webhook时使用。下面是我创建Access Token时使用的参数:
Name: token-for-asus-3
expires at: 2023-11-30
Scopes: (全部勾选5个scope)
点击 Create personal access token
进行创建,然后把页面顶部 Your new personal access token
下面的值记录下来,以备后用。我的access token是 pHt2XifyorWQeFTHs8e-
现在可以在GitLab中,创建一个名为 devops-kata-jenkins-pipeline-as-code
的空的项目,然后把前面编写的代码push到该项目中,以便后面操练中的Jenkins流水线读取代码来运行自动化测试。下面是我创建该项目时填的参数:
Project Name: devops-kata-jenkins-pipeline-as-code
Visibility Level: Public
点击 Create Project
按钮,创建代码库
要将代码push到GitLab,需要把你的代码所在的电脑的ssh key配置到GitLab中,以便push代码
点击 Add SSH key
按钮,进入 SSH Keys
页面
此时,在命令行窗口运行命令 ls ~/.ssh/
查看电脑上的ssh key。如果没有发现 id_ed25519.pub
或 id_rsa.pub
文件,那么推荐优先用以下命令创建ED25519 ssh key (比下面的RSA ssh key更安全高效),把其中的 email@company.com
换成你的email
ssh-keygen -t ed25519 -C "email@company.com>"
也可以用以下命令创建RSA ssh key,把其中的 email@company.com
换成你的email
ssh-keygen -t rsa -b 2048 -C "email@company.com>"
再次在命令行窗口运行命令 ls ~/.ssh/
查看电脑上的ssh key,此时就能看到 id_ed25519.pub
或 id_rsa.pub
文件了
现在可以在 SSH Keys
页面,创建ssh key了。下面是我创建时使用的参数
Key: (先运行 cat ~/.ssh/id_ed25519.pub
,然后把该命令的输出内容复制粘贴到此次)
Title: For TW-MacBookPro-3
Expires at: 2023/11/30
点击 Add Key
按钮创建ssh key
下面push代码的命令中的 192.168.71.244
是我的ubuntu电脑ip地址,需要换成你的电脑ip
git init
git add .
git commit -m "AdminService with a test"
git remote add origin git@192.168.71.244:wuzhenben/devops-kata-jenkins-pipeline-as-code.git
git push -u origin master
下面的任务,就是要把GitLab中的单元测试,运行在Jenkins流水线上
虽然本操练的一个目标,是要用保存在GitLab中进行版本化管理的Jenkinsfile脚本来定义流水线,但为了调试脚本方便,所以先在Jenkins界面上把脚本调试好,然后再把这些脚本写入Jenkinsfile
为方便管理操练内容,首先在Jenkins主页上创建 jenkins-pipeline-as-code-kata
文件夹,以后的操作都在该文件夹中
点击 New Item
New Item
创建文件夹
不需要配置,直接点 Save
文件夹创建完毕
因为运行流水线需要Maven和Git这两个工具,所以需要事先在Jenkins里配置好
进入 Global Tool Configuration
页面
Global Tool Configuration
页面把Maven命名为M3
把git命令在Jenkins容器里的路径设置为 /usr/bin/git
。这一点可以通过执行命令 docker container exec -it jenkins bash
进入容器内部查看,查看有按 Ctrl + PQ
退出
/usr/bin/git
进入jenkins-pipeline-as-code-kata文件夹,点击 New Item
,创建名为 adminprovider
的流水线
adminprovider
的流水线在流水线配置页面的底部, script
输入框的右上角 try sample Pipeline…
,选择 GitHub + Maven
流水线样例脚本,作为修改的基础
GitHub + Maven
流水线样例脚本,作为修改的基础将第13行的git代码库的地址改为本操练的代码库的地址 http://username:pHt2XifyorWQeFTHs8e-@192.168.71.244/wuzhenben/devops-kata-jenkins-pipeline-as-code.git
其中, 192.168.71.244
是我的ubuntu电脑ip地址,需要替换成你的电脑地址
将第16行的mvn命令,改为 ./mvnw -s /var/jenkins_home/maven/settings.xml clean package
。
mvnw命令能够在没有安装maven的情况下,运行maven命令。之后,点击 Save
按钮保存
/var/jenkins_home/
对应mac电脑的 ~/docker-volumes/jenkins/
目录,这已经在上面在mac电脑上所运行的docker run命令中的 -v
参数设置好了。这种volume的设置,能在你的电脑上设置一个文件夹,供docker和你的电脑操作系统共同访问,方便使用
/maven/settings.xml
其实是把电脑本地的带有阿里云maven镜像的settings.xml文件,复制过来,加快构建的速度
而 ./mvnw -s
命令,就能读取后面跟随的settings.xml文件
点击 Build Now
手工触发流水线构建。点击左下角 #1
左侧的小圆点,能够跳转到控制台输出页面,观察运行结果。
Build Now
手工触发流水线构建#1
左侧的小圆点,能够跳转到控制台输出页面如果一切正常,那么构建应该成功。这表明在界面上编写的脚本没有问题。下面可以把这些脚本写到 Jenkinsfile
文件中,以便让Jenkins读取该文件中的流水线配置信息。从而实现用Jenkinsfile脚本文件来定义流水线,减轻配置的工作量。
因为流水线脚本要从git版本库中读取,需要重新配置,所以现在创建一个名为 adminprovider-from-scm
新的流水线
在流水线配置页面的底部, script
输入框的右上角 try sample Pipeline…
,选择 GitHub + Maven
流水线样例脚本,将其内容复制粘贴到代码根目录下新创建的Jenkinsfile文件中,并把其中的git版本库地址和maven命令如上所示更改过来。为了验证Jenkins确实从Jenkinsfile读取了流水线配置,在 steps
第一句增加了 echo 'hello from scm
。修改完Jenkinsfile后,就可以点击流水线配置页面底部的 Save
按钮,保存配置。
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 'http://username:pHt2XifyorWQeFTHs8e-@192.168.71.244/wuzhenben/devops-kata-jenkins-pipeline-as-code.git'
// Run Maven on a Unix agent.
sh "./mvnw -s /var/jenkins_home/maven/settings.xml 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'
}
}
}
}
}
上面代码中的 http://username:pHt2XifyorWQeFTHs8e-@
包含了前面配置的GitLab的 access token。如果没有这个token,那么在Jenkins里构建时会报 Authentication failed
错误
使用以下命令,将代码push到git版本库
git add .
git commit -m "add Jenkinsfile"
git pull --rebase
git push -u origin master
进入刚刚创建的流水线 adminprovider-from-scm
配置页面,在页面底部的 Pipeline
配置区域,点击 Definition
下拉框,选择 Pipeline script from SCM
Pipeline script from SCM
在 SCM
下拉框中,选择 Git
。在 Repository URL
中,填入Jenkinsfile所在的代码库的地址 http://192.168.71.244/wuzhenben/devops-kata-jenkins-pipeline-as-code.git
。确保 Branch Specifier
中填写了 */master
, Script Path
中填写了 Jenkinsfile
。点击 Save
保存
Git
,填写代码库地址点击 Build Now
手工触发流水线构建,让Jenkins读取代码库中的Jenkinsfile。
Build Now
手工触发流水线构建点击左下角 #1
左侧的小圆点,能够跳转到控制台输出页面,观察运行结果中包含了上面添加的那句 hello from scm
。说明Jenkins确实读取了Jenkinsfile
hello from scm
现在Jenkins能从代码库中读取Jenkinsfile了。这意味着流水线的配置,都可以用有版本控制的脚本来完成。但如何让流水线的构建自动进行,从而尽早频繁小批地发现代码集成的问题,以便修复呢?
一种方法是使用cron来每隔一段时间来轮询。但这样作无论代码是否更新,轮询总是会触发构建,比较耗费资源。另一种更有优势的方法是在GitLab里配置web hook。这样代码库一旦有代码push上来, GitLab 就能通过 web hook 通知Jenkins进行构建,从而把频繁小批构建做到极致。
首先确认Jenkins安装了GitLab插件和Git插件
在Jenkins的 Configure System
,找到GitLab的配置区域,把 Enable authentication for /project end-point
的勾选取消掉。如不取消勾选,则会在web hook测试时,报403 forbidden error
下面是我配置的两个参数:
Connection name: gitlab on ausu3
Gitlab host URL: http://192.168.71.244
在下面的Credentials里,把GitLab的api access token粘贴进去。点击 Add
按钮,选择 Jenkins
选项,出现Jenkins Credentials Provider: Jenkins对话框。下面是我输入的一些参数:
Kind: GitLab API token
API token: pHt2XifyorWQeFTHs8e-
ID: token-for-asus-3
Description: token for asus 3
点击 Add
创建credential
在Jenkins的System Configuration里,确保GitLab中的Credentials下拉菜单选择了上面配置的名为 token for asus 3
的GitLab API token
由于Jenkinsfile的triggers声明暂不支持gitlab的web hook,没法在Jenkinsfile里编写脚本。所以下面用直接在Jenkins界面里写脚本的adminprovider流水线来实验web hook
进入adminprovider流水线的配置页面,在 Build Triggers
区域,勾选 Build when a change is pushed to GitLab. GitLab webhook URL: http://192.168.71.243:8080/project/jenkins-pipeline-as-code-kata/adminprovider
,并勾选下面两个选项:
Accepted Merge Request Events
Closed Merge Request Events
注意,这个选项已经提示你GitLab webhook URL了
进入GitLab里刚刚创建的代码库项目 devops-kata-jenkins-pipeline-as-code
,点击左下角的 Settings
,再点击 Web hooks
,下面是我配置的一些参数:
URL: http://192.168.71.243:8080/project/jenkins-pipeline-as-code-kata/adminprovider
Secret Token: pHt2XifyorWQeFTHs8e-
确保勾选 Push events
点击 Add webhook
按钮。然后在页面底部,点击 Test
按钮,并选择 Push events
。如果一切顺利,会在页面顶部出现 Hook executed successfully: HTTP 200
成功信息
现在操练一下当流水线遇到编译错误时,会报什么错
在测试代码中,加一句 abc();
,然后push代码到代码库
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分钟后,流水线被轮询程序自动触发。把鼠标放到有提交的出错构建处,能看到导致这次构建失败的提交人和提交信息。点击相应提交左边的小圆球,能看到具体的错误信息
使用下述命令来查看上次提交的hash号,revert刚才引起流水线故障的提交
git log
git revert 131f54ebb5554aef43fc823d5d8d6fb7aaa8898c
git push
revert并且push,流水线自动构建,故障消失
现在操练一下当流水线遇到测试失败时,会报什么错
在测试代码中,将断言中的 firstName [4]
改为 firstName [40]
,然后push代码到代码库
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]");
}
}
流水线被自动触发。把鼠标放到有提交的出错构建处,能看到导致这次构建失败的提交信 息。点击相应提交左边的小圆球,能看到具体的错误信息
可以使用上面提到的命令来查看上次提交的hash号,revert刚才引起流水线故障的提交
为了让下次DevOps编程操练让你更有收获,不妨花2分钟 填写4个问题
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。