Gitlab CI/CD+Runner+Docker实现自动打包部署springboot项目


前言

本文所使用的软件及版本如下:
Gitlab:14.6.1;Gitlab-Runner:16.3.1

本文使用Gitlab CI/CD + Gitlab Runner实现自动打包部署springboot项目的功能
使用自动CI/CD可以减轻维护的负担,也可以避免人员操作失误等问题

  • Gitlab与Gitlab-Runner均使用Docker部署,Runner也使用Docker为执行者(executor)
  • 本文中Runner仅负责打包并输出至指定目录,springboot项目由定时脚本进行备份&部署
  • 本文中包含笔者的CI配置、备份&部署的定时脚本
  • 有关Gitlab的部署,本文不作赘述

一、Gitlab Runner部署

1、获取Runner注册令牌

使用Gitlab的管理员账号(默认为root)按下图顺序打开Gitlab-Runner管理界面
Gitlab-Runner注册界面
复制Runner的注册令牌,在后续部署Runner时会用到
Runner注册令牌

2、注册Runner

使用以下命令拉取Runner镜像,注意:本文使用的不是官方镜像

docker pull bitnami/gitlab-runner

使用以下命令创建并运行Runner
Runner注册时会生成config.toml至/etc/gitlab-runner/config.toml,而实际运行时使用的是/home/gitlab-runner/.gitlab-runner/config.toml,所以将其映射为同一文件方便修改
-d后台运行,-name命名为[Gitlab_Runner],--restart always自动启动,-v挂载宿主机目录
[宿主机目录]根据实际情况修改,docker.sock路径一般不需要修改

docker run -d --name Gitlab_Runner --restart always \
-v [宿主机目录]/.gitlab-runner/config.toml:/etc/gitlab-runner/config.toml \
-v [宿主机目录]:/home/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
bitnami/gitlab-runner:latest

接下来以root进入容器内部进行操作([Gitlab_Runner]需替换为实际容器名)

docker exec -it -u root Gitlab_Runner bash

如下图所示,输入命令开始注册Runner:
因笔者Gitlab与Runner位于同一Docker网络下,所以此处Gitlab地址为内网地址,请根据实际情况修改
三个可以为空的配置,可以随时在Gitlab中修改

gitlab-runner register

Runner注册

3、配置Runner

Runner注册后,查看宿主机内对应文件如下:
Runner初始配置
docker in docker挂载路径需要根据实际情况修改,语法与docker指令一致:宿主机路径:容器内路径
请注意,此处的前者路径为宿主机的路径,而不是Runner容器的路径

在[runners.docker]下,添加:pull_policy = “if-not-present”,可以使Runner运行时,仅当镜像不存在时进行拉取,如下:

pull_policy = "if-not-present" # 默认always,可选: always, if-not-present, never

推荐将maven及其仓库路径映射出来,这样可以复用本地仓库,配置如下:

volumes = ["/cache", "[maven路径]:/root/.m2", "[jar包存放路径]:/app/build"]
# 注:maven仓库路径为:[maven路径]/repository

笔者配置了多种缓存,如下:

[runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]

重启Runner容器后,在Gitlab内可以看到刚刚注册的Runner
新注册的Runner

至此,Gitlab Runner已部署、配置完成。

二、配置GitLab CI

如下图,进入CI配置文件编辑界面,随后修改预置的CI配置文件:
CI编辑器

Gitlab已提供大量模板供参考,包含maven;官方文档中也有详细的语法说明。因此本文不作赘述,仅介绍笔者CI配置思路
因实际需求考虑,笔者没有使用Runner将项目封装为Docker镜像运行,而是仅输出jar包。备份、部署运行等动作由定时任务执行
所以CI配置仅执行mvn package,并将jar包移动至指定目录,因此仅需要build阶段
笔者CI配置示例如下:

