当我们开发 SpringBoot 项目时,如果需要对项目进行上线,传统方式就是先用mvn
命令构建jar
包,随后再使用java -jar
命令运行jar包,当我们需要频繁地更改代码并上线时,这种方式是很繁琐的,所以需要借助一些CI
工具让这整个流程自动化。
常见的CI
工具有GitHub Actions
和Jenkins
等,本文我主要讲解如何使用GitHub Actions
来构建工作流,使用Jenkins
也可以,但因为使用Jenkins
的话需要额外下载相关依赖,还需要再专门的服务器上搭建该服务,而GitHub Actions
直接依赖于github
,不需要去安装任何东西,对于开发个人项目来说,我觉得还是很方便的,话不多说,下面开始讲解具体的操作步骤~
首先需要有一个GitHub
仓库,在仓库页面点击Actions
进入Actions
页面后会有很多选项提供选择,这些都是创建工作流的模板,你可以选择一个你想要的模板,也可以自己创建一个新的模板,因为我开发项目使用maven,所以这里我就选择了Java with Maven
模板,如果你用的是gradle
,可以选择gradle模板
点击config
后,你的仓库会自动在根目录下创建一个.github/workflows
文件夹,里面有一个maven.yml
文件,这个yml
文件就是用来设置工作流的,我们需要根据自己的需求去配置该文件,如jdk版本、打包命令、运行命令等。在介绍具体的yml配置之前,我们需要先创建自己的Secrets
,因为在yml配置文件中涉及到连接服务器的操作,在连接服务器的时候我们需要再命令中加上服务器的ip和密码,为了防止密码暴露出去,我们需要用一个变量维护它,这个变量就是secrets
,在仓库页面点击settings
,随后点击左侧栏的secrets and variables
,再点击下拉框的actions
,随后创建secret
即可,这个secret
在创建后就无法再查看了,所以要记好。在使用的时候,格式为${{secrets.你定义的名字}}
下面介绍一下具体的工作流配置:
name: Java CI with Maven
on:
push:
branches: [ "master" ] # 当向master分支进行git push时触发该工作流
pull_request:
branches: [ "master" ] # 当向master分支合并分支时触发该工作流
# 工作流具体执行的任务
jobs:
build:
runs-on: ubuntu-latest # 运行在虚拟机上,指定虚拟机及其版本
# 工作流步骤
# 写在steps中
# 每个 - 即代表一个任务
# name:任务名字
# uses:使用github提供的某个action,每个action都有不同的用途
steps:
- name: pull latest code
uses: actions/checkout@v3 # 使用官方的checkout action,用于将仓库中的最新代码检查并拉取到工作目录中
- name: Set up JDK 1.8
uses: actions/setup-java@v3 # 安装java环境的action
with:
java-version: '8.0' # 指定jkd版本
distribution: 'temurin'
cache: maven # 使用maven缓存,避免每次构建项目时都要重新下载maven依赖
- name: Build docker image
run: | # run:该步骤要执行的命令,| 代表可以有多条命令
docker build -t dingsai-backend:0.1 . # 构建docker镜像,命令最后的点代表Dockerfile所在目录
docker save -o dingsai-backend.tar dingsai-backend:0.1 # 保存压缩后的docker镜像,这一步是为了方便后面我们将该镜像上传至指定的服务器
# 删除旧的docker镜像
# 使用sshpass以非交互式的用户名密码方式登录远程服务器
# 停止运行中的docker容器、删除该容器、删除镜像
# docker命令后面的两条竖线 || 代表当前面的docker命令执行失败时,命令可以继续往下执行,这样做的原因是在第一次构建项目的时候肯定不会存在这些容器和镜像,此时删除或停止这些容器就会失败
- name: delete old docker image
run: sshpass -p ${{secrets.REMOTE_SERVER01_PWD}} ssh -o StrictHostKeyChecking=no root@${{secrets.REMOTE_SERVER01_IP}} "docker stop dingsai-backend || true && docker rm dingsai-backend || true && docker rmi dingsai-backend:0.1 || true"
# 删除旧的docker镜像压缩包
- name: delete old docker tar
run: sshpass -p ${{secrets.REMOTE_SERVER01_PWD}} ssh -o StrictHostKeyChecking=no root@${{secrets.REMOTE_SERVER01_IP}} "cd ${{secrets.REMOTE_PROJECT_CATALOGUE}} && rm -f dingsai-backend.tar"
# 上传新的docker镜像
- name: upload new docker image and start-up script
run: sshpass -p ${{secrets.REMOTE_SERVER01_PWD}} scp -r -o StrictHostKeyChecking=no ./dingsai-backend.tar root@${{secrets.REMOTE_SERVER01_IP}}:${{secrets.REMOTE_PROJECT_CATALOGUE}}
# 加载tar文件,加载docker镜像
- name: load new docker image
run: sshpass -p ${{secrets.REMOTE_SERVER01_PWD}} ssh -o StrictHostKeyChecking=no root@${{secrets.REMOTE_SERVER01_IP}} "docker load -i ${{secrets.REMOTE_PROJECT_CATALOGUE}}/dingsai-backend.tar"
# docker run 运行,启动容器
- name: run project
run: sshpass -p ${{secrets.REMOTE_SERVER01_PWD}} ssh -o StrictHostKeyChecking=no root@${{secrets.REMOTE_SERVER01_IP}} "docker run -d -p 8081:8081 --name dingsai-backend dingsai-backend:0.1"
上面我在yml文件中都标注了各个命令的含义,但还有一下需要注意的地方:
- 使用ssh连接服务器的时候一定要加上
-o StrictHostKeyChecking=no
,因为在第一次连接服务器的时候,即便是使用的非交互式的sshpass命令,服务器也会询问你是否要建立连接,即总会出现一次交互,当在ssh命令中加上该参数后,代表不需要进行连接确认,可以直接建立连接 - 指定java版本的时候一定要填8.0而不是1.8,写1.8会找不到版本!!!
在上面的工作都完成后,我们向master分支push代码:
如上所示,github触发了工作流,我们再看一下服务器上是否有对应的docker容器在运行:
成功运行!!!