Maven antrun vs Jenkins 脚本组装 deb的优缺点、适用场景

文章目录

引言

生产环境推荐使用 Jenkins Pipeline 脚本构建 deb 包,相比 Maven Antrun 插件,其可维护性、调试体验与 CI/CD 灵活性显著更优。方案核心为:Maven 打包 fat-jar,Shell 脚本组装 deb 目录结构,动态配置 JVM 内存并集成 systemd 服务管理。关键优化包括移除无效参数、拆分启动脚本、合理设置内存上限,并通过 Jenkinsfile 实现自动化构建与上传至 APT 仓库,确保部署高效可靠。

一、结论

维度 maven-antrun-plugin Jenkins Pipeline 脚本
推荐度 ⭐⭐ ⭐⭐⭐⭐⭐
复杂度 高(XML 里写 shell) 低(直接 bash)
可维护性 差(XML 转义地狱) 好(独立脚本文件)
调试体验 差(mvn 日志里翻) 好(Jenkins 直接看)
与 deb 工具集成 勉强 原生
CI/CD 灵活性 低 高
本地也能打包 ✅ ❌(依赖 CI 环境)

结论:生产环境用 Jenkins 脚本方案。maven-antrun 只适合"本地开发时快速验证 deb 结构"。


二、service 文件常见问题分析

参数 问题
User=root / Group=root 前面讨论过,能用但不够安全
ExecStart= /usr/bin/java 前面有空格 systemd 会解析失败
-XX:MaxNewSize=640m + -XX:SurvivorRatio=16 ZGC 下全部无效
-XX:+UseNUMA RK3588 ARM 不是 NUMA
-Xms2048m -Xmx2048m 2GB 对 manage 服务偏多,RK3588 总共 8GB
ExecStart 一行太长 不可维护,改参数要改整个文件

三、方案 A:Jenkins Pipeline 脚本组装 deb(✅ 推荐)

核心思路

复制代码
Jenkinsfile
  → mvn package(产出 fat-jar)
  → bash scripts/build-deb.sh(组装 deb 目录结构)
  → dpkg-deb --build
  → rsync 到 APT 仓库

项目目录结构

复制代码
mes-manage/
├── src/
│   ├── main/java/
│   └── resources/
│       └── application-prod.yml
├── deb/
│   ├── DEBIAN/
│   │   ├── control
│   │   ├── postinst
│   │   ├── prerm
│   │   └── postrm
│   ├── opt/
│   │   └── sight/
│   │       ├── start.sh
│   │       └── conf/
│   │           └── application-prod.yml
│   └── lib/
│       └── systemd/
│           └── system/
│               └── sight-manage.service
├── scripts/
│   └── build-deb.sh
├── pom.xml
└── Jenkinsfile

deb/lib/systemd/system/sight-manage.service(修正版)

ini 复制代码
[Unit]
Description=sight Manage API (Spring Boot)
After=network.target mysql.service
Wants=mysql.service

[Service]
Type=simple
User=sight
Group=sight
WorkingDirectory=/opt/sight

# JVM 参数拆到 start.sh 里,service 只管调脚本
ExecStart=/opt/sight/start.sh

ExecStop=/bin/kill -SIGTERM $MAINPID
TimeoutStopSec=30
Restart=always
RestartSec=5

StandardOutput=journal
StandardError=journal
SyslogIdentifier=sight-manage

PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/opt/sight/logs /var/log/sight /var/lib/sight

[Install]
WantedBy=multi-user.target

deb/opt/sight/start.sh(exec 前台运行)

bash 复制代码
#!/bin/bash
# sight-manage start script
# 注意:不用 nohup,不用 &,用 exec 让 systemd 管控 java

set -e

JAR="/opt/sight/sight-manage.jar"
JAVA="/usr/bin/java"

if [ ! -x "${JAVA}" ]; then
    echo "ERROR: java not found at ${JAVA}" >&2
    exit 1
fi

if [ ! -f "${JAR}" ]; then
    echo "ERROR: ${JAR} not found" >&2
    exit 1
fi

