Jenkins pipeline流水线方式部署后端jar

以freestyle方式部署前后端可以参考:

jenkins+mqtt实现本地构建和远程自动发版_jenkins远程调用和本地调用-CSDN博客

jenkins部署nodejs前端项目_jenkins nodejs-CSDN博客

pipeline流水线的方式适用于大于10人的团队且有专人运维的团队。

一个简单的例子

复制代码
pipeline {
    agent any
    environment {
        // 代码仓库配置( 使用占位符替换真实地址和凭证ID)
        GIT_REPO = 'http://gitlab.example.com/[部门标识]/[项目组]/[项目名]'
        GIT_BRANCH = 'master'
        GIT_CRED_ID = '[GITLAB_凭证ID_占位符]' 
        // 子模块配置( 使用业务标识占位符)
        MODULE_PATH = '[模块根目录]/[子模块目录]'
        MODULE_NAME = '[子模块名称]'
        // SSH部署配置( 服务器标识占位符)
        SSH_SERVER_ID = '[SSH服务器配置名称_占位符]'
        // 远程部署根目录( 使用通用路径占位符)
        REMOTE_BASE_DIR = '/[业务根目录]/[项目目录]'
        // 远程Jar包实际存储路径( 整合通用路径占位符)
        REMOTE_JAR_PATH = '/[数据盘目录]/[业务根目录]/[模块根目录]/[子模块目录]/target'
        // Java启动路径(保留通用路径,若为定制路径则替换为占位符)
        JAVA_CMD = '/[JDK安装目录]/bin/java'
        // Maven路径(保留通用路径,若为定制路径则替换为占位符)
        MAVEN_CMD = '/[Maven安装目录]/bin/mvn'
    }
    stages {
        stage('拉取代码') {
            steps {
                echo '开始拉取Git代码...'
                git url: "${GIT_REPO}", branch: "${GIT_BRANCH}", credentialsId: "${GIT_CRED_ID}"
            }
        }

        // 新增:替换bootstrap.yml配置文件
        stage('替换bootstrap.yml配置') {
            steps {
                echo '开始执行bootstrap.yml替换脚本...'
                sh """
                    set -e  # 执行出错时立即退出脚本

                    # ===================== 配置项 =====================
                    # 定义bootstrap.yml文件的路径(基于Jenkins工作空间)
                    BOOTSTRAP_FILE="\${WORKSPACE}/${MODULE_PATH}/src/main/resources/bootstrap.yml"
                    # ==================================================

                    # 1. 检查文件目录是否存在,不存在则创建
                    FILE_DIR=\$(dirname "\${BOOTSTRAP_FILE}")
                    if [ ! -d "\${FILE_DIR}" ]; then
                        echo "⚠️ 目录\${FILE_DIR}不存在,正在创建..."
                        mkdir -p "\${FILE_DIR}"
                    fi

                    # 2. 检查文件是否存在,不存在则创建空文件
                    if [ ! -f "\${BOOTSTRAP_FILE}" ]; then
                        echo "⚠️ 文件\${BOOTSTRAP_FILE}不存在,正在创建空文件..."
                        touch "\${BOOTSTRAP_FILE}"
                    fi

                    # 3. 写入指定内容到bootstrap.yml(覆盖原有内容)
                    # 注意:YAML缩进必须严格匹配,EOF加单引号避免Shell解析变量
                    cat > "\${BOOTSTRAP_FILE}" << 'EOF'
spring:
  application:
    name: [应用名称]
  profiles:
    active: dev
  cloud:
    nacos:
      config:
        server-addr: [Nacos服务器IP]:[Nacos端口]
        namespace: [Nacos命名空间标识]-\${spring.profiles.active}
        group: \${spring.profiles.active}
        prefix: \${spring.application.name}
        file-extension: yaml
        username: [Nacos登录账号]
        password: [Nacos登录密码]
EOF

                    # 4. 验证写入结果
                    echo -e "\\n✅ 成功替换\${BOOTSTRAP_FILE}内容,当前内容:"
                    cat "\${BOOTSTRAP_FILE}"

                    echo -e "\\n🎉 脚本执行完成!"
                """
            }
        }

        stage('Maven子模块编译打包') {
            steps {
                echo '开始编译打包Maven子模块...'
                sh "${MAVEN_CMD} clean package -pl ${MODULE_PATH} -am -Pdev -U -DskipTests"
            }
        }

        stage('动态获取Jar包名称') {
            steps {
                script {
                    echo "正在识别${MODULE_PATH}/target下的可运行Jar包..."
                    // 过滤出可执行的Fat Jar(排除源码包和original包)
                    def jarName = sh(
                        script: "ls ${MODULE_PATH}/target/*.jar | grep -v 'sources.jar' | grep -v 'original' | tail -n 1 | xargs basename",
                        returnStdout: true
                    ).trim()
                    env.APP_JAR_NAME = jarName
                    echo "识别到的可运行Jar包名称:${APP_JAR_NAME}"
                }
            }
        }

        stage('验证Jar包路径') {
            steps {
                echo "检查Jar包路径:${MODULE_PATH}/target/${APP_JAR_NAME}"
                sh "ls -l ${MODULE_PATH}/target/${APP_JAR_NAME} || (echo 'Jar包不存在,打包失败' && exit 1)"
            }
        }

        stage('SSH部署到远程服务器') {
            steps {
                echo '开始通过SSH部署文件到远程服务器并执行启动命令...'
                // 使用片段生成器的核心配置,修正execCommand位置和路径
                sshPublisher(publishers: [
                    sshPublisherDesc(
                        configName: "${SSH_SERVER_ID}",
                        transfers: [
                            sshTransfer(
                                 // 远程执行命令(移到sshPublisherDesc根层级,确保执行)
                                execCommand: """
                                    # 停止占用[应用端口]端口的进程
                                    netstat -lnp | grep [应用端口] | awk '{print \$NF}' | awk -F '/' '{print \$1}' | xargs -r kill -9
                                    # 后台启动应用,日志重定向到null(无日志输出)
                                    nohup ${JAVA_CMD} -jar ${REMOTE_JAR_PATH}/${APP_JAR_NAME} --spring.profiles.active=dev >/dev/null 2>&1 &
                                    sleep 1
                                """,
                                execTimeout: 120000,
                                cleanRemote: false,
                                excludes: '',
                                flatten: false, // 保留本地目录结构
                                makeEmptyDirs: false,
                                noDefaultExcludes: false,
                                patternSeparator: '[, ]+',
                                remoteDirectory: "${REMOTE_BASE_DIR}", // 传输到远程根目录
                                remoteDirectorySDF: false,
                                removePrefix: "",
                                sourceFiles: "${MODULE_PATH}/target/${APP_JAR_NAME}" // 本地Jar包路径
                            )
                        ],
                        usePromotionTimestamp: false,
                        useWorkspaceInPromotion: false,
                        verbose: false
                    )
                ])
            }
        }
    }
    post {
        success {
            echo '子模块构建、部署及启动命令执行成功!'
        }
        failure {
            echo '子模块构建、部署或启动命令执行失败!'
        }
    }
}

