侧边栏壁纸
博主头像
一朵云的博客博主等级

拥抱生活,向阳而生。

  • 累计撰写 67 篇文章
  • 累计创建 25 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

jenkins -- 搭建一个java部署任务(详细)

一朵云
2022-11-26 / 0 评论 / 5 点赞 / 8878 阅读 / 19913 字

前言

  Jenkins搭建任务的文章去年年初,刚学jenkins时其实已经记录过几篇了,但最近回过头去看,发现文章记录的不太细致,所以我决定重新梳理一篇。(特别提醒:本文篇幅比较长,但比较干货,还请耐心观看吧~)

  该篇文章主要包括内容有:配置Git拉取代码、配置Maven构建代码、配置shell脚本启动代码、配置邮件通知、账号权限分配的操作。

讲解

一、Git拉取代码

  拉取git代码需要做一些准备工作,便是检查是否安装Jenkins插件,其中包括:GitMultiple SCMs

image-1669771866018

image-1669772462098

  确认插件安装无误了,那我们便可前往任务面板,对任务进行源码管理配置。

  若只需拉取单一仓库代码,可直接选用Git插件配置。
image-1669772698921

  若需要同时拉取两个仓库的代码,Git插件就不适用了,我们可以采用Multiple SCMs插件进行配置。

image-1669773099380

image-1669773187032

  其中jenkins与git仓库之间的连接有三种方式:

  • ①、使用账号密码进行连接

  • ②、使用ssh公私钥进行连接(常用、推荐)

  • ③、使用私人令牌进行连接

连接方式说明:

方式①:账密连接

  三种方式中最简单的了,但是通过jenkins配置可能泄露git仓库的账号密码,风险较高,故不推荐。但若忽略泄露的情况,坚持配置,具体操作如下:

  任务的源码管理中,点击Credentials下的“添加”按钮。

image-1669776258543

image-1669776542270

  填写完成后点击“添加”即可,后续便可以再源码管理中的Credentials下勾选了。

  前面说到泄露账密,可能会好奇到底要怎么看呢?直接揭秘,操作如下:

  打开jenkins管理中的脚本命令行(Script Console),在输入框内输入以下代码,遍历credentials数据。

com.cloudbees.plugins.credentials.SystemCredentialsProvider.getInstance().getCredentials().forEach{
  it.properties.each { prop, val ->
    println(prop + ' = "' + val + '"')
  }
  println("-----------------------")
}

image-1669789183639

下图中,username和password就显示出来了,所以风险就出来了。

image-1669789266870

方式②:SSH桥接

  相对第一种方式,更安全,jenkins使用私钥,在git仓库上配置公钥,从而完成免密连接。具体操作如下:

  • 第一步:

   确认jenkins当前系统用户与linux系统用户是否保持一致,不一致则进行修改。(jenkins默认安装的用户名为Jenkins,可能会产生操作权限问题,所以建议将Jenkins用户保持与linux系统用户权限一致,避免linux上能直接操作,但jenkins上不行。)

  以我为例,运维给我建了一个opser用户,权限仅次于root,那么我就要改jenkins配置文件了。

vim /etc/sysconfig/jenkins

企业微信截图_16687583254072(1)

vim /usr/lib/systemd/system/jenkins.service

企业微信截图_16687583709741(1)

  刷新配置文件。

systemctl daemon-reload
systemctl restart jenkins

若启动失败,可参考我之前写的另一篇博客 – Jenkins – 踩坑记录之权限不足(切换用户)

  • 第二步:

  为linux系统用户opser创建ssh连接的公私钥。以gitee的推荐方式为例,生成/添加SSH公钥

  前往linux操作系统进行如下指令操作,按提示回车三次即可。

ssh-keygen -t ed25519 -C "xxxxx@xxxxx.com"  

  注:其中 ed25519 表示使用的签名算法;xxxxx@xxxxx.com表示 sshkey 的名称,用邮箱只是习惯而已。

  上述指令操作完成后,可前往~/.ssh/目录查看生成的公私钥。(其中 id_ed25519.pub 文件表示公钥,id_ed25519 文件表示私钥)

image-1669859085707

  • 第三步:

  复制私钥内容填写进jenkins的Credentials配置中。

image-1669859390355

image-1669859433250

  注意:私钥的头尾也需要带上。

