GitLab CI/CD 自动化部署-springBoot-demo示例

CI/CD 的核心概念是持续集成、持续交付和持续部署

  • CI 持续集成(Continuous Integration)
  • CD 持续交付(Continuous Delivery)
  • CD 持续部署(Continuous Deployment)

GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务。安装方法是参考GitLab在GitHub上的Wiki页面。
GitLab 是支持CI/CD的,当前项目使用的gitlab管理的代码,故自己尝试一下 jar的CI/CD。

参考

主要参考:GitLab CI/CD 自动化部署入门 ,手把手教你搭建 —— 从安装 Linux 到 GitLab 自动化部署(非常详细)
Gitlab CI 配置文件 .gitlab-ci.yaml 详解(上)
GitLab Runner的安装与使用
部署-gitlab克隆地址踩坑
Gitlab 安装gitlab-runner踩坑记录
什么是 CI/CD ?

操作

Linux服务器是使用的 公司内网测试服务 centos 7
gitlab的server端是由同事前不久部署的,版本 14.0.5
在这里插入图片描述
下载gitlab-runner,版本15.1.0

 wget https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
 ll

部署、授权、增加用户、安装、运行

cp gitlab-runner-linux-amd64 /usr/local/bin/gitlab-runner
 # 分配运行权限
 chmod +x /usr/local/bin/gitlab-runner
 ll /usr/local/bin/
 # 获取版本
 gitlab-runner -v
 # 创建用户
 useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
 # 安装 指定工作目录
 gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
 # 运行 
 gitlab-runner start
 # 注册 runner
gitlab-runner register
####
# 输入 gitlab 的访问地址
http://192.168.x.x:x
# 输入 runner token,把开 http://192.168.x.x:x/admin/runners 页面查看
xxxxxxx
# runner 描述,随便填
构建 runner-001 项目
# runner tag
runner-001
# 输入(选择) shell
shell
####

注册完成后,在页面 http://192.168.x.x:x/admin/runners 中查看
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建测试项目

结构如下
在这里插入图片描述

gitlab-ci.yml

# gitlab 持续CI配置

## 用于docker镜像
#image: ruby:2.1

## 用于docker服务
#services:
#  - postgres

## 定义在每个job之前运行的命令
before_script:
  - echo "----> start"

## 定义在每个job之后运行的命令
after_script:
  - echo "----> end"

## 定义构建变量-全局
variables:
  MVN_ECHO_1: "开始mvn编译打包"
  RUN_DIR_1: /home/gitlab-runner/server
  JAR_NAME_1: runner-spring-demo-1.0-SNAPSHOT.jar
## 定义构建阶段, 默认是(build、test、deploy),可以自定义名称 无限量(不能用 gitlab-ci的保留字)
stages:
  - build
  - deploy
cache: # 缓存-全局,job内有就覆盖全局的
  untracked: true # 缓存git中没有被跟踪的文件
  # $CI_JOB_NAME 缓存每个job、$CI_COMMIT_REF_NAME 缓存每个分支、
  # $CI_JOB_NAME/$CI_COMMIT_REF_NAME 缓存每个job且每个分支、$CI_JOB_STAGE/$CI_COMMIT_REF_NAME 缓存每个分支且每个stage
  #key: "$CI_JOB_NAME"
  paths: # 缓存 target 目录,mvn会清理。如果是前端项目 就可以缓存 依赖目录 如 node_modules 可以减少打包时间
    - target/
# 单独job,名字唯一-拉取项目
build:
  #cache: # job级别缓存,内容和全局配置一样
  #variables: [] # job级别变量,内容和全局配置一样,[] 是关闭全局变量
  #before_script: # job级别 job之前运行的命令,内容和全局配置一样
  #before_script: # job级别 job之后运行的命令,内容和全局配置一样
  #allow_failure: true # 设置一个job失败的之后并不影响后续的CI组件 默认false
  # 定义何时开始job。可以是on_success(前面stages的所有工作成功时才执行 默认),on_failure(前面stages中任意一个jobs失败后执行),
  # always(无论前面stages中jobs状态如何都执行)或者manual(手动执行)
  #when: on_success
  stage: build # 阶段名称 对应,stages
  tags: # runner 标签(注册runner时设置的,可在 admin->runner中查看)
    - runner_001
  script: # 脚本(执行的命令行)
    - cd ${CI_PROJECT_DIR} # 拉取项目的根目录
    - pwd
    - echo ${MVN_ECHO_1}
    - mvn clean validate  package -Dmaven.test.skip=true
  only: # 定义一列git分支,并为其创建job
    - master # 拉取分支
  #except: # 定义一列git分支,不创建job,和only对应
  artifacts: # 把 dist 的内容传递给下一个阶
    paths:
      - target/
      - archive/