# 动态内存:物理内存的 1/4,上限 2048m
MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
HEAP_MB=$(( MEM_KB / 1024 / 4 ))
[ ${HEAP_MB} -gt 2048 ] && HEAP_MB=2048
[ ${HEAP_MB} -lt 512 ] && HEAP_MB=512

# exec:用 java 替换当前 shell 进程
exec "${JAVA}" \
  -Xms${HEAP_MB}m \
  -Xmx${HEAP_MB}m \
  -XX:+UseZGC \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=/var/log/sight/heapdump.hprof \
  -Duser.timezone=GMT+08 \
  -Dfile.encoding=UTF-8 \
  -Dspring.profiles.active=prod \
  -Dspring.config.location=file:/opt/sight/conf/application-prod.yml \
  -jar "${JAR}"

scripts/build-deb.sh(Jenkins 调用)

bash 复制代码
#!/bin/bash
set -e

VERSION="${1:-$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)}"
BUILD_DIR="build/deb/sight-manage_${VERSION}_all"

echo "=== Building deb v${VERSION} ==="

# 清理 & 创建目录
rm -rf build/deb
mkdir -p ${BUILD_DIR}/DEBIAN
mkdir -p ${BUILD_DIR}/opt/sight/conf
mkdir -p ${BUILD_DIR}/opt/sight/logs
mkdir -p ${BUILD_DIR}/lib/systemd/system

# 1. 复制 jar
cp target/sight-manage.jar ${BUILD_DIR}/opt/sight/

# 2. 复制配置文件
cp deb/opt/sight/conf/application-prod.yml ${BUILD_DIR}/opt/sight/conf/
cp deb/opt/sight/start.sh ${BUILD_DIR}/opt/sight/
chmod +x ${BUILD_DIR}/opt/sight/start.sh

# 3. 复制 systemd service
cp deb/lib/systemd/system/sight-manage.service ${BUILD_DIR}/lib/systemd/system/

# 4. 复制 DEBIAN 控制文件
cp deb/DEBIAN/control ${BUILD_DIR}/DEBIAN/
cp deb/DEBIAN/postinst ${BUILD_DIR}/DEBIAN/
cp deb/DEBIAN/prerm ${BUILD_DIR}/DEBIAN/
cp deb/DEBIAN/postrm ${BUILD_DIR}/DEBIAN/

# 替换版本号
sed -i "s/^Version:.*/Version: ${VERSION}/" ${BUILD_DIR}/DEBIAN/control

# 设置脚本权限
chmod 755 ${BUILD_DIR}/DEBIAN/postinst
chmod 755 ${BUILD_DIR}/DEBIAN/prerm
chmod 755 ${BUILD_DIR}/DEBIAN/postrm

# 打包
dpkg-deb --build --root-owner-group ${BUILD_DIR}

echo "=== Done: sight-manage_${VERSION}_all.deb ==="
ls -lh sight-manage_${VERSION}_all.deb

Jenkinsfile 片段

groovy 复制代码
stage('Build Fat-Jar') {
    steps {
        sh 'mvn clean package -DskipTests'
    }
}

stage('Assemble DEB') {
    steps {
        sh 'bash scripts/build-deb.sh'
    }
}

stage('Verify DEB') {
    steps {
        sh '''
            dpkg-deb -I sight-manage_*_all.deb
            dpkg-deb -c sight-manage_*_all.deb | head -20
        '''
    }
}

stage('Upload to APT Repo') {
    steps {
        sshagent(credentials: ['apt-repo-rsync']) {
            sh '''
                VERSION=$(dpkg-deb -f sight-manage_*_all.deb Version)
                rsync -avz sight-manage_${VERSION}_all.deb \
                    aptly@192.168.20.100:/srv/incoming/
                ssh aptly@192.168.20.100 \
                    "aptly repo add mes-stable /srv/incoming/sight-manage_${VERSION}_all.deb && \
                     aptly publish switch stable mes-stable-$(date +%Y%m%d-%H%M%S)"
            '''
        }
    }
}

四、方案 B:maven-antrun-plugin 组装 deb

什么时候用?

  • 本地开发想 mvn package 直接出 deb
  • 没有 Jenkins 环境
  • 快速验证 deb 结构

pom.xml 配置

xml 复制代码
<build>
    <finalName>sight-manage</finalName>
    <plugins>
        <!-- Spring Boot -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <executable>true</executable>
            </configuration>
        </plugin>

        <!-- 复制 deb 资源 -->
        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>3.3.1</version>
            <executions>
                <execution>
                    <id>copy-deb-resources</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/deb-build</outputDirectory>
                        <resources>
                            <resource>
                                <directory>deb</directory>
                                <filtering>false</filtering>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <!-- antrun: 组装 deb 目录 + dpkg-deb 打包 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <id>build-deb</id>
                    <phase>package</phase>
                    <goals>
                        <goal>run</goal>
                    </goals>
                    <configuration>
                        <target>
                            <!-- 创建目录结构 -->
                            <mkdir dir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/DEBIAN"/>
                            <mkdir dir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/opt/sight/conf"/>
                            <mkdir dir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/opt/sight/logs"/>
                            <mkdir dir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/lib/systemd/system"/>

                            <!-- 复制 jar -->
                            <copy file="${project.build.directory}/sight-manage.jar"
                                  tofile="${project.build.directory}/deb-build/sight-manage_${project.version}_all/opt/sight/sight-manage.jar"/>

                            <!-- 复制 service 文件 -->
                            <copy file="deb/lib/systemd/system/sight-manage.service"
                                  todir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/lib/systemd/system/"/>

                            <!-- 复制 start.sh -->
                            <copy file="deb/opt/sight/start.sh"
                                  tofile="${project.build.directory}/deb-build/sight-manage_${project.version}_all/opt/sight/start.sh"/>
                            <chmod file="${project.build.directory}/deb-build/sight-manage_${project.version}_all/opt/sight/start.sh" perm="755"/>

                            <!-- 复制 DEBIAN 脚本 -->
                            <copy file="deb/DEBIAN/postinst"
                                  todir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/DEBIAN/"/>
                            <copy file="deb/DEBIAN/prerm"
                                  todir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/DEBIAN/"/>
                            <copy file="deb/DEBIAN/postrm"
                                  todir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/DEBIAN/"/>

                            <!-- 生成 control 文件(替换版本号) -->
                            <copy file="deb/DEBIAN/control"
                                  tofile="${project.build.directory}/deb-build/sight-manage_${project.version}_all/DEBIAN/control"/>

                            <!-- 设置权限 -->
                            <chmod perm="755">
                                <fileset dir="${project.build.directory}/deb-build/sight-manage_${project.version}_all/DEBIAN">
                                    <include name="postinst"/>
                                    <include name="prerm"/>
                                    <include name="postrm"/>
                                </fileset>
                            </chmod>

                            <!-- 执行 dpkg-deb 打包 -->
                            <exec executable="dpkg-deb" failonerror="true">
                                <arg value="--build"/>
                                <arg value="--root-owner-group"/>
                                <arg value="${project.build.directory}/deb-build/sight-manage_${project.version}_all"/>
                                <arg value="${project.build.directory}/sight-manage_${project.version}_all.deb"/>
                            </exec>

                            <echo message="DEB package created: ${project.build.directory}/sight-manage_${project.version}_all.deb"/>
                        </target>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

antrun 方案的致命缺点

问题 说明
XML 里写 shell < 要转义为 &lt;,& 要转义为 &amp;
调试困难 mvn 日志混在一起,看不到中间状态
条件逻辑弱 想判断架构、判断文件存在?ant 条件语法反人类
不可复用 这段 XML 绑死在 pom 里,Jenkins 没法单独调
打包工具耦合 dpkg-deb 必须在本地有,Windows 开发机直接挂
版本管理 control 文件版本号替换要用 filter,容易出错

五、两种方案对比总结

维度 Jenkins 脚本 maven-antrun
学习成本 低(bash 谁都会) 高(ant XML 语法)
可调试 ✅ bash -x ❌ mvn 日志翻
可复用 ✅ 脚本可独立运行 ❌ 绑死 Maven
跨平台 ❌ 依赖 Linux ❌ 依赖 dpkg-deb
CI 集成 ✅ 原生 ⚠️ 能跑但不优雅
适合生产 ✅ ❌
适合本地验证 ⚠️ 要装 dpkg-deb ✅ mvn package 一条命令