image-1669859513113

  校验git连接仓库是否正常即可。如果遇到linux上能拉取代码,但jenkins上拉取失败,大概率还是权限问题,可参考我之前的博客 – Jenkins – 踩坑记录之权限不足(切换用户)

方式③:私人令牌

  使用私人令牌和使用账密一样不太安全,容易通过jenkins泄露,但它的优势是更便捷的管理git仓库的权限,如限制用户上传、合并等操作。

  以码云为例,生成私人令牌的地方如下:

image-1669860638072

image-1669860687175

  使用gitee的私人令牌,推荐下载个jenkins 插件 Gitee后进行配置,这里就不展开了。

2、Maven构建代码

①、下载maven资源包

  访问maven官网:maven.apache.org ,如下图提示复制资源链接。

image.png

②、在linux上使用wget指令获取资源包

# 进入用户在该系统的home目录
cd /var/lib/maven

# 拉取maven的资源压缩包
wget https://dlcdn.apache.org/maven/maven-3/3.8.5/binaries/apache-maven-3.8.5-bin.zip

③、解压maven压缩包(即安装)

unzip apache-maven-3.8.5-bin.zip

④、配置maven系统参数,验证maven是否安装成功

# 编辑linux的环境变量
vim /etc/profile
# 在文件内添加以下内容,如图:(PATH有东西的话,就用:间隔拼接)
export MAVEN_HOME=/var/lib/maven/apache-maven-3.8.5

export PATH=$MAVEN_HOME/bin:$PATH

image.png

# 修改了环境变量文件,需重新加载
. /etc/profile
# 查看maven版本校验是否安装成功
mvn -version

image.png

⑤、修改maven源,替换为阿里云的。

# 编辑maven的配置文件
vim /var/lib/maven/apache-maven-3.8.5/conf/settings.xml
# 替换掉原来的mirrot标签内容
    <mirror>
        <id>alimaven</id>
        <name>aliyun maven</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <mirrorOf>central</mirrorOf>
    </mirror>

image.png

3、shell脚本启动代码

  在Jenkins构建中新增构建步骤“Execute shell”。

image-1670404126195

  文本输入框内填写如下内容:

# jenkins默认在build结束后会kill掉所有的衍生进程,填写该配置可避免
BUILD_ID=DONTKILLME

# 重新加载配置参数
. /etc/profile

# 获取git拉取代码后存放的路径
export PROJ_PATH=`pwd`

# 执行自定义的shell脚本
source $PROJ_PATH/cmge-sdk-start.sh

image-1670405238283

  上面的shell脚本中 cmge-sdk-start.sh 为启动脚本,该文件放置在当前项目的工作空间目录下,脚本中包括 mvn构建jar包、备份jar包、kill原有jar包进程、启动新jar包等系列操作,以我公司目前测试环境的脚本为例进行演示。

  我司服务端拆分服务,包括网关服务、管理配置服务、第三方服务、登录服务、支付服务总计5个。那么我就需要分别构建、启动这五个服务,如下:

#!/usr/bin/env bash

# 1、查进程,有则杀,无则输出提示
killJavaGatewayProcess()
{
    pid=`ps -ef | grep java | grep cmge-sdk-gateway | awk '{print $2}'`
    echo "cmge-sdk-gateway PId list :$pid"
    if [ "$pid" = "" ]
    then
      echo "no cmge-sdk-gateway pid alive!"
    else
      kill -9 $pid
      echo "kill cmge-sdk-gateway pid success!"
    fi
}
killJavaManageProcess()
{
    pid=`ps -ef | grep java | grep cmge-sdk-manage | awk '{print $2}'`
    echo "cmge-sdk-manage PId list :$pid"
    if [ "$pid" = "" ]
    then
      echo "no cmge-sdk-manage pid alive!"
    else
      kill -9 $pid
      echo "kill cmge-sdk-manage pid success!"
    fi
}
killJavaThirdpartyProcess()
{
    pid=`ps -ef | grep java | grep cmge-sdk-thirdparty | awk '{print $2}'`
    echo "cmge-sdk-thirdparty PId list :$pid"
    if [ "$pid" = "" ]
    then
      echo "no cmge-sdk-thirdparty pid alive!"
    else
      kill -9 $pid
      echo "kill cmge-sdk-thirdparty pid success!"
    fi
}
killJavaChargeProcess()
{
    pid=`ps -ef | grep java | grep cmge-sdk-charge | awk '{print $2}'`
    echo "cmge-sdk-charge PId list :$pid"
    if [ "$pid" = "" ]
    then
      echo "no cmge-sdk-charge pid alive!"
    else
      kill -9 $pid
      echo "kill cmge-sdk-charge pid success!"
    fi
}
killJavaLoginProcess()
{
    pid=`ps -ef | grep java | grep cmge-sdk-login | awk '{print $2}'`
    echo "cmge-sdk-login PId list :$pid"
    if [ "$pid" = "" ]
    then
      echo "no cmge-sdk-login pid alive!"
    else
      kill -9 $pid
      echo "kill cmge-sdk-login pid success!"
    fi
}