deploy:
  stage: deploy
  tags:
    - runner_001
  script:
    - echo "开始部署>>jar"
    - mkdir -p ${RUN_DIR_1} # 创建目录,如果存在 不报错
    - /bin/cp -rf ${CI_PROJECT_DIR}/target/${JAR_NAME_1} ${RUN_DIR_1}/${JAR_NAME_1} # 使用系统原生cp强制覆盖 避免交互提示
    - /bin/cp -rf ${CI_PROJECT_DIR}/archive/start_server.sh ${RUN_DIR_1}/start_server.sh # 复制 启动脚本
    - cd ${RUN_DIR_1} # 跳转到 服务目录
    - chmod +x ${RUN_DIR_1}/start_server.sh # 授权运行权限
    - sh ${RUN_DIR_1}/start_server.sh restart # 重启
    - ps -ef | grep ${JAR_NAME_1} # 查看运行状态
    - tail ${RUN_DIR_1}/logs/runner-demo.log # 查看服务运行日志,可以看指定时间日志 info.`date +"%Y-%m-%d"`.0.log

start_server.sh

#!/bin/bash

#jar包路径
APP_PATH="/home/gitlab-runner/server/"
JAR_FILE_PATH="${APP_PATH}runner-spring-demo-1.0-SNAPSHOT.jar"
#环境变量 如果没有可空,dev test prod
# ACTIVE="-Dspring.profiles.active=test"
ACTIVE=""
#web项目检查,是否启动 此路径需要自己创建直接返回 ok,不填写则经过默认时间后认为服务启动
WEB_CHECK_URL=""
#console path 数据输出路径,即项目print的内容以及日志sdpt的内容会输出到此文件 /dev/null 为 消失,其他具体文件为输出到指定文件
CONSOLE_PATH="${APP_PATH}hup.out"
#预计项目多久启动
WEB_START_TIME=10

#jvm配置 值依次如下
#元空间初始大小
#元空间最大
#新生代初始空间
#堆栈初始大小
#堆栈最大空间
#垃圾回收器
#启动模式 使用server
#设置时区
#配置文件路径 -Dspring.config.location=${APP_PATH}etc/
JAVA_OPTS="-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=512M
-Xms256M
-Xmx4G
-XX:+UseG1GC
-Xss512k
-server
-Duser.timezone=GMT+08
"

#检查服务是否在运行
is_running(){
  pid=$(ps -ef |grep ${JAR_FILE_PATH}|grep -v grep|awk '{print $2}')
  #如果不存在返回1,存在返回0
  if [ -z "${pid}" ]; then
    return 1
  else
    return 0
  fi
}

#运行服务,如果服务运行中则进行提示
start_service(){
  echo `date +"%Y-%m-%d %H:%M:%S"` "开始启动服务..."
  is_running
  if [ $? -eq "0" ]; then
    echo `date +"%Y-%m-%d %H:%M:%S"` "${JAR_FILE_PATH} 已经在运行,线程id ${pid}"
  else
    #启动jar包,并且将输出扔入黑洞(即不保留输出)
    nohup java $JAVA_OPTS -jar $ACTIVE $JAR_FILE_PATH > $CONSOLE_PATH 2>&1 &
    if [ -n "$WEB_CHECK_URL" ]; then
      i=1
      start_ok=0
      while [ $start_ok -eq 0 ]
      do
          if [ $WEB_START_TIME -lt $i ]; then
            start_ok=1
            break
          fi
          back=$(curl -s ${WEB_CHECK_URL})
          if [ "$back" == "ok" ]; then
            start_ok=2
            break
          fi
          let i++
          sleep 1
      done
      if [ $start_ok -eq 2 ]; then
        echo "服务已启动"
      else
        echo `date +"%Y-%m-%d %H:%M:%S"` "服务未在规定时间内正确运行(${WEB_START_TIME}),请检查日志"
      fi
    else
      echo `date +"%Y-%m-%d %H:%M:%S"` "等待${WEB_START_TIME}秒..."
      sleep $WEB_START_TIME
      echo `date +"%Y-%m-%d %H:%M:%S"` "服务已启动"
    fi
  fi
}

