提前声明:下文均使用Gradle进行项目的管理,没有使用Maven进行项目的管理。
1. 准备工作
注意:
- 1.GraalVM编译需要gcc,在编译打包之前需要在Jenkins编译机器上先安装gcc。
- 2.GraalVM编译需要
libz.a
,因此需要在Jenkins编译机器上先安装zlib
。 - 3.GraalVM打包成为本地的二进制文件,因此它没有跨平台特性,如果想要在Linux上部署服务,就必须在Linux机器上进行打包。
- 4.GraalVM打包必须使用GraalVM专属的JDK进行编译,不能使用普通的JDK进行打包,可以从Oracle官网
https://www.oracle.com/cn/java/technologies/downloads/#java24
进行GraalVM的下载。
安装GCC:
sudo apt install gcc
安装zlib:
# ubuntu
sudo apt-get install zlib1g-dev
# centos
sudo yum install zlib-devel
# homebrew
brew install zlib
2.自定义GraalVM编译参数
Jenkins的编译Shell脚本如下,注意必须使用GraalVM的JDK进行编译和打包,使用普通的JDK无法进行GraalVM的编译打包。具体可以从Oracle官网https://www.oracle.com/cn/java/technologies/downloads/#java24
上进行下载。
JAVA_HOME=/home/wanna/graalvm-jdk21
./gradlew clean nativeCompile -x test
对应的是Jenkins的BuildSteps这部分的配置。
类型选择执行Shell。
3.部署命令
编译之后,上传到目标机器上的启动脚本:
lsof -t -i:8080 | xargs -r kill -9 && cd /home/wanna/datasync/schedule-datasync/ && chmod a+x datasync-server && nohup ./datasync-server > info.log 2>&1 &
对应的是Jenkins中的"构建后操作"。
注意:
-
Source files
决定我们要上传的文件列表,GraalVM的Gradle插件打包出来的产物放在build/native/nativeCompile/
目录下,我们需要将build/native/nativeCompile/*
上传到服务器上。
-
- 为了上传到远程服务器后,目录中的
build/native/nativeCompile
丢掉,在Remove prefix
中,把这部分去掉,这样上传到目标服务器后目录就短一些。
- 为了上传到远程服务器后,目录中的
-
Remote directory
中需要配置上传到服务器的哪个文件夹下,我这里填写的是schedule-datasync
,代表我希望打包的二进制文件产物上传到这个文件夹下(注意Publish Over SSH
插件本地配置了登录时的默认工作路径,两者路径拼接之后才是真正的目录)。
类型选择"Send build artifcats over SSH"(注意需要先安装"Publish Over SSH"插件)
4. 出现问题介绍
4.1 重复部署8080端口会出现端口冲突
使用如下的命令,找出来8080端口所占用的进程PID,使用kill命令进行杀掉。
lsof -t -i:8080 | xargs -r kill -9
4.2 上传的二进制文件没有x执行权限
解决方式:在部署命令中给二进制可执行文件先加上+x
的权限再进行执行。
chmod a+x datasync-server
4.3 CPU指令集不兼容
出现问题详细如下:
The current machine does not support all of the following CPU features that are required by the image: [CX8, CMOV, FXSR, MMX, SSE, SSE2, SSE3, SSSE3, SSE4_1, SSE4_2, POPCNT, LZCNT, AVX, AVX2, BMI1, BMI2, FMA].
Please rebuild the executable with an appropriate setting of the -march option.
这种情况,说明GraalVM编译时,用到了一些高级的指令集,但是当前的CPU并不支持。
此时我们需要修改Gradle的配置,对GraalVMExtension进行配置,新增一个-march=x86-64
参数,使用通过的x86-64结构,可以兼容大多数的服务器。
configure<GraalVMExtension> {
binaries {
named("main") {
buildArgs.add("-march=x86-64")
}
}
}
修改后,重新进行提交代码,并触发Jenkins部署。当去服务器上看到如下的SpringBoot启动日志,说明启动成功(/home/wanna/datasync/schedule-datasync/datasync-server
可以看到,用的是二进制的包进行的启动,而不是用的jar包进行的启动)。
2025-03-30T18:49:59.542Z INFO 1845 --- [datasync-server] [ main] c.w.p.d.DatasyncServerApplicationKt : Starting AOT-processed DatasyncServerApplicationKt using Java 21.0.6 with PID 1845 (/home/wanna/datasync/schedule-datasync/datasync-server started by wanna in /home/wanna/datasync/schedule-datasync)
5. 基于Jenkinsfile利用Pipeline完成项目的自动化部署
5.1 项目中新增Jenkinsfile文件
在项目下新增Jenkinsfile
文件,其中内容如下:
pipeline {
agent any
environment {
// Gitea 仓库信息
GITEA_REPO = 'https://gitea.wanna1314y.top/wanna/datasync-server.git'
GITEA_CREDENTIALS = 'gitea-username-password'
GIT_BRANCH = 'main'
// 部署的目标服务器的名字
SERVER_NAME = 'datasync-server'
}
tools {
// 使用 Jenkins 配置的 Maven
maven 'maven'
// 使用 Jenkins 配置的 JDK
jdk 'graalvm-jdk21'
}
stages {
stage('Checkout') {
steps {
// 使用凭证拉取代码
git credentialsId: "${GITEA_CREDENTIALS}",
url: "${GITEA_REPO}",
branch: "${GIT_BRANCH}"
}
}
stage('Gradle Build') {
steps {
// 执行 Maven 构建
sh """
JAVA_HOME=/home/wanna/graalvm-jdk21
./gradlew clean nativeCompile -x test
"""
}
}
// 上传文件并启动服务器
stage('Upload And Start Server') {
steps {
sshPublisher(publishers: [
sshPublisherDesc(
configName: "${SERVER_NAME}", // 部署的目标服务器的名字, 需要和Publish Over SSH配置的名称对应
transfers: [
sshTransfer(
sourceFiles: 'build/native/nativeCompile/*', // 需要传输到远程的文件
remoteDirectory: "schedule-datasync", // 上传到远程服务器路径, 会以Publish Over SSH配置的路径作为基础路径, 这里填相对路径
removePrefix: 'build/native/nativeCompile', // 上传到服务器之后, 需要把文件去除的前缀, 比如文件是build/libs/xx.jar, 配置"build/libs/",那么上传到服务器之后路径就会去掉前缀
// 上传到远程服务器之后, 需要执行的命令, 需要注意的是: 当前路径是Home目录
execCommand: """
lsof -t -i:8080 | xargs -r kill -9
cd /home/wanna/datasync/schedule-datasync/
chmod a+x datasync-server
nohup ./datasync-server >> info.log 2>&1 &
"""
)
],
verbose: true
)
])
}
}
}
post {
success {
// 构建成功后的操作
echo 'Build and deployment successful!'
}
failure {
// 构建失败后的操作
echo 'Build or deployment failed!'
}
always {
// 清理工作空间
cleanWs()
}
}
}
5.2 在Jenkins上新建项目
在Jenkins中,新建任务,选择"流水线":
选择"Pipeline scripte from SCM",代表从代码管理仓库中,选择Jenkinsfile进行项目构建。
接入填入Git仓库地址,和账号密码(Credentials)。
在下面选择Git仓库中的代码分支,和Jenkinsfile的文件路径,从而实现让Jenkins自动从Git仓库拉取Jenkinsfile,进行项目的编译和部署。
评论