# 脚本变量
variables:
  # 项目端口号
  PORT_NUM: "[端口号]"
  # 构建阶段打印的信息
  BUILD_PREFIX_INFO: "$CI_COMMIT_BRANCH 构建开始\n构建创建者:$GITLAB_USER_NAME\n分支提交者:$CI_COMMIT_AUTHOR\n打包开始时间:$CI_PIPELINE_CREATED_AT"
  BUILD_SUFFIX_INFO: "$CI_COMMIT_BRANCH 构建结束"
  # 项目文件根目录
  # Runner容器中的"[jar包存放路径]:/app/build"],指定了/app/build映射至宿主机
  BASE_PATH: "/app/build/$CI_PROJECT_NAMESPACE/$CI_PROJECT_TITLE"
  # 新包路径
  PACKAGE_PATH: "$BASE_PATH/new"
  # 新包名:项目名-端口号.jar
  PACKAGE_NAME: "$CI_PROJECT_TITLE-$PORT_NUM.jar"
  # 备份路径
  BACKUP_PACKAGE_PATH: "$BASE_PATH/backup"
  # maven打包参数
  MAVEN_PACKAGE_OPTS: "-Djansi.passthrough=true -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
  -DskipTests=true -Dmaven.test.skip=true"
# 构建阶段,打包项目并放至对应路径下,由服务器自动部署脚本进行备份与部署
# jar包命名规则:项目名-端口号.jar
# 最终产物文件结构:
# /  项目文件根目录,也即/app/build/
# ╚═══╦══群组或用户名/
#     ╚═══╦══项目名/
#         ╠═══╦══new/
#         ║   ╚══════new.jar  输出的jar包
#         ╠═══╦══backup/
#         ║   ╚══════backup.jar
#         ╚══════old.jar
build: # 阶段名,可以任意修改
  stage: build
  # 仅master分支执行
  only:
    - master
  before_script:
    - echo -e "$BUILD_PREFIX_INFO"
  script:
    - mvn $MAVEN_PACKAGE_OPTS clean package
    - if [ ! -d $PACKAGE_PATH ];
        then echo -e "创建项目新包路径"; mkdir -p $PACKAGE_PATH;
      fi
    - if [ ! -d $BACKUP_PACKAGE_PATH ];
        then echo -e "创建项目备份路径"; mkdir -p $BACKUP_PACKAGE_PATH;
      fi
    - if [ -f target/*.jar ];
        then cp target/*.jar $PACKAGE_PATH/$PACKAGE_NAME; # 输出jar包至[jar包存放路径]
        else echo -e "未找到项目新包,不进行迁移"; exit 1;
      fi
  # 若不需要将jar包输出至Gitlab流水线产物中,则不需要以下步骤
    - cp target/*.jar $CI_PROJECT_DIR/$PACKAGE_NAME # 输出至Gitlab工件目录下
  # 输出打包后的jar包至Gitlab流水线产物
  artifacts:
      name: $CI_PROJECT_NAMESPACE-$CI_PROJECT_TITLE-$CI_COMMIT_BRANCH
      paths:
        - $CI_PROJECT_DIR/$PACKAGE_NAME
      expire_in: 1 week
  after_script:
    - echo -e "$BUILD_SUFFIX_INFO"

三、运行流水线

当项目git根目录下存在.gitlab-ci.yml文件时,如果再对相关分支进行提交或合并操作,Gitlab就会自动创建并执行流水线及相关作业
如下图为一次成功的作业,在宿主机的[jar包存放路径]文件夹内,也找到了生成的jar包:
在这里插入图片描述

四、使用定时脚本进行备份&部署

笔者服务器的文件结构示例如下:
在这里插入图片描述
因此定时脚本需要有如下功能:

遍历所有项目
项目Y
继续遍历群组内的其它项目
继续遍历其它群组
遍历所有群组
群组X
停止服务
old.jar迁移至backup
new.jar迁移至项目Y根目录
启动服务

笔者的定时备份&部署脚本如下:

BaseDir="[群组文件夹的父目录]"
BackupDirName="backup"
NewPackageDirName="new"
LogDirName="[日志]" # 日志文件夹名,遍历时跳过
RunScriptName="[启停脚本].sh"
StopCommand=" stop" # 停止服务指令
StartCommand=" start" # 启动服务指令

cd $BaseDir
echo "**********开始部署**********"
if (ls -A $BaseDir/ | grep -q ".")
then
    for groupName in $(ls -A $BaseDir/)
    do
        echo -----开始检查群组:$groupName-----
        for projectName in $(ls -A $BaseDir/$groupName)
        do
            thisBaseDir=$BaseDir/$groupName/$projectName
            projectPath=$groupName/$projectName
            if [ $projectName == $LogDirName ]
                then continue
            fi
            if [ ! -d $thisBaseDir/$BackupDirName ]
                then echo $projectPath未创建备份文件夹; mkdir -p $thisBaseDir/$BackupDirName;
            fi
            if [ ! -d $thisBaseDir/$NewPackageDirName ]
                then echo $projectPath未创建新包文件夹; mkdir -p $thisBaseDir/$NewPackageDirName;
            fi
            if [ -f $thisBaseDir/$NewPackageDirName/* ]
                then
                    echo $projectPath中已发现新文件,开始进行部署;
                    cd $thisBaseDir;
                    if [ -f $thisBaseDir/$RunScriptName ]
                        then $thisBaseDir/$RunScriptName$StopCommand;
                        else echo $projectPath未找到停止脚本!;
                    fi
                    if [ -f $thisBaseDir/*.jar ]
                        then 
                            for file in $thisBaseDir/*.jar
                            do
                                # 备份文件名格式:old_YYYYmmdd-HHMM.jar
                                mv $file $thisBaseDir/$BackupDirName/$(basename ${file%.*})_$(date +%Y%m%d-%H%M).jar;
                            done
                            echo "旧包备份完成";
                        else echo $projectPath未找到旧包,无需备份;
                    fi
                    mv $thisBaseDir/$NewPackageDirName/*.jar $thisBaseDir/; #新包不存在的情况已排除
                    echo "新包迁移完成";
                    if [ -f $thisBaseDir/$RunScriptName ]
                        then $thisBaseDir/$RunScriptName$StartCommand;
                        else echo $projectPath未找到启动脚本!;
                    fi
                    echo $projectPath部署完毕;
                else echo $projectPath中未发现新文件;
            fi
        done
        echo -----结束检查群组:$groupName-----
    done
else
    echo "未发现新文件"
fi
echo "**********部署结束**********"
exit 0

笔者java服务启停脚本如下:

#!/bin/bash

# jar包文件名
PROJECT_NAME="[jar包文件名].jar"
# jdk路径,笔者未安装java环境,而是直接使用jdk文件夹内的java
JavaBaseDir="[jdk路径]/jdk/bin"
 
function check() {
    PID=$(ps aux | grep $1 | grep -v grep | awk '{print $2}')
    if [[ "${PID[@]}" != "" ]];then
        echo "服务已存在:$1"
        exit 1
    fi
}
 
function check_start() {
    PID=$(ps aux | grep $1 | grep -v grep | awk '{print $2}')
    if [[ "${PID[@]}" != "" ]];then
        echo "服务启动成功: $1"
    else
        echo "服务启动失败: $1"
    fi
}
 
function stop_service() {
    PID=$(ps aux | grep $1 | grep -v grep | awk '{print $2}')
    if [[ "${PID[@]}" != "" ]];then
        ps -ef | grep $1 | grep -v grep | cut -c 9-15 | xargs kill -9
        test $? -eq 0 && echo "服务关闭成功: $1"
    else
        echo "未找到对应服务: $1"
    fi
}
 
function start_service() {
    check ${PROJECT_NAME}
    # 运行服务,若已配置java环境,可以直接使用java指令
    nohup $JavaBaseDir/java -Xms1000m -Xmx1000m -XX:-UseGCOverheadLimit -Dfile.encoding=utf-8 -jar ${PROJECT_NAME} >/dev/null 2>&1 &
    check_start ${PROJECT_NAME}
}
 
 
case $1 in 
    start)
        start_service
        ;;
    stop)
        stop_service ${PROJECT_NAME}
        ;;
    restart)
        stop_service ${PROJECT_NAME}
        sleep 1
        start_service
        ;;
    *)
        echo "Usage: bash $0 start | stop | restart"
        ;;
esac

笔者某次定时脚本的输出如下:
定时脚本输出结果

参考网址

官方文档
Gitlab之CICD环境变量
GitLab CI/CD + GitLab Runner in Docker 全自动部署服务器网页
自动化构建:gitlab gitlab-run ,maven的缓存 和 gitea drone drone-run

总结

至此,Gitlab自动部署springboot项目的功能已实现,各位请根据自己实际需求选择采取何种Runner执行者、CI/CD内容等
感谢各位阅览。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值