stop_service(){
  echo `date +"%Y-%m-%d %H:%M:%S"` "即将关闭程序..."
  is_running
  if [ $? -eq "1" ]; then
    echo "${JAR_FILE_PATH} 未运行,无需停止"
  else
    echo `date +"%Y-%m-%d %H:%M:%S"` "杀死进程(kill不带-9) ${pid}"
    kill $pid
    echo `date +"%Y-%m-%d %H:%M:%S"` "程序已关闭"
  fi
}

status(){
  is_running
  if [ $? -eq "0" ]; then
    echo "${JAR_FILE_PATH} 运行中,线程id ${pid}"
  else
    echo "${JAR_FILE_PATH} 未运行"
  fi
}

#重启服务
restart_service(){
  echo `date +"%Y-%m-%d %H:%M:%S"` "等待1秒,在执行停止..."
  sleep 1
  stop_service
  echo `date +"%Y-%m-%d %H:%M:%S"` "等待10秒,在执行重启..."
  sleep 10
  start_service
  echo `date +"%Y-%m-%d %H:%M:%S"` "服务重启结束..."
}

case "$1" in
  "start")
    echo `date +"%Y-%m-%d %H:%M:%S"` "开始执行服务启动..."
    start_service
    ;;
  "stop")
    echo `date +"%Y-%m-%d %H:%M:%S"` "开始执行服务停止..."
    stop_service
    ;;
  "restart")
    echo `date +"%Y-%m-%d %H:%M:%S"` "开始执行服务重启..."
    restart_service
    ;;
  "status")
    status
    ;;
  *)
    echo "命令为 start|stop|restart|status"
    exit 0
    ;;
esac

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.zy.demo.runner</groupId>
    <artifactId>runner-spring-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--基于Springboot-->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.1.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <skipTests>true</skipTests>

        <spring-boot.version>2.3.1.RELEASE</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-jar</id>
                        <phase>package</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-deploy-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

yml

server:
  port: 9980
  version: 2022072001
  servlet:
    context-path: /runner-demo/
spring:
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
logging:
  file:
    name: ./logs/runner-demo.log
  pattern:
    console: '%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}'

java

启动类
import cn.zy.demo.runner.util.EnvUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 启动类
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/7/20
 */
@SpringBootApplication
public class RunnerSpringDemoApplication {
    private static final Logger log = LoggerFactory.getLogger(RunnerSpringDemoApplication.class);
    public static void main(String[] args) {
        SpringApplication.run(RunnerSpringDemoApplication.class,args);
        String port = EnvUtil.getStr("server.port"),
                path = EnvUtil.getStr("server.servlet.context-path");
        log.info("http://127.0.0.1:{}{}",port,path);
    }
}
工具类
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;

/**
 * EnvUtil 类说明:
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/7/20
 */
@Component
public class EnvUtil implements EnvironmentAware {
    private static Environment env;
    @Override
    public void setEnvironment(@NotNull Environment environment) {
        env = environment;
    }
    public static String getStr(String key){
        return env.getProperty(key);
    }
}
测试接口
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

/**
 * RootController 类说明:
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/7/20
 */
@RestController
@RequestMapping("/")
public class RootController {
    private static final Logger logger = LoggerFactory.getLogger(RootController.class);
    private static final Date RUN_TIME = new Date();
    @Value("${server.version}")
    private String version;
    @RequestMapping
    public Map<String, Object> index(){
        Map<String, Object> map  = new TreeMap<>();
        map.put("now-time", new Date());
        map.put("run-time", RUN_TIME);
        map.put("version", version);
        logger.info("请求,{}",map);
        return map;
    }
}

测试CI CD

提交代码,登录 页面 http://192.168.x.x:x/admin/jobs,就可以看到触发的自动job。
可以看到定义的两个阶段job串行执行了,status 状态大概是:等待、执行中、已失败、已跳过等。点击 status状态,就可以看到日志了
在这里插入图片描述

大概分为几个运行阶段

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mvn编译的日志

在这里插入图片描述

第二个job

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

部署的日志

在这里插入图片描述

失败的情况

在这里插入图片描述

跳过的没有日志

因为依赖的上个job执行失败,就会跳过,也和yml中的配置有关系
在这里插入图片描述

提交项目,自动构建,查看发现失败

构建失败的原因是gitlab的克隆路径不对,因为gitlab是公司同事维护的,并且是在docker部署。联系同事一起解决问题
在这里插入图片描述
在这里插入图片描述
修复后
在这里插入图片描述
在这里插入图片描述

问题-部署失败-git版本低问题

报错

Running with gitlab-runner 15.1.0 (76984217)
  on 构建 runner001 项目 xymGSfhp
Preparing the "shell" executor
00:00
Using Shell executor...
Preparing environment
00:00
Running on localhost.localdomain...
Getting source from Git repository
00:01
Fetching changes with git depth set to 50...
重新初始化现存的 Git 版本库于 /home/gitlab-runner/builds/xymGSfhp/0/****/runner-spring-demo/.git/
fatal: git fetch-pack: expected shallow list
fatal: The remote end hung up unexpectedly
ERROR: Job failed: exit status 1

解决方式

# git版本太低 要升级
git --version
#git version 1.8.3.1
#安装源
yum install http://opensource.wandisco.com/centos/7/git/x86_64/wandisco-git-release-7-2.noarch.rpm
#安装git
#yum install git
#更新git
yum update git
#...
git --version
#git version 2.31.1

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

END

这只是后端的部署,前端部署 在cp文件到nginx下面就可以了,命令更少点。这只是个人的操作记录,请根据实际情况自行判断。

<think>好的,用户之前已经询问过关于使用CI/CD Pipeline部署Spring Boot应用的一般流程,现在他们进一步问的是如何新建一个Spring Boot项目并使用Pipeline进行部署。我需要确保回答覆盖两个部分:项目创建和Pipeline配置。 首先,用户可能已经有一定的Spring Boot基础,但可能需要详细的步骤来创建项目,特别是使用Spring Initializr或IDE的方式。我应该列出不同的方法,比如通过网页、IDEA或者命令行,这样用户可以选择自己熟悉的方式。 接下来是Pipeline部署部分。用户之前已经了解过Pipeline的基本流程,所以这次需要更具体的示例,可能针对不同的工具如Jenkins、GitLab CIGitHub Actions。需要给出具体的配置文件或脚本,并解释每个步骤的作用。 需要注意的是,用户可能在部署过程中遇到环境配置的问题,比如如何管理不同环境的配置文件(如application-prod.properties)。这里应该提到Spring Boot的Profile功能,以及如何在Pipeline中切换环境。 另外,容器化部署也是一个重要点,特别是Docker和Kubernetes的使用。用户可能希望了解如何将应用打包成镜像并推送到仓库,以及如何在部署时更新镜像。需要提供Dockerfile的示例和相关的Kubernetes命令。 还要考虑安全性,比如敏感信息的管理,如数据库密码或API密钥。这里应该建议使用CI/CD工具的秘密管理功能,如GitHub Actions的Secrets或者Jenkins的Credentials插件。 用户可能没有提到具体使用哪种CI/CD工具,所以需要覆盖多个常用工具的例子,比如Jenkinsfile、GitLab CI的.gitlab-ci.yml、GitHub Actions的workflow文件,以及AWS CodePipeline的配置。这样用户可以根据自己使用的工具选择相应的配置。 另外,最佳实践部分也很重要,比如环境分离、回滚策略、健康检查等。这些可以帮助用户避免常见问题,并提升部署的可靠性。 最后,用户可能需要知道如何测试整个流程,比如在部署后如何验证应用是否正常运行,可能需要提到使用curl命令或自动化测试工具进行健康检查。 总结一下,回答需要结构清晰,分步骤讲解项目创建和Pipeline部署,提供多种工具的具体配置示例,并涵盖最佳实践和常见问题处理,确保用户能够顺利实施从项目创建到自动化部署的整个流程。</think>以下是**从零创建一个 Spring Boot 项目并使用 CI/CD Pipeline 部署**的完整流程,涵盖项目初始化、Pipeline 配置和关键实践: --- ### 一、创建 Spring Boot 项目 #### 1. **通过 Spring Initializr 生成项目** - **方式 1:网页生成** 1. 访问 [https://start.spring.io](https://start.spring.io)。 2. 选择: - **Project**:Maven/Gradle - **Language**:Java - **Spring Boot**:最新稳定版 - **Dependencies**:添加 `Spring Web`(构建 REST API 必备)。 3. 点击 **Generate** 下载 ZIP 文件,解压后导入 IDE(如 IntelliJ IDEA)。 - **方式 2:通过 IDEA 创建** 1. 打开 IntelliJ → New Project → Spring Initializr。 2. 配置项目元数据(Group、Artifact、包名)。 3. 勾选依赖项(如 `Spring Web`),完成创建。 #### 2. **验证项目结构** - 生成的项目应包含以下关键文件: ```bash src/ main/ java/com/example/demo/DemoApplication.java # 启动类 resources/ application.properties # 配置文件 pom.xml # 或 build.gradle(依赖管理) ``` #### 3. **编写示例接口** 在 `src/main/java` 下创建 `HelloController.java`: ```java @RestController public class HelloController { @GetMapping("/hello") public String hello() { return "Hello, Pipeline!"; } } ``` #### 4. **本地运行测试** 执行启动类 `DemoApplication`,访问 `http://localhost:8080/hello`,确认返回成功。 --- ### 二、配置 CI/CD Pipeline 选择一种 CI/CD 工具(如 GitHub Actions、Jenkins 或 GitLab CI),以下是具体配置示例--- #### **方案 1:GitHub Actions(推荐)** 1. **在项目根目录创建 `.github/workflows/deploy.yml`**: ```yaml name: Deploy Spring Boot App on: push: branches: [ "main" ] # 仅监听 main 分支的推送 jobs: build-and-deploy: runs-on: ubuntu-latest steps: # 拉取代码 - name: Checkout uses: actions/checkout@v4 # 设置 Java 环境 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' # 构建并打包 JAR - name: Build with Maven run: mvn clean package -DskipTests # 若需测试则去掉 -DskipTests # 部署到服务器(示例:通过 SSH) - name: Deploy to Server uses: appleboy/scp-[email protected] with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} password: ${{ secrets.SSH_PASSWORD }} source: "target/*.jar" target: "/home/user/app/" - name: Restart Service uses: appleboy/ssh-[email protected] with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} password: ${{ secrets.SSH_PASSWORD }} script: | systemctl stop my-spring-app cp /home/user/app/*.jar /opt/my-spring-app/ systemctl start my-spring-app ``` 2. **配置 Secrets**: -GitHub 仓库的 **Settings → Secrets → Actions** 中添加: - `SSH_HOST`:服务器 IP - `SSH_USER`:SSH 用户名 - `SSH_PASSWORD`:SSH 密码 --- #### **方案 2:Jenkins Pipeline** 1. **安装 Jenkins 插件**:确保已安装 `Git`、`Maven Integration`、`Pipeline` 插件。 2. **创建 Jenkinsfile**(项目根目录): ```groovy pipeline { agent any stages { stage('Checkout') { steps { git 'https://github.com/your-username/your-repo.git' } } stage('Build') { steps { sh 'mvn clean package' } } stage('Deploy') { steps { sshagent(['ssh-credentials-id']) { sh 'scp target/*.jar user@server:/opt/my-spring-app/' sh 'ssh user@server "systemctl restart my-spring-app"' } } } } } ``` 3. **配置 Jenkins Job**: - 新建 Pipeline 任务,选择 **Pipeline script from SCM**,指定 Git 仓库和 Jenkinsfile 路径。 --- #### **方案 3:Docker 化部署(进阶)** 1. **添加 Dockerfile**(项目根目录): ```dockerfile FROM eclipse-temurin:17-jdk-jammy VOLUME /tmp ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} app.jar ENTRYPOINT ["java", "-jar", "/app.jar"] ``` 2. **修改 Pipeline 步骤**(以 GitHub Actions 为例): ```yaml - name: Build Docker Image run: | docker build -t my-spring-app:latest . docker tag my-spring-app:latest your-docker-registry/my-spring-app:latest docker push your-docker-registry/my-spring-app:latest - name: Deploy to Kubernetes run: | kubectl set image deployment/my-spring-app my-spring-app=your-docker-registry/my-spring-app:latest ``` --- ### 三、关键实践与注意事项 1. **环境分离**: - 使用 `application-{profile}.properties`(如 `application-prod.properties`)管理不同环境配置。 - 在 Pipeline 中通过 `-Dspring.profiles.active=prod` 激活生产环境。 2. **安全优化**: - 避免在代码中硬编码敏感信息,使用环境变量或 Secrets 管理(如数据库密码)。 - 限制服务器 SSH 访问权限,推荐使用密钥认证替代密码。 3. **回滚机制**: - 在 Pipeline 中增加健康检查,失败时自动回滚旧版本。 - 使用 Docker 镜像 Tag 或 Kubernetes 版本控制实现快速回滚。 4. **监控集成**: - 启用 Spring Boot Actuator 的 `/actuator/health` 端点。 - 集成 Prometheus + Grafana 监控 JVM 状态和接口性能。 --- ### 四、完整流程总结 1. **创建项目** → 2. **本地开发** → 3. **编写 Pipeline 脚本** → 4. **配置 CI/CD 工具** → 5. **自动化部署** → 6. **监控与维护** 如果需要更详细的某一步骤(如 Kubernetes 部署或蓝绿发布),可以进一步说明!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值