cd $PROJ_PATH/cmge-sdk
mvn clean install -DskipTests

#调用之前封装的方法杀掉java进程
killJavaGatewayProcess
killJavaManageProcess
killJavaThirdpartyProcess
killJavaChargeProcess
killJavaLoginProcess

# 判断是否有history文件夹,没有则创建,用于存储jar包的备份
if [ ! -d "$PROJ_PATH/history/comge-sdk" ]; then
  mkdir -p $PROJ_PATH/history/cmge-sdk
fi

# 清空历史文件夹$PROJ_PATH/running/cmge-sdk/
rm -rf $PROJ_PATH/running/cmge-sdk/

# 判断是否有running文件夹和相关子文件夹,没有则创建,用于存储正在运行的jar包
if [ ! -d "$PROJ_PATH/running/cmge-sdk/cmge-sdk-gateway" ]; then
  mkdir -p $PROJ_PATH/running/cmge-sdk/cmge-sdk-gateway
fi
if [ ! -d "$PROJ_PATH/running/cmge-sdk/cmge-sdk-manage" ]; then
  mkdir -p $PROJ_PATH/running/cmge-sdk/cmge-sdk-manage
fi
if [ ! -d "$PROJ_PATH/running/cmge-sdk/cmge-sdk-thirdparty" ]; then
  mkdir -p $PROJ_PATH/running/cmge-sdk/cmge-sdk-thirdparty
fi
if [ ! -d "$PROJ_PATH/running/cmge-sdk/cmge-sdk-login" ]; then
  mkdir -p $PROJ_PATH/running/cmge-sdk/cmge-sdk-login
fi
if [ ! -d "$PROJ_PATH/running/cmge-sdk/cmge-sdk-charge" ]; then
  mkdir -p $PROJ_PATH/running/cmge-sdk/cmge-sdk-charge
fi


# 移动刚通过maven install出来的jar包到running文件夹
cp $PROJ_PATH/cmge-sdk/cmge-sdk-gateway/target/cmge-sdk-gateway.jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-gateway/cmge-sdk-gateway.jar
cp $PROJ_PATH/cmge-sdk/cmge-sdk-manage/target/cmge-sdk-manage.jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-manage/cmge-sdk-manage.jar
cp $PROJ_PATH/cmge-sdk/cmge-sdk-thirdparty/target/cmge-sdk-thirdparty.jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-thirdparty/cmge-sdk-thirdparty.jar
cp $PROJ_PATH/cmge-sdk/cmge-sdk-login/target/cmge-sdk-login.jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-login/cmge-sdk-login.jar
cp $PROJ_PATH/cmge-sdk/cmge-sdk-charge/target/cmge-sdk-charge.jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-charge/cmge-sdk-charge.jar


# 备份cmge-sdk部署中的jar,
cp -r $PROJ_PATH/running/cmge-sdk/ $PROJ_PATH/history/cmge-sdk_`date +%Y%m%d%H%M%S`_bak


# 依次执行java的启动指令,gateway第一,manage第二,其他随意
nohup java -Xms512m -Xmx1024m -jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-gateway/cmge-sdk-gateway.jar > $PROJ_PATH/running/cmge-sdk/cmge-sdk-gateway/boot.log 2>&1 &
sleep 30
cat $PROJ_PATH/running/cmge-sdk/cmge-sdk-gateway/boot.log
echo "------------------ end ---------------------"

nohup java -Xms512m -Xmx1024m -jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-manage/cmge-sdk-manage.jar > $PROJ_PATH/running/cmge-sdk/cmge-sdk-manage/boot.log 2>&1 &
sleep 30
cat $PROJ_PATH/running/cmge-sdk/cmge-sdk-manage/boot.log
echo "------------------ end ---------------------"

