创建一个基于Maven的Java应用
目录
本教程将向您展示如何使用Jenkins构建基于 Maven的简单Java应用。
如果您是一名使用Maven的Java开发人员,并且之前并没有接触过持续集成/持续部署的概念,或者您可能熟悉这些概念但并不清楚如何使用Jenkins实现这样的构建,那么本教程适合您。
这个简单Java程序(您将从一个GitHub仓库上获取它)会输出字符串“Hello world!”,并包含一系列单元测试来保证主程序的运行符合预期。测试结果将会被保存为JUnit
XML报告。
用时: 完成本教程需要20-40分钟的时间(假如您已经符合下文的 先决条件)。确切的用时将取决于您的机器速度,以及您是否已经完成了 另一教程中的 在Docker中运行Jenkins。
您可以在任何时刻停止本教程并在随后继续。
如果您已经做过 另一篇教程了,您可以跳过下面的《先决条件》和《在Docker中运行Jenkins》两节,直接从《派生示例仓库》开始。(要确保您已经在本地安装了 Git。)如果您需要重启Jenkins,只需要跟着《Jenkins的重启和停止》做就可以了,并且之后您还可以从停止的地方继续。
先决条件
对本教程来说,您需要:
- 一台macOS、Linux或Windows机器(译注:Windows家庭版无法运行Docker),它有
- 至少256MB内存,尽管推荐512MB或更高。
- 10GB存储空间,用于Jenkins和Docker容器及镜像。
- 需要安装如下软件:
- Docker - 关于安装Docker的信息在安装Jenkins教程页的安装Docker小节。注意: 如果您使用的是Linux,本教程假定您不会使用root用户执行Docker命令,而是使用一个同样可以访问其他本教程涉及的工具的独立用户账户。
- Git和可选的GitHub Desktop。
在Docker中运行Jenkins
在本教程中,您将使用来自“jenkinsci/blueocean”Docker镜像的Docker容器来运行Jenkins。
要在Docker中运行Jenkins,请遵循下文对应的对macOS和Linux或Windows系统的讲解。
您可以在安装Jenkins上的Docekr和在Docker中下载及运行Jenkins小节获取更多信息。
macOS和Linux
- 打开一个终端窗口。
- 使用docker run命令在Docker中以容器的方式运行
jenkinsci/blueocean
镜像(该命令会在您本机没有下载该镜像时自动下载镜像):
docker run \
--rm \
-u root \
-p 8080:8080 \
-v jenkins-data:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \ <1>
-v "$HOME":/home \ <2>
jenkinsci/blueocean
<1> 映射容器中的/var/jenkins_home
目录到名为jenkins-data
的Docker数据卷。如果该数据卷不存在,docker run
命令会自动帮您创建。
<2> 映射宿主(例如您的本地)机器的$HOME
目录(通常为/Users/<用户名>
目录)至容器的/home
目录。
注意: 如果上述命令片段复制粘贴过去无法工作,尝试复制粘贴下文不包含标注的版本:
docker run \
--rm \
-u root \
-p 8080:8080 \
-v jenkins-data:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME":/home \
jenkinsci/blueocean
- 根据《安装向导》继续操作。
Windows
- 打开一个命令提示符窗口。
- 使用docker run命令在Docker中以容器的方式运行
jenkinsci/blueocean
镜像(该命令会在您本机没有下载该镜像时自动下载镜像):
docker run ^
--rm ^
-u root ^
-p 8080:8080 ^
-v jenkins-data:/var/jenkins_home ^
-v /var/run/docker.sock:/var/run/docker.sock ^
-v "%HOMEPATH%":/home ^
jenkinsci/blueocean
有关这些参数的解释,请参照上文《macOS和Linux》的内容。
- 根据《安装向导》继续操作。
访问Jenkins/Blue Ocean Docker容器
如果您有Docker的使用经验,并且想要通过终端/命令提示符使用docker exec命令访问Jenkins/Blue Ocean容器,那么您可以添加--name jenkins-tutorials
(在上文docker run命令那里)选项,它会将您的容器命名为“jenkins-tutorials”。
这意味着您可以通过docker exec
命令(通过另一个终端/命令提示符窗口)访问Jenkins/Blue Ocean容器,就像这样:
docker exec -it jenkins-tutorials bash
安装向导
在访问Jenkins之前,您需要做一些很快的“一次性”步骤。
解锁Jenkins
当您首次访问一个新的Jenkins实例时,您需要使用一段自动生成的密码来将其解锁。
- 在终端/命令提示符窗口里出现数行星号后,访问
http://localhost:8080
并等待解锁Jenkins页面出现。
- 回到您的终端/命令提示符窗口,拷贝自动生成的密码(在数行星号之间)。
- 在解锁Jenkins页面粘贴密码至管理员密码输入框并点击继续。
自定义Jenkins插件
在解锁了Jenkins之后,就会出现自定义Jenkins页面。
在该页面,点击安装推荐的插件。
安装向导会显示Jenkins的配置进度,以及正在安装的插件。该环节将持续数分钟。
创建首个管理员用户
最后,Jenkins会让您创建您的首个管理员用户。
- 当创建第一个管理员用户页面出现时,在对应输入框指定您的详细信息并点击保存并完成。
- 当Jenkins已就绪页面出现时,点击开始使用Jenkins。
注意:
- 该页面可能会提示Jenkins几乎就绪了!,这时点击重启。
- 如果页面在一分钟后还没有自动刷新,手动点击web浏览器的刷新按钮。
- 如果需要的话,使用刚创建的账户登录Jenkins,您已经做好了开始使用Jenkins的所有准备工作~
Jenkins的重启和停止
在本教程的剩余部分,您可以通过在之前执行docker run …
命令的终端或命令提示符窗口键入Ctrl-C
来停止Jenkins/Blue Ocean Docker容器。
要重启Jenkins/Blue Ocean Docker容器:
- 根据上文执行同样的
docker run …
命令。
**注意:**该处理会在镜像发布更新时,同时更新jenkinsci/blueocean
Docker镜像。 - 浏览器访问
http://localhost:8080
。 - 等待登录界面出现并登录。
在GitHub上派生并克隆示例仓库
从GitHub上获取示例“Hello World!”Java应用,将源码派生至您个人的GitHub账户并在本地克隆该派生。
- 确保您已经注册了GitHub账户。如果没有的话,就先去GitHub网站注册一个。
- 将GitHub上的
simple-java-maven-app
派生至您个人GitHub账户。如果这一步您需要帮助,请参考GitHub网站上的派生一个仓库来获取更多信息。 - 将派生的仓库克隆到您的本地机器上。要执行这一步,下文给出两种解决方案(
<your-username>
代表您在操作系统中的用户名):
- 如果您在机器上安装了GitHub Desktop应用程序:
- 在GitHub您的派生仓库,点击绿色的Clone or Download按钮,之后点击Open in Desktop。
- 在GitHub Desktop中,在点击Clone a Repository对话框的Clone按钮之前,确保Local Path为:
- macOS为
/Users/<your-username>/Documents/GitHub/simple-java-maven-app
- Linux为
/home/<your-username>/GitHub/simple-java-maven-app
- Windows为
C:\Users\<your-username>\Documents\GitHub\simple-java-maven-app
- macOS为
- 否则:
- 打开一个终端/命令提示符并
cd
至如下目录:- macOS -
/Users/<your-username>/Documents/GitHub/
- Linux -
home/<your-username>/GitHub/
- Windows -
C:\Users\<your-username>\Documents\GitHub\
(不过使用Git bash命令行窗口时是强力反对使用传统微软命令提示符的)
- macOS -
- 执行如下命令以继续/完成您的派生仓库的克隆:
git clone https://github.com/YOUR-GITHUB-ACCOUNT-NAME/simple-java-maven-app
YOUR-GITHUB-ACCOUNT-NAME
即您在GitHub上的账户名。
- 打开一个终端/命令提示符并
在Jenkins中创建管线工程
- 回到Jenkins,可能需要重新登录,点击欢迎页上的create new jobs(新建任务)。
提示:如果看不到该项,点击左上侧New Item。 - 在**Enter an item name(输入任务名)**输入框,指定管线项目的名称(例如
simple-java-maven-app
)。 - 滚动页面并点击Pipeline(管线),之后点击页面底部的OK按钮。
- (可选)在新的页面里,在**Description(描述)**输入框里指定管线的简单描述(例如“一个入门级管线,用于演示如何使用Jenkins构建基于Maven的简单Java应用”)。
- 点击页面顶部的**Pipeline(管线)标签页,滑动页面至Pipeline(管线)**部分。
- 在**Definition(定义)输入框,选择Pipeline script from SCM(来自源码控制系统的管线脚本)**选项。该选项会引导Jenkins从源码控制管理系统(SCM),也就是您本地克隆的Git仓库处获取管线。
- 在SCM字段项,选择Git。
- 在**Repository URL(仓库URL)**字段项,指定上文克隆到本地的仓库的路径。
- 点击**Save(保存)**保存该管线项目。现在您就可以创建
Jenkinsfile
,并签入本地克隆的Git仓库内。
使用Jenkinsfile创建初始化管线
现在您就可以创建管线以在Jenkins里基于Maven自动化构建Java应用了。 管线应该以Jenkinsfile
文件的形式创建,它可以被提交到您本地克隆的Git仓库(simple-java-maven-app
)里。
将持续交付管线代码和视为应用其他受版控和复查的代码一样的一部分是“代码式管线”的基础。更多关于管线和Jenkinsfile是什么的内容位于用户手册的管线和使用Jenkinsfile小节。
首先,创建一个初始化管线下载Maven Docker镜像并将其以容器的形式运行(将会在里边构建您的Java应用)。同时给添加一个“Build(构建)”阶段以启动整个流程的编排。
- 使用您擅长的文本编辑器或IDE,在您本地的
simple-java-maven-app
Git仓库根目录新建一个名为Jenkinsfile
的文件。 - 复制如下声明式管线代码并贴入
Jenkinsfile
文件(注意删除尖括号数字标记):
pipeline {
agent {
docker {
image 'maven:3-alpine' <1>
args '-v /root/.m2:/root/.m2' <2>
}
}
stages {
stage('Build') { <3>
steps {
sh 'mvn -B -DskipTests clean package' <4>
}
}
}
}
<1> image
参数(在agent部分的docker
参数里)会下载maven:3-apline Docker镜像(如果您本地没有下载过)并将该镜像作为独立容器。这意味着:
· 您的Jenkins和Maven容器会分别运行在本地Docker里。
· Jenkins会使用Maven容器作为agent执行管线项目。然而,该容器是短存活的,它的生命周期仅限您的管线的执行期间。
<2> args
参数在段村扩Maven Docker容器和Docker宿主机文件系统的/root/.m2
(Maven仓库)文件夹间建立了对等映射。解释该作用域的细节超出了本教程的范围。不过,这样做的主要原因是确保编译您的Java应用所需要的包依赖(Maven会在管线执行时下载)在Maven容器的生命周期结束后仍然存留。在反复执行Jenkins管线时,Maven就不需要冲虚下载相同的包了。注意和上文创建的jenkins-data
Docker数据卷不同,Docker宿主机文件系统会在Docker每次重启时清空。这意味着您将会在Docker每次重启时丢失已下载的Maven仓库包。
<3> 定义一个名为Build
的stage(阶段)(指令),会显示在Jenkins UI上。
<4> 该sh
步骤(位于steps作用域)先清理后构建您的Java应用(不执行测试)。
- 保存
Jenkinsfile
并将其提交到本地Git仓库。例如,在simple-java-maven-app
目录下,执行如下命令:
git add .
之后
git commit -m "Add initial Jenkinsfile"
- 返回Jenkins,也许需要再次登录。点击左侧的**Open Blue Ocean(打开Blue Ocean)**进入Jenkins Blue Ocean界面。
- 在This job has not been run(该任务没被运行过)消息框处,点击Run(运行),快速点击短暂出现在右下方的OPEN(打开)链接查看Jenkins对管线的执行。如果您无法点击OPEN链接,点击主Blue Ocean界面行来访问本功能。
**注意:**可能需要您等待数分钟第一次执行才能完毕。在Jenkins对您本地的simple-java-maven-app
进行拷贝后:
· Jenkins在内部对要在agent上运行的项目进行队列
· 下载Maven Docker镜像并在Docker里运行它。
· 在Maven容器里运行Build
阶段(定义在Jenkinsfile
里)。此时,Maven会下载构建所需依赖包,并最终存放于Jenkins的本地Maven仓库里(在Docker宿主机文件系统中)。
Blue Ocean在Jenkins构建成功后变为绿色。
- 点击右上角的×返回到Blue Ocean主界面。
给管线添加测试阶段
- 返回文本编辑器/IDE并打开
Jenkinsfile
。 - 复制粘贴下文声明式管线语法代码至您的
Jenkinsfile
的Build
阶段下:
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
故现在文件结果应是:
pipeline {
agent {
docker {
image 'maven:3-alpine'
args '-v /root/.m2:/root/.m2'
}
}
stages {
stage('Build') {
steps {
sh 'mvn -B -DskipTests clean package'
}
}
stage('Test') { <1>
steps {
sh 'mvn test' <2>
}
post {
always {
junit 'target/surefire-reports/*.xml' <3>
}
}
}
}
}
<1> 定义一个名为Test
的阶段(指令)。
<2> sh
步骤通过执行Maven命令运行单元测试。该命令同时会生成JUnit XML报告,保存于target/surefire-reports
目录(在Jenkins容器的/var/jenkins_home/workspace/simple-java-maven-app
目录下)。
<3> junit步骤(由JUnit插件提供)保存JUnit XML报告(由mvn test
命令产生)并将结果暴露给Jenkins接口。在Blue Ocean里,该结果可以通过管线运行的**Tests(测试)**页访问到。post作用域的always
会确保Test
阶段执行完毕后不理会阶段的结果,总是执行其包含的junit
步骤。
- 保存
Jenkinsfile
并将其提交到本地仓库。
git stage.
git commit -m "添加 'Test' 步骤"
- 返回Jenkins,访问Blue Ocean界面。
- 点击Run,快速点击OPEN链接。
**注意:**您可能发现这次运行Jenkins不在需要下载Maven Docker镜像了。Jenkins会使用之前下载过的镜像。同时因为Docker从上次执行管线以来没有重启过,所以在“Build”阶段Maven也不需要下载依赖包。也就是说,本次管线的运行应该会快很多。
如果改进版的管线执行成功,Blue Ocean的界面应如下图所示。注意新增加的“Test”阶段。您可以点击“Build”阶段的原型标记访问在该阶段的输出。
- 点击×返回Blue Ocean主界面。
给管线添加最终分发阶段
- 返回文本编辑器/IDE并确保打开了
Jenkinsfile
。 - 复制粘贴如下声明式管线语法代码到
Jenkinsfile
的Test
步骤下:
stage('Deliver') {
steps {
sh './jenkins/scripts/deliver.sh'
}
}
此时文件最终结果应是:
pipeline {
agent {
docker {
image 'maven:3-alpine'
args '-v /root/.m2:/root/.m2'
}
}
stages {
stage('Build') {
steps {
sh 'mvn -B -DskipTests clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Deliver') { <1>
steps {
sh './jenkins/scripts/deliver.sh' <2>
}
}
}
}
<1> 定义一个名为Delivar
的新阶段。
<2> sh
步骤执行位于仓库根目录下,jenkins/scripts
目录下的deliver.sh
shell脚本。该脚本的行为说明请参考脚本内容自身。通常原则上,保持管线代码(如Jenkinsfile
)尽可能地简单并将复杂的构建步骤(特别是包含两步或更多步骤的)放入独立的shell脚本文件如deliver.sh
文件里是一个好主意。最终这会使您的管线代码易于维护,特别是在管线变得越来越复杂的时候。
- 保存
Jenkinsfile
并提交至本地Git仓库。
git stage .
git commit -m "添加 Deliver' 阶段"
- 返回Jenkins,访问Blue Ocean界面。
- 点击Run,快速点击OPEN链接。如果修改后的 管线执行成功,其界面应如下:
此处是“Deliver”步骤输出的样子,在结尾向您展示了Java应用的执行结果。
- 点击×返回Blue Ocean主界面,上面以时序倒序展示了您之前的管线执行。
封装
很好!您刚刚已经使用Jenkins基于Maven构建了一个简单的Java应用!
您在上面创建的“Build”、“Test”和“Deliver”步骤都是在Jenkins中基于Maven构建使用了更多技术栈的更加复杂的Java应用的基础。
由于Jenkins是极度可扩展的,它可以通过修改和配置以支持几乎任意的自动化相关部分。
要了解更多关于Jenkins可以做什么,参考: