小白学习gitlab+jenkins进行自动化构建(docker)之springboot项目

1,107 阅读7分钟

前言

gitlab和jenkins的安装参考我的另外两篇博客:

在Jenkins上安装必要的插件

所需插件:Maven IntegrationPipeline Maven IntegrationGitlabGitLab AuthenticationSSHPublish Over SSHDocker

点击 Manage Jenkins(系统管理) ——> Manage Plugins(插件管理)

image.png

安装Maven插件

点击可选插件 ——> 过滤Maven Integration插件 ——> 勾选Maven Integration和Pipeline Maven Integration ——> 点击直接安装

image.png

如图开始安装插件:

image.png

安装完成后,即可在插件管理下的已安装选项卡下看到刚刚已经安装的插件。

安装Gitlab插件

点击可选插件 ——> 过滤Gitlab插件 ——> 勾选Gitlab和Gitlab Authentication ——> 点击直接安装

image.png

安装SSH插件和Publish Over SSH插件

安装Publish Over SSH插件的原因:因为本方式是使用docker启动jenkins服务,所以在jenkins后续执行构建任务时候,需要在build成功后,将服务的jar包(以spring boot服务为例)拷贝到Dockerfile所在服务器的指定目录,进行微服务的启动;所以,此处需要配置SSH服务器的连接,意思就是在jenkins的任务结束后,去执行指定的服务器上的shell命令,做spring boot或cloud服务的镜像的构建,容器的运行,等一系列的事情。

点击可选插件 ——> 过滤SSH插件 ——> 勾选SSH和Publish Over SSH ——> 点击直接安装

image.png

安装Docker插件

点击可选插件 ——> 过滤Docker插件 ——> 勾选Docker ——> 点击直接安装

image.png

插件全部安装完成后,可以重启一下Jenkins。

相关配置

添加凭据

点击 Manage Jenkins(系统管理) ——> Manage Credentials(凭据管理)

image.png

点击添加凭据 ——> 输入宿主机服务器的用户名和密码等信息并保存

image.png

配置SSH remote hosts

这个配置是干什么的呢?配置SSH连接Dockerfile所在服务器的相关信息,并添加凭证,最后测试连接并保存,以备后面使用!!!

点击 Manage Jenkins(系统管理) ——> 系统配置

image.png

找到配置 ——> 下拉选择SSH remote hosts

image.png

如下图,输入对应的信息,并校验是否连接成功!成功后,点击应用 ——> 点击保存

image.png

配置Publish over SSH

找到配置 ——> 下拉选择Publish over SSH,进行相关配置即可。

image.png

image.png

image.png

这里配置的数据,目前只能在Post Steps中选中send files or execute commands over ssh使用,要想能够在execute shell script on remote host using ssh方式中使用,需要再配置一份SSH remote hosts和它配套使用

全局工具配置

由于我们要实现的是SpringBoot项目的自动化部署操作,所以需要安装JDK、Git、Maven、Docker。

image.png

安装JDK

可以安装多个,根据项目JDK版本需求。

输入自定义JDK名称 ——> 勾选自动安装 ——> 输入Oracle账户、密码 ——> 选择JDK版本 ——> 勾选同意协议

image.png

安装Git

输入自定义Git名称 ——> 勾选自动安装

image.png

安装Maven

输入自定义名称 ——> 勾选自动安装 ——> 选择版本

image.png

安装Docker

输入自定义名称 ——> 勾选自动安装

image.png

最后,点击应用 ——> 点击保存即可。

新建Jenkins任务

点击新建任务,输入名称

注意:本名称必须和项目名称一致,因为本名称会在jenkins工作空间下生成目录,类似于IDEA或Eclipse的工作空间的概念。所以,一般情况下,保证本名称=项目名称=docker镜像名称=docker容器名称 这样能尽可能的减轻jenkins配置的shell命令的复杂性!(空间命名要小写:因为镜像名不允许存在大写字母)

选择构建一个Maven项目(因为是Spring Boot的服务)

image.png

源码管理

输入描述信息,源码管理选择Git,从gitlab复制克隆地址(http协议的)粘贴到Repository URL中。未添加凭证会报授权失败的错误。错误如下:

![]()无法连接仓库:Command "git ls-remote -h -- http://192.168.57.128:8880/root/video-book-backend.git HEAD" returned status code 128:\
stdout:\
stderr: remote: HTTP Basic: Access denied\
fatal: Authentication failed for 'http://192.168.57.128:8880/root/video-book-backend.git/'

image.png

添加gitlab凭证:

image.png

构建触发器

接下来将会生成供gitlab配置webhook使用的URL和Token,请记录下来,后面会使用。

image.png

点击高级,拉下来找到Generate并点击,生成一串Secret Token。

image.png

添加webhook

前往gitlab,进入要构建的项目,在setting中选择Webhooks,输入URL和Secret Token 这两在上面图中已经给你标注了,去掉Enable SSL verification的勾选。

image.png

点击Add webhook,如图表示成功添加了webhook:

image.png

如果添加不成功解决方案请参考:解决 Url is blocked: Requests to the local network are not allowed

构建环境

勾选Add timestamps to the Console Output,等下可以看到控制台打印的信息,这个根据自己的需求勾选。

image.png

Pre Steps(构建之前的步骤)

配置前一步需要做的事情是:清理本项目在jenkins的workspace中的历史文件夹。

你可以不用知道WORKSPACE具体的地址在哪里,因为下方有链接可以查看到当前jenkins中有哪些可用的变量供你使用。