nohup java -Xms512m -Xmx1024m -jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-thirdparty/cmge-sdk-thirdparty.jar > $PROJ_PATH/running/cmge-sdk/cmge-sdk-thirdparty/boot.log 2>&1 &
sleep 30
cat $PROJ_PATH/running/cmge-sdk/cmge-sdk-thirdparty/boot.log
echo "------------------ end ---------------------"

nohup java -Xms512m -Xmx1024m -jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-login/cmge-sdk-login.jar > $PROJ_PATH/running/cmge-sdk/cmge-sdk-login/boot.log 2>&1 &
sleep 60
cat $PROJ_PATH/running/cmge-sdk/cmge-sdk-login/boot.log
echo "------------------ end ---------------------"

nohup java -Xms512m -Xmx1024m -jar $PROJ_PATH/running/cmge-sdk/cmge-sdk-charge/cmge-sdk-charge.jar > $PROJ_PATH/running/cmge-sdk/cmge-sdk-charge/boot.log 2>&1 &
sleep 60
cat $PROJ_PATH/running/cmge-sdk/cmge-sdk-charge/boot.log
echo "------------------ end ---------------------"

  完成脚本编写后,建议添加个第三方插件“Timestamper”,用于展示构建日志的时间。

image-1670405736620

  完成插件的安装后,在项目中的构建环境环节,可以看到“Add timestamps to the Console Output”选项,我们对他进行勾选。

image-1670405595637

  最终项目构建后,cmge-sdk-start.sh执行的效果如下:

image-1670406027671

4、构建邮件通知

  安装邮箱拓展插件“Email Extension Plugin”。

image-1670406397867

  进入Jenkins的“Manage Jenkins”菜单内的“Configure System”项。

  该配置大坑,经常漏配置!!!

image-1670406710835

  qq邮箱为例,获取smtp信息,然后再jenkins中联调。

image.png

image-1670406878031

  联调通过后,最终可在项目中进行配置使用。

image-1670407512733

  构建邮件的格式,我习惯这么处理:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
	</head>

	<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
		<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
			<tr>
				(本邮件由系统自动发出,无需回复!)
				<br />
				各位好,以下是${PROJECT_NAME}项目构建信息
				<br />
				<td>
					<font color="#CC0000">构建结果 - ${BUILD_STATUS}</font>
				</td>
			</tr>
			<tr>
				<td>
					<br />
					<b>
						<font color="#0B610B">构建信息 - ${BUILD_STATUS}</font>
					</b>
					<hr size="2" width="100%" align="center" />
				</td>
			</tr>
			<tr>
				<td>
					<ul>
						<li>项目名称:${PROJECT_NAME}</li>
						<li>构建编号:第${BUILD_NUMBER}次构建</li>
						<li>触发原因:${CAUSE}</li>
						<li>构建状态:${BUILD_STATUS}</li>
						<li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a>
						</li>
						<li>构建地址:<a href="${BUILD_URL}">${BUILD_URL}</a>
						</li>
						<li>工作目录:<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a>
						</li>
						<li>项目地址:<a href="${PROJECT_URL}">${PROJECT_URL}</a>
						</li>
					</ul>

					<h4>
						<font color="#0B610B">变更记录</font>
					</h4>
					<hr size="2" width="100%" />
                                         变更明细:<a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a>
					<br />

				</td>
			</tr>
		</table>
	</body>
</html>

  最终选择 Triggers 触发事件即可。

image-1670407652458

5、账号权限配置

  考虑到多人使用 jenkins 后台进行构建的情况,我们需要对每个人进行权限配置,有的人可以配置项目;有的人只能构建和查看;有的人只能查看。

  ①、安装第三方插件 “Role-based Authorization Strategy”进行权限管理。

image-1670408537289

  ②、进入Jenkins的“Manage Jenkins”菜单内的“Configure Global Security”项,将Jenkins的授权策略修改为“Role-based Strategy”。

image-1670408630084

  ③、进入Jenkins的“Manage Jenkins”菜单内的“Manage and Assign Roles”项,配置角色和用户之前的关系。

image-1670409139721

image-1670409219375

  至此,账号与角色之间的关系就配置好了。如果需要更精细到项目,也可以通过该插件实现,自行摸索吧!

5

评论区