配置的简要说明如下

一、环境配置说明

脚本通过environment块定义了全流程的核心配置项(均为占位符,需替换为实际值),包括:

  1. 代码仓库配置:Git 仓库地址、分支、Jenkins 凭证 ID;
  2. 子模块配置:待部署的 Maven 子模块路径与名称;
  3. SSH 部署配置:远程服务器配置名称、部署根目录、Jar 包存储路径;
  4. 工具路径配置:Java 与 Maven 的执行路径。

二、执行阶段详细说明

阶段 1:拉取代码

  • 核心操作 :通过 Jenkins 的git步骤,根据配置的仓库地址、分支和凭证 ID,从 Git 仓库拉取代码到 Jenkins 工作空间;
  • 作用:获取项目最新代码,为后续编译打包提供基础。

阶段 2:替换 bootstrap.yml 配置

  • 核心操作
    1. 定义bootstrap.yml文件的路径,检查文件所在目录是否存在,不存在则创建;
    2. 若配置文件不存在,创建空文件;
    3. 覆盖写入定制化的 Spring Cloud 配置(包含应用名称、Nacos 配置中心地址、命名空间、认证信息等);
    4. 验证文件写入结果并打印内容。
  • 作用:统一替换项目的核心配置文件,确保应用连接正确的配置中心。