默认WORKSPACE地址:/var/jenkins_home/workspace(如果你jenkins是docker启动的,并且挂载了目录在宿主机,那你在宿主机也是可以看到的,即 /usr/local/docker/workspace

本处选择的是执行shell,则表示本处配置的shell命令,是默认在jenkins容器中执行的,而不是在宿主机上。

下拉选择执行 shell:

image.png

在执行shell的命令中输入以下命令,设置全局变量:

SERVER_NAME_1=video-book-backend
echo "=========================>>>>>>>工作空间WORKSPACE的地址:$WORKSPACE "
cd $WORKSPACE
echo "=========================>>>>>>>进入工作空间WORKSPACE,清除工作空间中原项目的工作空间$SERVER_NAME_1 "
rm -rf $SERVER_NAME_1
echo "=========================>>>>>>>清除工作空间中原项目的工作空间$SERVER_NAME_1 ......成功success"

注意:本处的SERVER_NAME_1=jenkins-docker-gitlab-springboot是配置项目的名称(和gitlab中的项目名保持一致)

Build(构建)

我们是SpringBoot项目,所以用到maven,这里设置一下全局操作,clean项目,并打成jar包,所以这里输入:clean package

image.png

Post Steps(执行任务)

只在jenkins构建成功后,才执行这一步。

因为最后的构建成功的maven项目的jar包是以docker启动服务为目的,所以最后的docker操作,一定是在jenkins容器以外的服务器上运行的,可能是本机宿主机,也可能是远程的服务器,这个根据自己的情况去配置。

本处选择,在远程的SSH执行shell脚本。

选中只有构建成功才执行这些命令,然后选择Execute shell script on remote host using ssh。

image.png

shell命令:

# =====================================================================================
# =================================定义初始化变量======================================
# =====================================================================================

# 操作/项目路径(Dockerfile存放的路径,Dockerfile一般都放在项目的根目录下)
# 如果Dockerfile放在项目根目录的子目录下,则子目录不能与项目同名
# 会导致在复制jar包的时候,覆盖子目录为jar包,同时没有扩展名jar,原因我暂时不知道
# 目前我的做法是将Dockerfile放在项目根目录下
BASE_PATH=/usr/local/docker/jenkins/workspace/video-book-backend

# jenkins构建好的源jar路径
# 这个路径是jenkins容器挂载在宿主机上的路径
# 我的jenkins的目录被我挂载在了/usr/local/docker/jenkins上
SOURCE_PATH=/usr/local/docker/jenkins/workspace

# docker镜像、docker容器、Dockerfile同目录下的jar名字[用它build生成image的jar]、jenkins的workspace下的项目名称
# 注意统一名称!!!!!
SERVER_NAME=video-book-backend

# 容器id  [grep -w 全量匹配容器名] [awk 获取信息行的第一列,即容器ID]  [无论容器启动与否,都获取到]
CID=$(docker ps -a | grep -w "$SERVER_NAME" | awk '{print $1}')

# 镜像id  [grep -w 全量匹配镜像名] [awk 获取信息行的第三列,即镜像ID]
IID=$(docker images | grep -w "$SERVER_NAME" | awk '{print $3}')

# 源jar完整地址[jenkins构建成功后,会在自己的workspace/项目/target下生成maven构建成功的jar包,获取jar包名的完整路径]
# 例如:/usr/local/docker/jenkins/workspace/video-book-backend/target/video-book-backend-0.0.1-SNAPSHOT.jar
SOURCE_JAR_PATH=$(find "$SOURCE_PATH/$SERVER_NAME/target/"  -name "*$SERVER_NAME*.jar" )

DATE=`date +%Y%m%d%H%M%S`

# =====================================================================================
# ============================对原本已存在的jar进行备份================================
# =====================================================================================

# 备份
function backup(){
    if [ -f "$BASE_PATH/$SERVER_NAME.jar" ]; then
        echo "=========================>>>>>>>$SERVER_NAME.jar 备份..."
            mv $BASE_PATH/$SERVER_NAME.jar $BASE_PATH/backup/$SERVER_NAME-$DATE.jar
        echo "=========================>>>>>>>备份老的 $SERVER_NAME.jar 完成"

    else
        echo "=========================>>>>>>>老的$BASE_PATH/$SERVER_NAME.jar不存在,跳过备份"
    fi
}

# =====================================================================================
# =========================移动最新源jar包到Dockerfile所在目录=========================
# =====================================================================================


 
# 查找源jar文件名,进行重命名,最后将源文件移动到Dockerfile文件所在目录
function transfer(){
      
    echo "=========================>>>>>>>源文件完整地址为 $SOURCE_JAR_PATH"

    echo "=========================>>>>>>>重命名源文件"
        mv $SOURCE_JAR_PATH  $SOURCE_PATH/$SERVER_NAME/target/$SERVER_NAME.jar

    echo "=========================>>>>>>>最新构建代码 将$SOURCE_PATH/$SERVER_NAME/target/$SERVER_NAME.jar 迁移至 $BASE_PATH"
        cp $SOURCE_PATH/$SERVER_NAME/target/$SERVER_NAME.jar $BASE_PATH
        
    echo "=========================>>>>>>>迁移完成Success"

}
 
# =====================================================================================
# ==================================构建最新镜像=======================================
# =====================================================================================

# 构建docker镜像
function build(){
    
    # 无论镜像存在与否,都停止原容器服务,并移除原容器服务
    echo "=========================>>>>>>>停止$SERVER_NAME容器,CID=$CID"
    docker stop $CID

    echo "=========================>>>>>>>移除$SERVER_NAME容器,CID=$CID"
    docker rm $CID

    # 无论如何,都去构建新的镜像
    if [ -n "$IID" ]; then
        echo "=========================>>>>>>>存在$SERVER_NAME镜像,IID=$IID"

        echo "=========================>>>>>>>移除老的$SERVER_NAME镜像,IID=$IID"
        
        docker rmi $IID

        echo "=========================>>>>>>>构建新的$SERVER_NAME镜像,开始---->"
        
        cd $BASE_PATH
        docker build -t $SERVER_NAME .
        
        echo "=========================>>>>>>>构建新的$SERVER_NAME镜像,完成---->"

    else
        echo "=========================>>>>>>>不存在$SERVER_NAME镜像,构建新的镜像,开始--->"
        
        cd $BASE_PATH
        docker build -t $SERVER_NAME .
        
        echo "=========================>>>>>>>构建新的$SERVER_NAME镜像,结束--->"
    fi
}
 

# =====================================================================================
# ==============================运行docker容器,启动服务===============================
# =====================================================================================

# 运行docker容器
function run(){
    backup
    transfer
    build

    # 创建容器
    docker run --name $SERVER_NAME -itd --net=host -v /etc/localtime:/etc/localtime:ro  -v /etc/timezone:/etc/timezone:ro  $SERVER_NAME 

}
 
# 入口
run

image.png

OK,到这里基本的任务已经新建成功,至于后续的两个步骤,根据自己的需求自行配置,没有难度的。

点击应用,保存。

测试

测试push事件触发自动化构建和部署,点击test下拉选择push events,出现HTTP 200表示OK了。

image.png

回到Jenkins可以看到任务列表,查看构建信息等。

image.png

待Jenkins构建成功之后,在服务器上执行命令:docker ps,可以看到我们启动起来的 SpringBoot 容器:

image.png

邮件通知

有时候团队合作,我们希望能通过邮件通知每一个开发者,项目是否构建成功。jenkins/jenkins:2.332.1默认安装了# Email Extension Template这个插件,还需要安装Email Extension Template这个插件

系统管理->插件管理->可选插件->搜索Email Extension Template

image.png

直接安装

配置Email(Jenkins自带)

2.1 基础信息查询

找到所要配置邮箱的基础信息,这里以QQ邮箱为例

  1. 通过网页端QQ邮箱的设置进入到邮箱客户端设置页面

image.png

  1. 找到邮箱的基础信息

image.png

2.2 Jenkins邮件通知配置

在Jenkins:系统管理->系统配置中,最底部找到邮件通知,打开高级,注意到在配置的下方有个"通过发送测试邮件测试配置",我们可以讲其勾选,填入邮箱地址,点击Test configuration来先测试一下邮件的发送。

这边最好先保存一下再测试,否则出错,又得重配。

image.png

如果报错如下:

image.png

这是因为我们还需要在设置Jenkins Location中配置系统管理员邮件地址,此地址要和邮件通知中的用户名一致

配置Email(Extended E-mail Notification)

记得文章一开头提到的下载Extended插件,没错,Jenkins系统设置里还可以通过Extended E-mail Notification对邮件发送进行模板格式的自定义

3.1 基础信息配置

基础信息配置与上述一致,唯一要注意的是这里需要重新生成一个授权码

image.png

3.2 模板格式配置

接3.1配置继续。这里主要就是配置展示的模板格式,常用的格式化的参数有:

- $BUILD_STATUS – 构建结果
- $PROJECT_NAME – 构建脚本名称
- $BUILD_NUMBER – 构建脚本编号
- $JOB_DESCRIPTION – 构建项目描述 
- $CAUSE – 脚本启动原因
- $BUILD_URL – 脚本构建详情URL地址

这里选择以HTML的格式展示,填入模板:

<!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">构建信息</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>构建  Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>    
                    <li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>    
                    <li>项目  Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>    
                </ul>    

<h4><font color="#0B610B">失败用例</font></h4>
<hr size="2" width="100%" />
$FAILED_TESTS<br/>

<h4><font color="#0B610B">最近提交(#$SVN_REVISION)</font></h4>
<hr size="2" width="100%" />
<ul>
${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
</ul>
详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/>

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

如下图:

image.png

3.3 触发条件配置

我们还可以在Default Triggers中根据自己的需要配置邮件的触发条件

image.png

image.png

这里为了防止因为构建一直尝试结果均为失败而造成的邮件轰炸,可以设置邮件仅第一次或第二次构建结果为失败时才发送邮件,后续失败的邮件将不再发送。我选择的是每一次失败和构建成功都会发邮件通知

3.4 jenkins的任务中配置邮件通知

  1. 在对应的任务中的构建设置中,勾选E-mail Notification Recipients

image.png

  1. 在对应的任务中的构建后操作中,下拉选择Editable Email Notification

image.png

image.png

image.png

至此,jnekins的自动化构建的邮件通知已配置完成,在gitlab点击push event发起构建进行测试。

发送成功的话,可看到如下图的提示:

image.png

总结

经过多款插件的安装配置,逐步掌握了如何上床Spring Boot项目到Gitlab中,并使用Jenkins自动构建任务,另外依托于Docker,让这一切变得更加方便,希望大家都多多思考,让机器自动干活,减少我们IT从业人员的重复、繁琐的工作量。