六、最终推荐架构

复制代码
开发阶段:mvn package → 本地手动 dpkg-deb -b 验证结构
CI 阶段:Jenkins → build-deb.sh → dpkg-deb → APT 仓库
生产部署:终端 apt update && apt install sight-manage

maven-antrun 不要用在 CI 里 ,它的定位是"本地开发时 mvn package 顺带出个 deb 方便联调",不是生产打包方案。


七、 service 文件的修正对照

原来 修正后 原因
User=root User=sight 最小权限
ExecStart= /usr/bin/java 前有空格 去掉空格 systemd 解析
JVM 参数全堆 ExecStart 一行 拆到 start.sh 可维护
-XX:MaxNewSize + -XX:SurvivorRatio 删除 ZGC 无效
-XX:+UseNUMA 删除 ARM 无效
-Xms2048m -Xmx2048m 动态计算 适配不同硬件
start.sh 用 nohup & exec java systemd 管控

see also

Jenkins Pipeline

是Jenkins 2.x版本引入的核心持续交付功能,通过Jenkinsfile将构建、测试、部署等流程编码为可版本控制的脚本,实现"流水线即代码"。相比传统自由风格任务,它具备版本可追溯、多分支隔离、失败可重入等优势,适用于微服务并行构建、多环境部署等复杂场景。Jenkins Pipeline分为声明式(结构化、易维护)和脚本式(灵活但需掌握Groovy)两种语法,生产中推荐优先使用声明式。其关键特性包括:通过agent配置动态分配执行节点(如Docker容器或Kubernetes Pod)、使用共享库复用逻辑、集成凭据管理实现安全构建。典型应用包括多阶段CI/CD流程自动化,如代码检出、并行测试、镜像构建及部署。

Jenkinsfile

是 Jenkins 流水线的代码化配置文件,使用 Groovy 语法定义 CI/CD 流程,支持声明式和脚本式两种写法。它将构建、测试、部署等步骤以代码形式管理,可提交到版本控制系统(如 Git)实现版本化和团队协作。典型结构包含 agent(执行节点)、stages(阶段)、steps(步骤)等元素,可配置环境变量、条件分支、循环等复杂逻辑。在生产环境中,Jenkinsfile 通过Pipeline 插件实现自动化构建,相比 Maven Antrun 等方案具有更高的可维护性和灵活性,尤其适合动态编排复杂流水线任务。

Fat-JAR(胖JAR)

是一种包含项目所有依赖的可执行JAR文件,通过Maven插件(如Assembly或Shade)将主类和依赖打包到一个文件中,适合独立部署。Spring Boot默认使用嵌套结构的Fat-JAR,依赖存放在BOOT-INF/lib目录,通过自定义类加载器解决类路径问题。Maven配置示例:使用Assembly插件指定主类

<mainClass>com.example.MainClass</mainClass>,执行

mvn package生成带依赖的JAR。其优势是部署简单,但需注意依赖冲突和文件体积。

相关推荐
hudd6683 小时前
JavaEE 初阶 - 多线程(初阶)
java·开发语言·java-ee
CarIise3 小时前
Java实训阶段查漏补缺复习笔记2
java·linux·算法
Wang's Blog3 小时前
Java框架 SpringCloud 快速入门: Feign 的性能优化
java·spring cloud·性能优化
蛋蛋的就会顺顺的4 小时前
hot100——二叉树
java·数据结构·算法·leetcode·力扣
打工仔折腾 AI4 小时前
System Prompt 替代 Few-shot:用规则约束大模型输出的省钱实践
java·人工智能·python·spring·langchain·prompt·ai agent 实战
CarIise4 小时前
Java实训阶段查漏补缺复习笔记1
java·开发语言·笔记
vx-程序开发5 小时前
【计算机毕设】51300童装超市管理系统的设计与实现
java·vue.js·spring boot·源码·课程设计·毕设·大作业
ym hyd 1115 小时前
题库建立与考试系统源码 Java+SpringBoot+Vue3 前后分离
java·开发语言·vue.js·spring boot·毕设
risc1234565 小时前
什么是码点?
java