阶段 3:Maven 子模块编译打包

  • 核心操作 :执行 Maven 命令clean package -pl ${MODULE_PATH} -am -Pdev -U -DskipTests,对指定子模块进行清理、编译并打包,跳过测试用例执行;
  • 参数说明
    • -pl:指定待打包的子模块路径;
    • -am:自动构建子模块依赖的其他模块;
    • -Pdev:激活 dev 环境的 Maven 配置;
    • -U:强制更新快照依赖;
    • -DskipTests:跳过单元测试。
  • 作用:生成可运行的 Jar 包文件。

阶段 4:动态获取 Jar 包名称

  • 核心操作 :通过 Shell 命令过滤子模块target目录下的 Jar 包(排除源码包和 original 包),获取最新的可执行 Jar 包名称,并将其存入环境变量APP_JAR_NAME
  • 作用:解决 Jar 包名称含版本号导致的路径不固定问题,动态识别待部署的 Jar 包。

阶段 5:验证 Jar 包路径

  • 核心操作 :通过ls命令检查识别到的 Jar 包是否存在,若不存在则打印错误信息并终止脚本;
  • 作用:校验打包结果,避免因打包失败导致后续部署操作无效。

阶段 6:SSH 部署到远程服务器

  • 核心操作 :通过 Jenkins 的sshPublisher插件完成远程部署与启动:
    1. 将本地 Jar 包传输至远程服务器指定的部署根目录;
    2. 执行远程 Shell 命令:停止占用指定端口的进程,通过nohup后台启动 Jar 包(日志重定向至空),并短暂休眠确保启动指令执行;
  • 作用:将打包好的 Jar 包部署到远程服务器,并自动启动应用。

三、后置操作说明

脚本通过post块定义了执行结果的反馈逻辑:

  1. 成功(success):打印 "子模块构建、部署及启动命令执行成功!";
  2. 失败(failure):打印 "子模块构建、部署或启动命令执行失败!"。
  • 作用:直观反馈 Pipeline 执行结果,便于问题排查。
相关推荐
代码总长两年半2 小时前
Linux---配置编程环境VSCode
linux·运维·服务器
朱 欢 庆2 小时前
在docker容器里 使用Jenkins部署前端项目
前端·经验分享·docker·jenkins
Tipriest_2 小时前
Linux 桌面(Desktop)图标的生成原理/执行流程/自己编写桌面图标的方法
linux·运维·服务器
G_H_S_3_2 小时前
【网络运维】KVM基础使用
linux·运维·网络·kvm
Lynnxiaowen2 小时前
今天我们利用Jenkins插件调用ansible
linux·运维·ansible·jenkins
_OP_CHEN2 小时前
【Linux系统编程】(十七)揭秘 Linux 进程创建与终止:从 fork 到 exit 的底层逻辑全解析
linux·运维·服务器·操作系统·shell·进程·进程创建与终止
草莓熊Lotso2 小时前
Makefile 完全指南:从入门到工程化,自动化构建不再难
linux·运维·服务器·人工智能·经验分享·后端·自动化
wanhengidc11 小时前
云手机的适配性怎么样?
运维·服务器·安全·智能手机·云计算
jimy111 小时前
安卓里运行Linux
linux·运维·服务器