Git + Maven Java 项目部署实战全指南

Git + Maven Java 项目部署实战全指南

基于华为云香港区全新 ecs-fddb 集群(4 台 c6.large_2),从 Git 版本控制到 Maven 构建管理,再到 Jenkins CI/CD 自动化部署的完整学习路径。所有命令、输出、踩坑均为真实操作记录。


目录

一、基础知识篇

  • [1.1 Git 版本控制基础](#1.1 Git 版本控制基础)
  • [1.2 Maven 项目管理基础](#1.2 Maven 项目管理基础)
  • [1.3 Java 项目结构规范](#1.3 Java 项目结构规范)

二、环境搭建篇

  • [2.1 开发环境配置](#2.1 开发环境配置)
  • [2.2 服务器环境准备](#2.2 服务器环境准备)

三、项目构建篇

  • [3.1 Maven 项目创建与配置](#3.1 Maven 项目创建与配置)
  • [3.2 依赖管理最佳实践](#3.2 依赖管理最佳实践)

四、自动化部署篇

  • [4.1 Jenkins 自动化部署](#4.1 Jenkins 自动化部署)
  • [4.2 部署流程设计](#4.2 部署流程设计)

五、高级应用篇

  • [5.1 多环境配置管理](#5.1 多环境配置管理)
  • [5.2 持续集成/持续部署(CI/CD)](#5.2 持续集成/持续部署(CI/CD))
  • [5.3 容器化部署](#5.3 容器化部署)

六、实战案例篇

  • [6.1 Spring Boot 项目部署](#6.1 Spring Boot 项目部署)
  • [6.2 微服务架构部署](#6.2 微服务架构部署)
  • [6.3 企业级部署方案](#6.3 企业级部署方案)

七、问题排查与优化篇

  • [7.1 常见问题排查](#7.1 常见问题排查)
  • [7.2 性能优化](#7.2 性能优化)
  • [7.3 最佳实践总结](#7.3 最佳实践总结)

附录

  • [A. 服务器集群拓扑](#A. 服务器集群拓扑)
  • [B. 常用命令速查](#B. 常用命令速查)
  • [C. 学习路径建议](#C. 学习路径建议)

一、基础知识篇

1.1 Git 版本控制基础

1.1.1 Git 核心概念

Git 是一个分布式版本控制系统(Distributed Version Control System, DVCS)。与 SVN 等集中式系统不同,每个开发者本地都拥有完整的仓库副本。

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        Git 工作流三区模型                         │
│                                                                 │
│   Working        git add       Staging        git commit      │
│   Directory ──────────────────→ Area ─────────────────────────→│
│   (工作目录)                    (暂存区)                        │
│                                                                 │
│      │ git checkout / git restore                               │
│      └────────────────────────────────────────────────────────  │
│                                                                 │
│                                                                 │
│   ┌──────────────────────────────────────────────────────────┐  │
│   │              Local Repository (.git/)                     │  │
│   │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐     │  │
│   │  │ Commit  │←─│ Commit  │←─│ Commit  │←─│ HEAD    │     │  │
│   │  │  a1b2c3 │  │  d4e5f6 │  │  g7h8i9 │  │ → main  │     │  │
│   │  └─────────┘  └─────────┘  └─────────┘  └─────────┘     │  │
│   └──────────────────────────────────────────────────────────┘  │
│                          │ git push / git fetch                 │
│                          ▼                                      │
│   ┌──────────────────────────────────────────────────────────┐  │
│   │              Remote Repository (GitHub/GitLab/Gitee)      │  │
│   └──────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

四个核心区域

区域 英文 说明 典型命令
工作目录 Working Directory 你实际编辑文件的地方,文件系统上的真实文件 vim App.java
暂存区 Staging Area / Index 准备提交的文件快照,"购物车"概念 git add
本地仓库 Local Repository .git/ 目录,存储所有提交历史和版本 git commit
远程仓库 Remote Repository GitHub/GitLab 等托管平台 git push / git pull

核心概念

概念 说明 类比
Commit(提交) 一次代码快照,包含 SHA-1 哈希、作者、时间、变更内容 游戏存档
Branch(分支) 指向某个 Commit 的指针,允许并行开发 平行宇宙
HEAD 指向当前所在分支/Commit 的指针 "你现在在哪"
Merge(合并) 将一个分支的变更合并到另一个分支 拼图
Tag(标签) 为特定 Commit 打标记(通常用于发版) 里程碑标记
1.1.2 Git 配置实战

在新服务器上的完整 Git 配置流程:

bash 复制代码
# === 1. 用户信息配置 ===
$ git config --global user.name "DevOps Engineer"
$ git config --global user.email "devops@example.com"

# === 2. 常用配置优化 ===
# 彩色输出
$ git config --global color.ui auto
# 默认分支名
$ git config --global init.defaultBranch main
# 别名(提高效率)
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
$ git config --global alias.lg "log --oneline --graph --all --decorate"
# 换行符处理(Windows/Linux 协作)
$ git config --global core.autocrlf input

# === 3. 查看配置 ===
$ git config --global --list
user.name=DevOps Engineer
user.email=devops@example.com
color.ui=auto
init.defaultBranch=main
alias.co=checkout
alias.br=branch
alias.lg=log --oneline --graph --all --decorate
core.autocrlf=input
参数 作用 说明
user.name 提交者显示名 会出现在每次 commit 的 Author 字段
user.email 提交者邮箱 与 GitHub 账号邮箱一致才能关联贡献图
core.autocrlf 换行符自动转换 input 表示提交时 CRLF→LF,检出时不转换
init.defaultBranch 默认分支名 master 改为 main(GitHub 2020 年起)
alias.lg 彩色日志图 最常用的别名之一,一目了然看分支拓扑
1.1.3 常用 Git 命令实战
bash 复制代码
# ====== 仓库初始化 ======
$ mkdir my-java-project && cd my-java-project
$ git init                          # 初始化本地仓库
$ git remote add origin git@github.com:user/my-java-project.git

# ====== 日常开发流程 ======
$ git status                        # 查看工作区状态
$ git diff                          # 查看未暂存的变更
$ git add src/main/java/App.java    # 添加单个文件到暂存区
$ git add .                         # 添加所有变更
$ git commit -m "feat: add App.java"  # 提交
$ git push origin main              # 推送到远程

# ====== 分支操作 ======
$ git branch feature-login          # 创建分支
$ git checkout feature-login         # 切换分支
$ git checkout -b feature-payment   # 创建并切换到新分支
$ git merge feature-login            # 合并分支(在目标分支上执行)
$ git branch -d feature-login        # 删除已合并的分支

# ====== 查看历史 ======
$ git log                           # 查看提交历史
$ git log --oneline                  # 单行模式
$ git log --oneline --graph --all    # 图形化显示所有分支
$ git show HEAD                     # 查看最新提交的详细变更
$ git blame src/main/java/App.java  # 查看每行代码的作者
1.1.4 分支管理策略
复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      Git Flow 分支模型                           │
│                                                                 │
│  main ──●────────────●──────────────────●────────────●──→       │
│          │\          /│                  │\          /│          │
│          │ ●────────● │                  │ ●────────● │          │
│          │  develop   │                  │  develop   │          │
│          │   │\    /│                    │            │          │
│          │   │ ●──● │                    │            │          │
│          │   │ feature                  │            │          │
│          │                              │            │          │
│          ●──────────────────────────────●            │          │
│           release/v1.0                               │          │
│                                                      │          │
│                                              ●───────●          │
│                                               hotfix            │
│                                                                 │
│  分支类型:                                                       │
│  ┌──────────┬──────────────────────────────────────────────┐    │
│  │ main     │ 生产就绪代码,只接受 merge,不直接 commit      │    │
│  │ develop  │ 开发主线,功能分支的合并目标                    │    │
│  │ feature/ │ 功能开发分支,从 develop 切出,合并回 develop   │    │
│  │ release/ │ 发布准备分支,从 develop 切出,合并到 main+develop│   │
│  │ hotfix/  │ 紧急修复分支,从 main 切出,合并到 main+develop │    │
│  └──────────┴──────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

Git Flow vs GitHub Flow 对比

维度 Git Flow GitHub Flow
分支数量 5 类(main/develop/feature/release/hotfix) 2 类(main/feature)
适用场景 有明确发布周期的项目(如企业软件) 持续部署的 Web 服务
复杂度 高,需要团队纪律 低,适合快速迭代
发布方式 release 分支 → main 打 tag 合并到 main 即触发部署
回滚 revert commit 或从 main 切 hotfix revert 或 redeploy 上一个版本
代表用户 传统企业、Android SDK GitHub、Netflix、Etsy
1.1.5 代码冲突解决实战
bash 复制代码
# 场景:两个开发者修改了同一个文件的同一行

$ git merge feature-login
Auto-merging src/main/java/UserService.java
CONFLICT (content): Merge conflict in src/main/java/UserService.java
Automatic merge failed; fix conflicts and then commit the result.

# 查看冲突文件
$ git status
Unmerged paths:
  both modified:   src/main/java/UserService.java

# 冲突标记在文件中
# <<<<<<< HEAD
#         return userRepository.findById(id);          // 当前分支(main)的代码
# =======
#         return userRepository.findActiveById(id);     // 合并分支(feature-login)的代码
# >>>>>>> feature-login

# 方式一:手动编辑 → 删除冲突标记 → git add → git commit
# 方式二:选择一方
$ git checkout --ours src/main/java/UserService.java    # 保留当前分支版本
$ git checkout --theirs src/main/java/UserService.java  # 保留合并分支版本
# 方式三:使用合并工具
$ git mergetool

# 完成合并
$ git add src/main/java/UserService.java
$ git commit -m "merge: resolve conflict in UserService"

冲突预防策略

策略 方法 效果
频繁拉取 每天开始工作前 git pull 减少分歧累积
小步提交 每个功能点独立 Commit 冲突范围小,易解决
任务拆分 避免多人同时改同一文件 从源头减少冲突
沟通机制 修改公共模块前群内通知 避免"撞车"

1.2 Maven 项目管理基础

1.2.1 Maven 核心概念

Maven(Yiddish 语 "知识的积累者")是 Apache 旗下的 Java 项目构建与依赖管理工具。它通过 约定优于配置(Convention over Configuration)原则,标准化了 Java 项目的构建流程。

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    Maven 核心体系                                │
│                                                                 │
│   ┌──────────────────────────────────────────────────────┐      │
│   │                   POM (Project Object Model)           │      │
│   │                    pom.xml                             │      │
│   │  ┌──────────┐  ┌──────────┐  ┌──────────────────┐    │      │
│   │  │  GAV 坐标 │  │ 依赖管理  │  │ 构建配置         │    │      │
│   │  └──────────┘  └──────────┘  └──────────────────┘    │      │
│   └──────────────────────────────────────────────────────┘      │
│                          │                                       │
│          ┌───────────────┼───────────────┐                      │
│          ▼               ▼               ▼                      │
│   ┌──────────┐    ┌──────────┐    ┌──────────┐                  │
│   │ 本地仓库  │    │ 中央仓库  │    │ 私服     │                  │
│   │ ~/.m2/   │    │ Maven    │    │ Nexus/   │                  │
│   │          │    │ Central  │    │ Artifactory│                │
│   └──────────┘    └──────────┘    └──────────┘                  │
│                                                                 │
│   依赖解析顺序: 本地仓库 → 私服 → 中央仓库                        │
└─────────────────────────────────────────────────────────────────┘

Maven 核心三要素

要素 说明 作用
POM(项目对象模型) pom.xml 文件 描述项目信息、依赖、构建配置的 XML 文件
依赖管理 Dependency Management 自动下载和管理项目所需的三方库
构建生命周期 Build Lifecycle 定义从编译到部署的标准化阶段
1.2.2 Maven 构建生命周期(Build Lifecycle)

Maven 有三套相互独立的生命周期,每套生命周期由多个阶段(Phase)按序组成:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                   Maven 三套生命周期                              │
│                                                                 │
│   Default Lifecycle(核心:处理项目构建和部署)                   │
│   ┌─────────┐  ┌──────────┐  ┌─────────┐  ┌──────────┐         │
│   │ compile │─→│ test     │─→│ package │─→│ install  │─→ deploy│
│   │ 编译源码 │  │ 运行测试  │  │ 打包JAR  │  │ 安装到本地│  部署到远程│
│   └─────────┘  └──────────┘  └─────────┘  └──────────┘         │
│                                                                 │
│   Clean Lifecycle(清理项目)                                    │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐                        │
│   │pre-clean│─→│  clean  │─→│post-clean│                        │
│   └─────────┘  └─────────┘  └─────────┘                        │
│                    │ 删除 target/ 目录                           │
│                                                                 │
│   Site Lifecycle(生成项目站点和文档)                            │
│   ┌─────────┐  ┌─────────┐  ┌──────────┐  ┌─────────┐         │
│   │pre-site │─→│  site   │─→│post-site │─→│site-deploy│        │
│   └─────────┘  └─────────┘  └──────────┘  └─────────┘         │
└─────────────────────────────────────────────────────────────────┘

Default Lifecycle 核心阶段详解

阶段 (Phase) 作用 对应的插件目标 输出
validate 验证项目结构完整性 --- ---
compile 编译 src/main/java 下的源码 maven-compiler-plugin:compile target/classes/
test 编译并运行 src/test/java 的测试 maven-surefire-plugin:test target/test-classes/ + 测试报告
package 打包项目(JAR/WAR) maven-jar-plugin:jar target/xxx.jar
verify 集成测试验证 maven-failsafe-plugin:verify ---
install 安装 JAR 到本地仓库 maven-install-plugin:install ~/.m2/repository/.../
deploy 部署到远程仓库(私服) maven-deploy-plugin:deploy 远程仓库

⚠️ 关键区别 --- Phase vs Goal :Phase(阶段)是生命周期中的抽象步骤,Goal(目标)是插件中具体的任务。执行 mvn compile 时,Maven 会按生命周期顺序执行 validatecompile,而 compile 的 Goal 由 maven-compiler-plugin 提供。

1.2.3 Maven 坐标体系(GAV)

每个 Maven 项目通过 GAV(GroupId:ArtifactId:Version)三要素在仓库中唯一标识:

xml 复制代码
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
坐标元素 含义 命名规范 示例
groupId 组织/公司/团队标识 反向域名格式 com.mycompany, org.apache
artifactId 项目/模块名称 小写字母+连字符 spring-boot-starter-web, petclinic
version 版本号 语义化版本 3.2.0, 1.0.0-SNAPSHOT
packaging 打包类型(可选) JAR/WAR/POM jar(默认)
classifier 附属构件标识(可选) 区分 JDK 版本/平台 sources, javadoc, linux-x86_64

坐标在仓库中的物理路径

复制代码
groupId=org.springframework.boot
artifactId=spring-boot-starter-web
version=3.2.0

→ ~/.m2/repository/org/springframework/boot/spring-boot-starter-web/3.2.0/
                  └─── groupId 转为目录 ───┘ └ artifactId ┘ └ version ┘
                      spring-boot-starter-web-3.2.0.jar
                      spring-boot-starter-web-3.2.0.pom
1.2.4 Maven 仓库体系
复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    Maven 仓库依赖解析链路                         │
│                                                                 │
│   项目 pom.xml                                                   │
│      │                                                          │
│      ├─ 1. 本地仓库 (~/.m2/repository/)           ← 最优先     │
│      │   └─ 命中 → 直接使用                                     │
│      │                                                          │
│      ├─ 2. 私服(Nexus / Artifactory)            ← 团队共享    │
│      │   └─ 命中 → 下载到本地 → 使用                             │
│      │                                                          │
│      └─ 3. 中央仓库 (repo.maven.apache.org)        ← 公共仓库   │
│          └─ 命中 → 下载到私服/本地 → 使用                         │
│                                                                 │
│   首次下载后:本地仓库 → 直接从本地读取(无需网络)                │
│   SNAPSHOT 版本:每天检查一次更新,`-U` 参数强制检查              │
└─────────────────────────────────────────────────────────────────┘

本地仓库目录结构实例(真实):

bash 复制代码
$ ls ~/.m2/repository/org/springframework/boot/
spring-boot-starter-web/
  └── 3.2.0/
      ├── spring-boot-starter-web-3.2.0.jar     # JAR 包
      ├── spring-boot-starter-web-3.2.0.pom     # POM 依赖声明
      └── _remote.repositories                  # 来源标记

$ du -sh ~/.m2/repository/
1.4G    ~/.m2/repository/     # Spring Boot 项目的典型本地仓库大小

1.3 Java 项目结构规范

1.3.1 Maven 标准目录结构
复制代码
my-java-project/
├── pom.xml                              # Maven 项目描述文件(核心)
├── src/
│   ├── main/
│   │   ├── java/                        # Java 源代码
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── Application.java  # 启动类
│   │   │           ├── controller/       # 控制器层
│   │   │           ├── service/          # 业务逻辑层
│   │   │           ├── repository/       # 数据访问层
│   │   │           ├── model/            # 数据模型
│   │   │           └── config/           # 配置类
│   │   └── resources/                   # 资源文件(classpath 根目录)
│   │       ├── application.properties   # 主配置文件
│   │       ├── application-dev.yml      # 开发环境配置
│   │       ├── application-prod.yml     # 生产环境配置
│   │       ├── static/                  # 静态资源
│   │       └── templates/               # 模板文件(Thymeleaf 等)
│   └── test/
│       ├── java/                        # 测试代码
│       │   └── com/
│       │       └── example/
│       │           ├── controller/
│       │           └── service/
│       └── resources/                   # 测试资源
└── target/                              # 构建输出目录(.gitignore)
    ├── classes/                         # 编译后的 .class 文件
    ├── test-classes/                    # 测试代码编译结果
    ├── surefire-reports/                # 测试报告
    └── my-app.jar                       # 最终打包产物

目录职责对照

目录 作用 打包后位置 说明
src/main/java 业务源代码 target/classes/ 编译后合并到 JAR
src/main/resources 配置文件、静态资源 target/classes/ 与源码同处 classpath 根
src/test/java 单元测试 target/test-classes/ 不打入最终 JAR
src/test/resources 测试专用配置 target/test-classes/ 覆盖 main 同名配置
target/ 构建输出(自动生成) --- 每次 mvn clean 删除
1.3.2 pom.xml 核心配置详解
xml 复制代码
<?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">

    <!-- ====== 1. 基础信息 ====== -->
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>         <!-- 组织/公司标识 -->
    <artifactId>my-java-app</artifactId>      <!-- 项目名称 -->
    <version>1.0.0-SNAPSHOT</version>        <!-- 版本号 -->
    <packaging>jar</packaging>               <!-- 打包类型:jar/war/pom -->
    <name>My Java Application</name>
    <description>A sample Maven project</description>

    <!-- ====== 2. 属性定义(集中管理版本号) ====== -->
    <properties>
        <java.version>21</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot.version>3.2.0</spring-boot.version>
        <junit.version>5.10.1</junit.version>
    </properties>

    <!-- ====== 3. 依赖管理 ====== -->
    <dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

        <!-- JUnit 5 测试 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>    <!-- 只在测试阶段使用 -->
        </dependency>
    </dependencies>

    <!-- ====== 4. 构建配置 ====== -->
    <build>
        <plugins>
            <!-- 编译插件:指定 Java 版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>

            <!-- Spring Boot Maven 插件:打包可执行 JAR -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>  <!-- 生成 Fat JAR -->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

pom.xml 各段详解

段落 关键元素 作用
基础信息 groupId/artifactId/version GAV 坐标,项目唯一标识
properties 自定义变量 集中管理版本号,避免"版本地狱"
dependencies 依赖声明 项目所需的第三方库
build/plugins 插件配置 编译、打包、测试等任务的具体执行者
1.3.3 依赖范围(Dependency Scope)详解

Maven 的 scope 控制依赖在什么阶段可用,直接影响 JAR 包大小和类路径:

Scope 编译时 测试时 运行时 打包 典型场景
compile(默认) 核心业务库:spring-boot-starter-web
test 测试框架:junit-jupiter, mockito
runtime JDBC 驱动:mysql-connector-j
provided Servlet API(容器已提供)
system 本地 JAR(已废弃,不推荐)

实战验证

bash 复制代码
# 查看项目的完整依赖树(含传递依赖和 scope)
$ mvn dependency:tree -Dincludes=org.springframework.boot

[INFO] --- dependency:3.6.1:tree ---
[INFO] com.mycompany:my-java-app:jar:1.0.0-SNAPSHOT
[INFO] \- org.springframework.boot:spring-boot-starter-web:jar:3.2.0:compile
[INFO]    +- org.springframework.boot:spring-boot-starter:jar:3.2.0:compile
[INFO]    +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.2.0:compile
[INFO]    \- org.springframework:spring-webmvc:jar:6.1.1:compile
#                                                                         ^^^^^^^
#                                                                        scope 标记

# 只查看编译期依赖(排除 test 和 provided)
$ mvn dependency:tree -Dscope=compile

# 查看有哪些冲突依赖
$ mvn dependency:tree -Dverbose=true

二、环境搭建篇

2.1 开发环境配置

2.1.1 JDK 安装与多版本管理
bash 复制代码
# ========== Ubuntu 24.04:使用 apt 安装 OpenJDK ==========
$ apt-get update
$ apt-get install -y openjdk-21-jdk

$ java --version
openjdk 21.0.11 2025-01-21
OpenJDK Runtime Environment (build 21.0.11+9-Ubuntu-124.04)
OpenJDK 64-Bit Server VM (build 21.0.11+9-Ubuntu-124.04, mixed mode, sharing)

$ javac --version
javac 21.0.11

# ========== 设置 JAVA_HOME ==========
$ echo "export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64" >> /etc/profile
$ echo "export PATH=\$JAVA_HOME/bin:\$PATH" >> /etc/profile
$ source /etc/profile

$ echo $JAVA_HOME
/usr/lib/jvm/java-21-openjdk-amd64

JDK 版本选择决策树

复制代码
需要长期支持? ────→ Yes ────→ JDK 21 LTS (支持到 2031 年)
    │                          JDK 17 LTS (支持到 2029 年)
    No
    │
    └──→ JDK 22+ (非 LTS,每 6 个月一个版本)
         适合尝鲜新特性,不适合生产环境
2.1.2 Maven 安装与环境变量
bash 复制代码
# ========== 方式一:apt 安装(推荐) ==========
$ apt-get install -y maven

$ mvn --version
Apache Maven 3.8.7
Maven home: /usr/share/maven
Java version: 21.0.11, vendor: Ubuntu
OS name: "linux", version: "6.8.0-52-generic", arch: "amd64"

# ========== 方式二:手动安装最新版 ==========
$ wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
$ tar -xzf apache-maven-3.9.6-bin.tar.gz -C /opt/
$ echo "export MAVEN_HOME=/opt/apache-maven-3.9.6" >> /etc/profile
$ echo "export PATH=\$MAVEN_HOME/bin:\$PATH" >> /etc/profile

Maven 配置文件:~/.m2/settings.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0
          https://maven.apache.org/xsd/settings-1.2.0.xsd">

    <!-- 本地仓库路径(默认 ~/.m2/repository) -->
    <localRepository>/data/maven-repo</localRepository>

    <!-- 镜像配置:加速依赖下载 -->
    <mirrors>
        <mirror>
            <id>aliyun-maven</id>
            <mirrorOf>central</mirrorOf>
            <name>阿里云 Maven 镜像</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </mirror>
    </mirrors>

    <!-- 私服认证(可选) -->
    <servers>
        <server>
            <id>my-nexus</id>
            <username>deployer</username>
            <password>${env.NEXUS_PASSWORD}</password>
        </server>
    </servers>
</settings>
配置项 作用 说明
localRepository 本地仓库路径 大型项目建议放到独立分区,避免 /home 写满
mirrors/mirror 中央仓库镜像 国内必配阿里云镜像,下载速度提升 10 倍+
mirrorOf 代理范围 central 只代理中央仓库;* 代理所有
servers/server 私服认证 用于 mvn deploy 时上传到私服
2.1.3 Git 安装与 SSH 密钥
bash 复制代码
# ========== 安装 Git ==========
$ apt-get install -y git

$ git --version
git version 2.43.0

# ========== SSH 密钥配置 ==========
$ ssh-keygen -t ed25519 -C "devops@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/root/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):    # CI/CD 场景建议留空
Your identification has been saved in /root/.ssh/id_ed25519
Your public key has been saved in /root/.ssh/id_ed25519.pub

$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3Nz... devops@example.com

# 添加到 GitHub/GitLab → Settings → SSH Keys → 粘贴上述公钥

# 验证连接
$ ssh -T git@github.com
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

2.2 服务器环境准备

2.2.1 集群拓扑

本次实战基于华为云香港区全新采购的 4 台 c6.large_2 规格 ECS:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│          华为云香港区 ecs-fddb 集群拓扑(Git + Maven 实战)        │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                  ecs-fddb-0001 (主控节点)                 │   │
│  │  ▪ 公网IP: 190.92.230.185    ▪ 内网IP: 192.168.0.5      │   │
│  │  ▪ 角色: Git Server + Jenkins Master + Maven Build      │   │
│  │  ▪ 服务: GitLab CE / Jenkins / SonarQube / Nexus         │   │
│  └──────────────────────┬──────────────────────────────────┘   │
│                         │                                       │
│      ┌──────────────────┼──────────────────┐                   │
│      ▼                  ▼                  ▼                   │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐                  │
│  │ecs-fddb  │    │ecs-fddb  │    │ecs-fddb  │                  │
│  │  -0002   │    │  -0003   │    │  -0004   │                  │
│  │          │    │          │    │          │                  │
│  │ 159.138. │    │ 190.92.  │    │ 121.91.  │                  │
│  │ 147.243  │    │ 231.53   │    │ 170.113  │                  │
│  │ .0.84    │    │ .0.214   │    │ .0.177   │                  │
│  │          │    │          │    │          │                  │
│  │ 开发环境  │    │ 测试环境  │    │ 生产环境  │                  │
│  └──────────┘    └──────────┘    └──────────┘                  │
└─────────────────────────────────────────────────────────────────┘

服务器规格明细

实例 公网 IP 内网 IP 规格 CPU 内存 角色
ecs-fddb-0001 190.92.230.185 192.168.0.5 c6.large_2 2vCPU 4GB Git Server + CI/CD Master
ecs-fddb-0002 159.138.147.243 192.168.0.84 c6.large_2 2vCPU 4GB 开发环境(DEV)
ecs-fddb-0003 190.92.231.53 192.168.0.214 c6.large_2 2vCPU 4GB 测试环境(TEST)
ecs-fddb-0004 121.91.170.113 192.168.0.177 c6.large_2 2vCPU 4GB 生产环境(PROD)

环境隔离策略

环境 用途 部署频率 访问控制
DEV(-0002) 开发联调、快速验证 每次 Push 自动部署 开发者 VPN 访问
TEST(-0003) 集成测试、QA 验收 每日构建自动部署 内网 + 白名单
PROD(-0004) 线上生产服务 手动审批后触发 仅运维可操作
2.2.2 批量环境初始化脚本
bash 复制代码
#!/bin/bash
# ============================================================
# ecs-fddb 集群批量初始化脚本
# 在每台服务器上依次执行
# ============================================================
set -e

echo "=== 服务器环境初始化 ==="
echo "Hostname: $(hostname)"
echo "OS: $(lsb_release -ds)"

# ---- 1. 系统更新 ----
echo ">>> Step 1: 系统更新..."
apt-get update -qq
apt-get upgrade -y -qq

# ---- 2. 基础工具 ----
echo ">>> Step 2: 基础工具..."
apt-get install -y -qq curl wget vim net-tools unzip zip tree htop

# ---- 3. Java 21 ----
echo ">>> Step 3: Java 21..."
apt-get install -y -qq openjdk-21-jdk
echo "export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64" >> /etc/profile
echo "export PATH=\$JAVA_HOME/bin:\$PATH" >> /etc/profile

# ---- 4. Maven ----
echo ">>> Step 4: Maven..."
apt-get install -y -qq maven

# ---- 5. Git ----
echo ">>> Step 5: Git..."
apt-get install -y -qq git

# ---- 6. SSH 免密 ----
echo ">>> Step 6: SSH 密钥..."
mkdir -p ~/.ssh && chmod 700 ~/.ssh
ssh-keygen -t ed25519 -N "" -C "$(hostname)" -f ~/.ssh/id_ed25519

echo "=== 初始化完成 ==="
java --version | head -1
mvn --version | head -2
git --version

三、项目构建篇

3.1 Maven 项目创建与配置

3.1.1 使用 Maven Archetype 创建项目
bash 复制代码
# ========== 方式一:快速创建 JAR 项目 ==========
$ mvn archetype:generate \
    -DgroupId=com.example \
    -DartifactId=hello-maven \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DarchetypeVersion=1.5 \
    -DinteractiveMode=false

[INFO] BUILD SUCCESS
[INFO] Total time:  3.456 s

$ tree hello-maven/
hello-maven/
├── pom.xml
└── src/
    ├── main/java/com/example/App.java
    └── test/java/com/example/AppTest.java

# ========== 方式二:创建 Spring Boot 项目 ==========
$ mvn archetype:generate \
    -DgroupId=com.example \
    -DartifactId=spring-boot-demo \
    -DarchetypeGroupId=org.springframework.boot \
    -DarchetypeArtifactId=spring-boot-starter-parent \
    -DarchetypeVersion=3.2.0 \
    -DinteractiveMode=false

常用 Archetype 速查

Archetype ID 用途 生成内容
maven-archetype-quickstart 最简 Java 项目 App.java + AppTest.java
maven-archetype-webapp Java Web 项目 web.xml + index.jsp
spring-boot-starter-parent Spring Boot 项目 Application.java + application.properties
maven-archetype-multimodule 多模块项目 父 POM + 子模块目录
3.1.2 常用 Maven 命令实战
bash 复制代码
# ========== 完整构建流程 ==========
$ cd hello-maven/

# 1. 清理上次构建产物
$ mvn clean
[INFO] Deleting /root/hello-maven/target

# 2. 仅编译源码(不运行测试)
$ mvn compile
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 1 source file to /root/hello-maven/target/classes

# 3. 运行单元测试
$ mvn test
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

# 4. 打包(JAR)
$ mvn package
[INFO] Building jar: /root/hello-maven/target/hello-maven-1.0.0.jar
$ ls -lh target/
-rw-r--r-- 1 root root 3.2K target/hello-maven-1.0.0.jar

# 5. 安装到本地仓库
$ mvn install
[INFO] Installing /root/hello-maven/target/hello-maven-1.0.0.jar
to /root/.m2/repository/com/example/hello-maven/1.0.0/hello-maven-1.0.0.jar

# 6. 跳过测试执行(但编译测试代码)
$ mvn package -DskipTests

# 7. 完全跳过测试(不编译、不运行)
$ mvn package -Dmaven.test.skip=true

# 8. 强制更新 SNAPSHOT 依赖
$ mvn clean package -U

# 9. 并行构建(多模块项目加速)
$ mvn clean package -T 4     # 4 个线程并行

# 10. 离线模式(不检查远程仓库)
$ mvn clean package -o

命令组合与阶段关系

复制代码
mvn clean compile test package install deploy
    │     │       │    │       │       │        │
    │     └───┬───┘    │       │       │        │
    │      阶段1      阶段2   阶段3   阶段4     阶段5
    │      编译       测试    打包    本地安装   远程部署
    │
    删除 target/

3.2 依赖管理最佳实践

3.2.1 依赖传递与冲突解决

Maven 依赖传递遵循 最短路径优先 + 最先声明优先 原则:

复制代码
依赖传递示例:

A (你的项目)
├── B:2.0
│   └── X:1.0          ← 传递依赖 X:1.0(路径长度 2)
└── C:3.0
    └── X:2.0          ← 传递依赖 X:2.0(路径长度 2)

结果:X:1.0 和 X:2.0 路径长度相同 → 最先声明优先(B 在先)
→ 最终使用 X:1.0

实战:查看和排除冲突依赖

bash 复制代码
# 查看完整依赖树
$ mvn dependency:tree

# 查找冲突
$ mvn dependency:tree -Dverbose=true | grep -E "conflict|omitted"
[INFO] |  \- com.google.guava:guava:jar:30.1-jre:compile (version managed from 20.0)

# 排除传递依赖
xml 复制代码
<dependency>
    <groupId>com.example</groupId>
    <artifactId>some-lib</artifactId>
    <exclusions>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>     <!-- 已知有安全漏洞 -->
        </exclusion>
    </exclusions>
</dependency>
3.2.2 BOM(Bill of Materials)使用

在 Spring Boot 项目中,spring-boot-starter-parent 就是一个巨型 BOM:

xml 复制代码
<!-- 父 POM 中的 dependencyManagement 不会直接引入依赖,只是声明版本 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 子模块引用时不需要写版本号 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- 版本由 BOM 统一管理,无需显式声明 -->
    </dependency>
</dependencies>

BOM 的优势

优势 说明
版本一致性 全项目统一使用同一套依赖版本
避免冲突 传递依赖的版本冲突由 BOM 仲裁
简化配置 子模块不需要重复声明版本号
升级方便 只需修改 BOM 版本即可全项目升级

四、自动化部署篇

4.1 Jenkins 自动化部署

4.1.1 Jenkins 部署架构

基于 ecs-fddb-0001 部署 Jenkins,其余 3 台作为部署目标:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                 Jenkins CI/CD 部署流水线架构                      │
│                                                                 │
│   ecs-fddb-0001 (Jenkins Master :8080)                          │
│   ┌──────────────────────────────────────────────────────────┐  │
│   │  Pipeline: Git → Maven → Test → Package → Deploy → Notify │  │
│   │                                                            │  │
│   │  1. git clone    ──→ 从 Git Server 拉取代码                │  │
│   │  2. mvn test     ──→ 运行 58 个单元测试                     │  │
│   │  3. mvn package  ──→ 打包可执行 JAR (67MB)                 │  │
│   │  4. scp JAR      ──→ 传输到目标服务器                       │  │
│   │  5. ssh deploy   ──→ 重启 systemd 服务                      │  │
│   │  6. health check ──→ 验证部署成功                           │  │
│   │  7. DingTalk     ──→ 群消息通知                             │  │
│   └─────────────┬────────────────────────────────────────────┘  │
│                 │                                                │
│     ┌───────────┼───────────┐                                   │
│     ▼           ▼           ▼                                   │
│  ┌────────┐┌────────┐┌────────┐                                 │
│  │ -0002  ││ -0003  ││ -0004  │                                 │
│  │  DEV   ││  TEST  ││  PROD  │                                 │
│  │ :8081  ││ :8081  ││ :8081  │                                 │
│  └────────┘└────────┘└────────┘                                 │
└─────────────────────────────────────────────────────────────────┘
4.1.2 Jenkins 安装(WAR 包方式)
bash 复制代码
# ========== 在 ecs-fddb-0001 上执行 ==========

# 1. 创建 Jenkins 用户
$ useradd -m -s /bin/bash jenkins

# 2. 下载 Jenkins WAR(从官方源,避免阿里云镜像不完整)
$ wget https://get.jenkins.io/war-stable/2.555.2/jenkins.war -O /opt/jenkins/jenkins.war
$ ls -lh /opt/jenkins/jenkins.war
-rw-r--r-- 1 root root 96M /opt/jenkins/jenkins.war

# 3. 创建 systemd 服务
$ cat > /etc/systemd/system/jenkins.service << 'EOF'
[Unit]
Description=Jenkins CI Server
After=network.target

[Service]
Type=simple
User=jenkins
Environment="JENKINS_HOME=/var/lib/jenkins"
ExecStart=/usr/bin/java -jar /opt/jenkins/jenkins.war --httpPort=8080
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

# 4. 启动
$ systemctl daemon-reload
$ systemctl enable jenkins
$ systemctl start jenkins

$ systemctl status jenkins
● jenkins.service - Jenkins CI Server
   Active: active (running)

# 5. 获取初始管理员密码
$ cat /var/lib/jenkins/secrets/initialAdminPassword
a1b2c3d4e5f6g7h8    # 用此密码完成首次登录
4.1.3 Freestyle Job:Maven 构建部署

Job 配置(可直接导入的 XML)

xml 复制代码
<?xml version='1.1' encoding='UTF-8'?>
<project>
  <description>Spring PetClinic: Git Clone → Maven Build → Remote Deploy → Notify</description>
  <keepDependencies>false</keepDependencies>

  <!-- 构建触发器:每 2 小时轮询 SCM -->
  <triggers>
    <hudson.triggers.SCMTrigger>
      <spec>H */2 * * *</spec>
    </hudson.triggers.SCMTrigger>
  </triggers>

  <builders>
    <hudson.tasks.Shell>
      <command><![CDATA[#!/bin/bash
set -e
BUILD_START=$(date +%s)

echo "=== Git + Maven 自动化构建 ==="
echo "Java: $(java --version 2>&1 | head -1)"
echo "Maven: $(mvn --version 2>&1 | head -1)"
echo "Git: $(git --version)"

# Step 1: Maven 编译 + 测试
echo ">>> Step 1: mvn clean test..."
mvn clean test -q
echo "  ✅ Tests passed"

# Step 2: Maven 打包
echo ">>> Step 2: mvn package..."
mvn package -DskipTests -q
JAR_FILE=$(ls target/*.jar | head -1)
echo "  ✅ Package: $(du -h $JAR_FILE | cut -f1)"

# Step 3: 部署到目标服务器
echo ">>> Step 3: Deploy to ${DEPLOY_HOST}..."
scp ${JAR_FILE} ${DEPLOY_USER}@${DEPLOY_HOST}:/opt/app/
ssh ${DEPLOY_USER}@${DEPLOY_HOST} "sudo systemctl restart my-app"

# Step 4: 健康检查
sleep 5
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://${DEPLOY_HOST}:8081/actuator/health)
[ "$HTTP_CODE" = "200" ] && echo "  ✅ Deploy success" || echo "  ❌ Deploy FAILED"

# Step 5: 钉钉通知
BUILD_END=$(date +%s)
DURATION=$((BUILD_END - BUILD_START))
/opt/dingtalk-notify.sh "SUCCESS" "${JOB_NAME}" "#${BUILD_NUMBER}" "${DURATION}s" "http://${DEPLOY_HOST}:8081"
]]></command>
    </hudson.tasks.Shell>
  </builders>
</project>

4.2 部署流程设计

4.2.1 标准部署流程
复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    Git + Maven 标准部署流程                       │
│                                                                 │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐  │
│  │ 代码拉取  │───→│ 项目编译  │───→│ 单元测试  │───→│ 打包生成  │  │
│  │git clone │    │mvn compile│   │ mvn test │    │mvn package│  │
│  │git pull  │    │          │    │          │    │          │  │
│  └──────────┘    └──────────┘    └──────────┘    └────┬─────┘  │
│                                                       │        │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐         │        │
│  │ 通知告警  │←───│ 健康检查  │←───│ 远程部署  │←────────┘        │
│  │DingTalk  │    │curl /act │    │scp + ssh │                  │
│  │Webhook   │    │uator/heal│    │systemctl │                  │
│  └──────────┘    └──────────┘    └──────────┘                  │
└─────────────────────────────────────────────────────────────────┘

各阶段详解

阶段 命令 输入 输出 失败处理
代码拉取 git pull origin main 远程仓库 最新源码 重试 3 次,超时跳过
编译 mvn compile src/main/java/ target/classes/ 构建失败通知
测试 mvn test src/test/java/ 测试报告 标记 UNSTABLE
打包 mvn package -DskipTests target/classes/ target/*.jar 构建失败通知
远程部署 scp + ssh systemctl restart JAR 包 运行中的服务 回滚到上一版本
健康检查 curl /actuator/health 服务端口 HTTP 200 自动回滚
通知 DingTalk Webhook 构建结果 群消息 不影响构建结果
4.2.2 多环境部署策略
环境 触发方式 部署命令 验证方式
DEV(-0002) Push 到 develop 分支 scp → 192.168.0.84 curl :8081
TEST(-0003) Push 到 release/* 分支 scp → 192.168.0.214 集成测试套件
PROD(-0004) 手动审批 + Tag scp → 192.168.0.177 全量回归测试

五、高级应用篇

5.1 多环境配置管理

5.1.1 Spring Boot Profile 机制

Maven 构建时通过 -P (profile) 参数激活不同环境配置:

xml 复制代码
<!-- pom.xml -->
<profiles>
    <!-- 开发环境 -->
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <env.name>dev</env.name>
            <server.port>8080</server.port>
            <db.url>jdbc:mysql://192.168.0.84:3306/dev_db</db.url>
        </properties>
    </profile>

    <!-- 测试环境 -->
    <profile>
        <id>test</id>
        <properties>
            <env.name>test</env.name>
            <server.port>8081</server.port>
            <db.url>jdbc:mysql://192.168.0.214:3306/test_db</db.url>
        </properties>
    </profile>

    <!-- 生产环境 -->
    <profile>
        <id>prod</id>
        <properties>
            <env.name>prod</env.name>
            <server.port>8080</server.port>
            <db.url>${env.PROD_DB_URL}</db.url>  <!-- 从环境变量读取 -->
        </properties>
    </profile>
</profiles>

激活方式

bash 复制代码
# 命令行激活
$ mvn clean package -P test

# 多 Profile 同时激活
$ mvn clean package -P dev,debug

# 在 Jenkins 中通过参数传递
$ mvn clean package -P ${BUILD_ENV}
5.1.2 配置文件外化
bash 复制代码
# 外部配置文件优先于 JAR 内的配置
$ java -jar my-app.jar --spring.config.location=/etc/my-app/application.yml

# 环境变量覆盖
$ export SERVER_PORT=8081
$ java -jar my-app.jar        # 自动读取 SERVER_PORT 环境变量

# 系统属性覆盖
$ java -Dserver.port=8081 -jar my-app.jar

Spring Boot 配置优先级(由高到低)

复制代码
1. 命令行参数(--server.port=8081)
2. 系统属性(-Dserver.port=8081)
3. 操作系统环境变量(SERVER_PORT)
4. application-{profile}.yml(JAR 外部)
5. application-{profile}.yml(JAR 内部)
6. application.yml(JAR 外部)
7. application.yml(JAR 内部)

5.2 持续集成/持续部署(CI/CD)

5.2.1 CI/CD 流程设计
复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    CI/CD 完整流水线                               │
│                                                                 │
│  ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐         │
│  │  代码    │   │   CI     │   │   制品   │   │   CD     │         │
│  │  提交    │──→│  流水线  │──→│   仓库   │──→│  流水线  │         │
│  └─────────┘   └─────────┘   └─────────┘   └─────────┘         │
│       │             │              │              │              │
│  git push       mvn test      Nexus/Docker   scp + ssh         │
│                 mvn package   Registry       systemctl          │
│                 SonarQube                    健康检查            │
│                                                                 │
│  触发条件:       质量控制:       产物管理:        部署验证:       │
│  Push/Tag/PR    Test覆盖率>80%  JAR/Docker      所有环境         │
│                 代码异味=0      Image            自动回滚         │
└─────────────────────────────────────────────────────────────────┘
阶段 工具 目标
代码检查 SonarQube + Checkstyle 代码质量门禁
单元测试 JUnit 5 + JaCoCo 覆盖率 ≥ 80%
安全扫描 OWASP Dependency-Check 无高危漏洞
制品管理 Nexus / Docker Registry 版本化存储
部署 Jenkins + SSH 自动化、可回滚
5.2.2 部署回滚策略
复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      部署回滚机制                                 │
│                                                                 │
│   当前版本: my-app-2.1.0.jar          ❌ 健康检查失败             │
│   上一版本: my-app-2.0.0.jar.bak      ✅ 立即可用                 │
│                                                                 │
│   回滚步骤:                                                       │
│   1. systemctl stop my-app                                      │
│   2. cp my-app-2.0.0.jar.bak my-app.jar    ← 恢复旧版本          │
│   3. systemctl start my-app                                     │
│   4. curl /actuator/health                    ← 验证恢复          │
│   5. 发送回滚通知(钉钉/邮件)                                    │
│                                                                 │
│   ⏱️ 目标回滚时间: < 30 秒                                       │
└─────────────────────────────────────────────────────────────────┘

回滚触发条件

条件 检测方式 响应
HTTP 非 200 curl 健康检查 立即回滚
响应超时 > 5s curl --max-time 立即回滚
错误率 > 1% 日志监控告警 人工确认后回滚
内存/CPU 异常 监控面板告警 人工确认后回滚

5.3 容器化部署

5.3.1 Dockerfile 编写
dockerfile 复制代码
# ========== 多阶段构建(Multi-stage Build) ==========

# Stage 1: Maven 构建(大镜像,仅用于编译)
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B    # 预下载依赖(利用 Docker 层缓存)
COPY src ./src
RUN mvn clean package -DskipTests

# Stage 2: 运行时镜像(小镜像,仅 JRE)
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder /app/target/*.jar app.jar
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"]

多阶段构建 vs 传统构建

维度 传统 Dockerfile 多阶段构建
最终镜像大小 ~600MB(含 JDK + Maven) ~200MB(仅 JRE)
构建依赖 需要 Maven 镜像 构建层自动丢弃
安全性 JDK 暴露更多攻击面 仅 JRE + 非 root 用户
Dockerfile 数量 需要 2 个文件 1 个文件搞定
5.3.2 Docker Compose 编排
yaml 复制代码
# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - DB_URL=jdbc:mysql://db:3306/app_db
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 3s
      retries: 3

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: app_db
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      retries: 5

volumes:
  mysql_data:
5.3.3 Maven 构建 Docker 镜像
xml 复制代码
<!-- pom.xml: docker-maven-plugin 配置 -->
<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.43.4</version>
    <configuration>
        <images>
            <image>
                <name>my-registry.com/${project.artifactId}:${project.version}</name>
                <build>
                    <from>eclipse-temurin:21-jre-alpine</from>
                    <assembly>
                        <descriptorRef>artifact</descriptorRef>
                    </assembly>
                </build>
            </image>
        </images>
    </configuration>
</plugin>
bash 复制代码
# 一条命令完成:Maven 打包 + Docker 构建 + 推送
$ mvn clean package docker:build docker:push

六、实战案例篇

6.1 Spring Boot 项目部署

6.1.1 Spring PetClinic 完整部署流程

以 Spring PetClinic(官方示例项目)为例,完整演示从 0 到生产:

bash 复制代码
# ========== 1. 克隆项目 ==========
$ git clone https://github.com/spring-projects/spring-petclinic.git
$ cd spring-petclinic

# ========== 2. 本地验证 ==========
$ mvn clean test
[INFO] Tests run: 58, Failures: 0, Errors: 0, Skipped: 2
[INFO] BUILD SUCCESS

# ========== 3. 打包 ==========
$ mvn clean package -DskipTests
[INFO] BUILD SUCCESS
$ ls -lh target/spring-petclinic-4.0.0-SNAPSHOT.jar
-rw-r--r-- 67M target/spring-petclinic-4.0.0-SNAPSHOT.jar

# ========== 4. 部署到目标服务器 ==========
$ scp target/*.jar deploy@192.168.0.177:/opt/petclinic/
$ ssh deploy@192.168.0.177 "sudo systemctl restart petclinic"

# ========== 5. 验证 ==========
$ curl -s http://192.168.0.177:8081/actuator/health
{"status":"UP"}
6.1.2 配置文件外部化
bash 复制代码
# 目标服务器上的外部配置
$ cat /opt/petclinic/config/application-prod.yml
server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://192.168.0.214:3306/petclinic
    username: ${DB_USER}
    password: ${DB_PASSWORD}

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics

6.2 微服务架构部署

6.2.1 Maven 多模块项目结构
复制代码
microservice-platform/
├── pom.xml                              # 父 POM(packaging: pom)
├── common/                              # 公共模块
│   ├── pom.xml
│   └── src/main/java/.../
├── service-user/                        # 用户服务
│   ├── pom.xml
│   └── src/main/java/.../
├── service-order/                       # 订单服务
│   ├── pom.xml
│   └── src/main/java/.../
├── service-gateway/                     # API 网关
│   ├── pom.xml
│   └── src/main/java/.../
└── docker-compose.yml                   # 统一编排

父 POM 核心配置

xml 复制代码
<!-- 父 pom.xml -->
<groupId>com.company</groupId>
<artifactId>microservice-platform</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>

<modules>
    <module>common</module>
    <module>service-user</module>
    <module>service-order</module>
    <module>service-gateway</module>
</modules>

<!-- dependencyManagement:统一管理版本,不实际引入依赖 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2023.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
6.2.2 一键构建所有模块
bash 复制代码
# 在根目录执行,自动按依赖顺序构建所有子模块
$ mvn clean package -T 4    # 4 线程并行

[INFO] Reactor Summary:
[INFO] microservice-platform 1.0.0 ........ SUCCESS [0.1s]
[INFO] common ............................... SUCCESS [3.2s]
[INFO] service-user ......................... SUCCESS [8.5s]
[INFO] service-order ........................ SUCCESS [7.1s]
[INFO] service-gateway ...................... SUCCESS [5.3s]
[INFO] BUILD SUCCESS

6.3 企业级部署方案

6.3.1 高可用部署架构
复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    企业级高可用部署架构                            │
│                                                                 │
│                          ┌──────────┐                           │
│                          │   DNS    │                           │
│                          │ 轮询解析  │                           │
│                          └────┬─────┘                           │
│                               │                                 │
│                    ┌──────────┴──────────┐                      │
│                    ▼                     ▼                      │
│             ┌────────────┐        ┌────────────┐               │
│             │  Nginx LB  │        │  Nginx LB  │               │
│             │  (主)       │← keep →│  (备)       │               │
│             │  :80/:443  │  alive │  :80/:443  │               │
│             └──────┬─────┘        └──────┬─────┘               │
│                    │                     │                      │
│         ┌──────────┼──────────┐          │                      │
│         ▼          ▼          ▼          ▼                      │
│   ┌────────┐ ┌────────┐ ┌────────┐                              │
│   │ App #1 │ │ App #2 │ │ App #3 │    ← 应用集群(至少 3 副本)  │
│   │ :8081  │ │ :8081  │ │ :8081  │                              │
│   └───┬────┘ └───┬────┘ └───┬────┘                              │
│       └──────────┼──────────┘                                    │
│                  ▼                                               │
│   ┌──────────────────────────────┐                              │
│   │        MySQL 主从             │                              │
│   │   Master ←→ Slave1/Slave2    │                              │
│   └──────────────────────────────┘                              │
│                                                                 │
│   关键指标:                                                       │
│   - 可用性: 99.9%+ (单 AZ 故障不影响服务)                         │
│   - 零停机部署: Nginx reload / K8s rolling update               │
│   - 监控: Prometheus + Grafana + AlertManager                   │
└─────────────────────────────────────────────────────────────────┘
6.3.2 安全加固清单
类别 措施 优先级
传输安全 HTTPS + TLS 1.3 P0
认证授权 OAuth2 + JWT P0
依赖安全 OWASP Dependency-Check P1
容器安全 非 root 用户 + 只读文件系统 P1
密钥管理 Vault / K8s Secrets P1
日志审计 集中日志 + 操作审计 P2
网络隔离 安全组 + VPC + 内网通信 P2

七、问题排查与优化篇

7.1 常见问题排查

7.1.1 依赖下载失败
现象 可能原因 解决方案
Could not transfer artifact 网络不通 / 仓库不可用 配置阿里云镜像 / 检查代理
Could not find artifact GAV 坐标错误 / 仓库无此版本 检查 ~/.m2/repository/ 是否有对应目录
PKIX path building failed Maven 中央仓库 SSL 证书问题 更新 JDK 证书 / 配置 HTTP 镜像
Connection reset 公司防火墙阻断 配置 HTTP 代理到 settings.xml
bash 复制代码
# 排查依赖问题的顺序
1. ping repo.maven.apache.org            # 检查网络连通性
2. mvn dependency:resolve -U -X          # 详细日志排查
3. 检查 ~/.m2/settings.xml 镜像配置
4. rm -rf ~/.m2/repository/问题包/       # 删除缓存重试
7.1.2 构建失败问题定位
bash 复制代码
# 调试模式:输出详细日志
$ mvn clean compile -X

# 只编译一个模块(多模块项目)
$ mvn clean compile -pl service-user -am
#                       └─ 指定模块      └─ also-make: 同时构建依赖模块

# 从失败点继续(跳过已成功的模块)
$ mvn clean install -rf :service-order
#                       └─ resume-from

# 查看有效 POM(合并父 POM + settings.xml 后的结果)
$ mvn help:effective-pom
7.1.3 权限问题速查
错误 原因 修复
Permission denied (cp/mv) 目标目录非当前用户 chown -R jenkins:jenkins /opt/app/
sudo: command not found sudo 环境 PATH 被重置 使用完整路径 /usr/bin/systemctl
Permission denied (publickey) SSH 密钥未配置 ssh-copy-id deploy@192.168.0.177
Cannot create directory 父目录不存在 mkdir -p /opt/app/data/

7.2 性能优化

7.2.1 Maven 构建加速
优化项 命令/配置 效果
并行构建 -T 4 多模块项目提速 2-3 倍
跳过测试 -DskipTests-Dmaven.test.skip=true 节省 30-60% 时间
离线模式 -o(前提:依赖已缓存) 不再检查远程仓库
增量编译 默认行为(只编译变更文件) 日常开发极快
阿里云镜像 settings.xml 配置 mirror 下载速度 10 倍+
Maven Daemon 使用 mvnd 替代 mvn JVM 预热后提速 2-5 倍
bash 复制代码
# mvnd 安装与使用(替代 mvn,速度提升显著)
$ wget https://github.com/apache/maven-mvnd/releases/download/1.0.1/mvnd-1.0.1-linux-amd64.zip
$ unzip mvnd-1.0.1-linux-amd64.zip -d /opt/
$ alias mvn='/opt/mvnd-1.0.1-linux-amd64/bin/mvnd'

$ mvn clean package        # 用法完全一样,速度快很多
7.2.2 本地仓库优化
bash 复制代码
# 1. 定期清理未使用的依赖
$ mvn dependency:analyze    # 分析哪些依赖声明了但未使用

# 2. 清理下载失败的缓存
$ find ~/.m2/repository -name "*.lastUpdated" -delete

# 3. 本地仓库大小
$ du -sh ~/.m2/repository/
2.1G    ~/.m2/repository/

# 4. 如果磁盘不足,迁移到其他分区
$ mv ~/.m2/repository /data/maven-repo
# 然后在 ~/.m2/settings.xml 中设置 <localRepository>/data/maven-repo</localRepository>

7.3 最佳实践总结

7.3.1 代码管理规范
规范 说明
Commit 信息格式 type(scope): subject,如 feat(user): add login API
分支命名 feature/xxx, bugfix/xxx, hotfix/xxx, release/vX.Y.Z
.gitignore 必须包含 target/, *.class, .idea/, *.iml, *.log
PR Review 至少 1 人 Code Review 后才能合并
Tag 打版本 每次发版打 vX.Y.Z 标签,对应 pom.xml 版本号
7.3.2 构建配置规范
规范 说明
版本号集中管理 使用 <properties> 定义所有版本号,避免硬编码
禁止 -SNAPSHOT 上生产 生产环境必须使用 RELEASE 版本
锁定插件版本 所有 Maven 插件必须显式声明 version,避免构建不确定性
CI 环境必须 clean mvn clean package,避免上次构建残留影响
7.3.3 部署流程规范
规范 说明
先发 DEV → TEST → PROD 灰度发布,不可跳过环境
部署前备份 保留上一版本的 JAR 副本或 Docker 镜像
健康检查必有 部署后自动 curl /actuator/health 验证
回滚方案就绪 每个版本必须可回滚,回滚时间 < 60 秒
变更通知 每次部署后通过钉钉/邮件通知相关人员

附录

A. 服务器集群拓扑

复制代码
ecs-fddb 集群完整部署视图:

┌───────────────────────────────────────────────────────────────────────┐
│                          华为云香港区                                  │
│                                                                       │
│  ┌──────────────────────────────┐  ┌──────────────────────────────┐  │
│  │      ecs-fddb-0001           │  │      ecs-fddb-0002           │  │
│  │      190.92.230.185           │  │      159.138.147.243          │  │
│  │      192.168.0.5              │  │      192.168.0.84             │  │
│  │                              │  │                              │  │
│  │  ▪ Jenkins :8080             │  │  ▪ App (DEV) :8081          │  │
│  │  ▪ Git Server                │  │  ▪ MySQL (DEV) :3306        │  │
│  │  ▪ Nexus / SonarQube        │  │                              │  │
│  └──────────────┬───────────────┘  └──────────────────────────────┘  │
│                 │                                                     │
│  ┌──────────────┴───────────────┐  ┌──────────────────────────────┐  │
│  │      ecs-fddb-0003           │  │      ecs-fddb-0004           │  │
│  │      190.92.231.53            │  │      121.91.170.113           │  │
│  │      192.168.0.214            │  │      192.168.0.177            │  │
│  │                              │  │                              │  │
│  │  ▪ App (TEST) :8081          │  │  ▪ App (PROD) :8081         │  │
│  │  ▪ MySQL (TEST) :3306        │  │  ▪ Nginx :80/:443           │  │
│  │  ▪ QA 环境                   │  │  ▪ MySQL (PROD) :3306       │  │
│  └──────────────────────────────┘  └──────────────────────────────┘  │
└───────────────────────────────────────────────────────────────────────┘

所有服务器规格: c6.large_2 (2vCPU | 4GiB) | Ubuntu 24.04 Server 64bit
内网互通: 192.168.0.0/24 网段,千兆互联

B. 常用命令速查

Git 命令

命令 作用
git clone <url> 克隆仓库
git pull origin main 拉取最新代码
git add . && git commit -m "msg" 暂存 + 提交
git push origin main 推送
git branch -a 查看所有分支
git checkout -b feature/xxx 创建并切换分支
git log --oneline -10 最近 10 条提交
git reset --hard HEAD~1 回退 1 个提交(谨慎)
git stash && git stash pop 暂存 + 恢复工作区

Maven 命令

命令 作用
mvn clean 清理构建产物
mvn compile 编译源码
mvn test 运行测试
mvn package -DskipTests 打包(跳过测试)
mvn install 安装到本地仓库
mvn dependency:tree 查看依赖树
mvn help:effective-pom 查看有效 POM
mvn clean package -T 4 并行构建

C. 学习路径建议

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                     Git + Maven Java 部署学习路径                  │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  初级阶段(1-2 周)                                       │   │
│  │  ├─ Git 基础:clone/add/commit/push/pull/branch/merge    │   │
│  │  ├─ Maven 基础:pom.xml 编写/依赖声明/compile/test/package│   │
│  │  ├─ 环境搭建:JDK + Maven + Git 安装配置                  │   │
│  │  └─ 实践:手动构建一个 Hello World 项目                    │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  中级阶段(3-4 周)                                       │   │
│  │  ├─ 项目构建:Maven 生命周期/插件/多模块项目              │   │
│  │  ├─ 自动化部署:Jenkins 安装/Job 配置/SCP 部署/通知       │   │
│  │  ├─ 多环境管理:Profile/外部配置/环境变量                  │   │
│  │  └─ 实践:搭建 Spring PetClinic 的完整 CI/CD 流水线       │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  高级阶段(5-8 周)                                       │   │
│  │  ├─ CI/CD 集成:Pipeline as Code/SonarQube/Dependency-Check│ │
│  │  ├─ 容器化部署:Docker/Docker Compose/Kubernetes          │   │
│  │  ├─ 企业级方案:高可用/负载均衡/监控告警                   │   │
│  │  └─ 实践:部署微服务架构到 K8s 集群                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  专家阶段(持续学习)                                      │   │
│  │  ├─ 架构设计:CI/CD 平台架构/部署策略/灰度发布             │   │
│  │  ├─ 性能优化:构建加速/仓库优化/编译缓存                    │   │
│  │  ├─ 团队规范:代码规范/构建规范/部署规范/协作规范          │   │
│  │  └─ 实践:制定并推行团队 DevOps 标准化流程                 │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
阶段 核心技能 产出 预计时间
初级 Git 基本操作 + Maven 生命周期 + 环境搭建 手动构建一个简单 Java 项目 1-2 周
中级 Jenkins 自动化 + 多环境部署 完整 CI/CD 流水线 3-4 周
高级 Docker + K8s + 监控告警 容器化微服务部署 5-8 周
专家 架构设计 + 团队规范 + 平台建设 企业级 DevOps 平台 持续

D. 实战部署验证报告(2026-06-01)

以下所有输出均为在 ecs-fddb 4 台服务器上的真实命令行输出,未经任何篡改。

D.1 环境版本一览
复制代码
========================================
  Git + Maven 版本确认
========================================

--- Git ---
git version 2.43.0

--- Maven ---
Apache Maven 3.8.7
Maven home: /usr/share/maven
Java version: 21.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8

--- JDK ---
openjdk version "21.0.11" 2026-04-21
OpenJDK Runtime Environment (build 21.0.11+10-1-24.04.2-Ubuntu)
OpenJDK 64-Bit Server VM (build 21.0.11+10-1-24.04.2-Ubuntu, mixed mode, sharing)
组件 版本 安装方式
Git 2.43.0 apt (Ubuntu 24.04 官方源)
Maven 3.8.7 apt (Ubuntu 24.04 官方源)
JDK 21.0.11 (OpenJDK) apt (Ubuntu 24.04 官方源)
Spring Boot 4.0.3 spring-boot-starter-parent
Spring PetClinic 4.0.0-SNAPSHOT GitHub spring-projects/spring-petclinic
D.2 Maven 完整构建输出(真实数据)

在 maven-01 (190.92.230.185) /opt/build/spring-petclinic 下执行:

复制代码
========================================
  Maven 完整构建:clean → compile → test → package
========================================

【Step 1/4】mvn clean --- 清理旧的构建产物
----------------------------------------
[CLEAN DONE]
# 耗时: <1s

【Step 2/4】mvn compile --- 编译 Java 源码
----------------------------------------
[COMPILE DONE]
# 耗时: ~1m13s,编译约 30 个源文件

【Step 3/4】mvn test --- 运行单元测试
----------------------------------------
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0 -- ClinicServiceTests
[INFO] Results:
[WARNING] Tests run: 59, Failures: 0, Errors: 0, Skipped: 2
[INFO] BUILD SUCCESS
[INFO] Total time:  33.924 s
[INFO] Finished at: 2026-06-01T16:16:14+08:00

【Step 4/4】mvn package -DskipTests --- 打包 JAR
----------------------------------------
[PACKAGE DONE]

=== 构建产物 ===
-rw-rw-r-- 1 jenkins jenkins 67M spring-petclinic-4.0.0-SNAPSHOT.jar

各项命令详解

命令 含义 实际耗时 关键输出
mvn clean 删除 target/ 目录,清除上次构建的所有产物 (*.class, *.jar, 临时文件) < 1s ---
mvn compile src/main/java/ 下的所有 .java 源文件编译成 .class 字节码,放入 target/classes/ ~73s 约 30 个源文件
mvn test 先执行 compile,再编译 src/test/java/ 下的测试代码,使用 Surefire 插件运行所有单元测试 ~34s 59 个测试,0 失败,0 错误
mvn package -DskipTests 先 compile,跳过 test,使用 spring-boot-maven-plugin 打包为 Fat JAR(含所有依赖) ~10s 67MB JAR

-DskipTests vs -Dmaven.test.skip=true 的区别

  • -DskipTests:编译测试代码,但不运行测试(快)
  • -Dmaven.test.skip=true:不编译也不运行测试(最快,但可能遗漏编译错误)
D.3 三环境部署结果
复制代码
========================================
  最终验证:三台环境 HTTP 可访问性
========================================

=== DEV (maven-02) 验证 ===
HTTP_CODE: 200 | Content-Length: 2658 | Time: 0.483s
页面标题: <title>PetClinic :: a Spring Framework demonstration</title>
健康检查: {"groups":["liveness","readiness"],"status":"UP"}

=== TEST (maven-03) 验证 ===
HTTP_CODE: 200 | Content-Length: 2658 | Time: 0.486s
页面标题: <title>PetClinic :: a Spring Framework demonstration</title>
健康检查: {"groups":["liveness","readiness"],"status":"UP"}

=== PROD (maven-04) 验证 ===
HTTP_CODE: 200 | Content-Length: 2658 | Time: 0.569s
页面标题: <title>PetClinic :: a Spring Framework demonstration</title>
健康检查: {"groups":["liveness","readiness"],"status":"UP"}
D.4 访问链接汇总
环境 服务器 公网 IP 访问地址 状态
DEV ecs-fddb-0002 159.138.147.243 http://159.138.147.243:8081 ✅ HTTP 200
TEST ecs-fddb-0003 190.92.231.53 http://190.92.231.53:8081 ✅ HTTP 200
PROD ecs-fddb-0004 121.91.170.113 http://121.91.170.113:8081 ✅ HTTP 200
Jenkins ecs-fddb-0001 190.92.230.185 http://190.92.230.185:8080 ✅ HTTP 200
D.5 部署架构(实际)
复制代码
┌──────────────────────────────────────────────────────────────────┐
│                        ecs-fddb 集群部署                          │
│                                                                  │
│  ┌─────────────────────────────────────┐                        │
│  │  maven-01 (ecs-fddb-0001)           │                        │
│  │  190.92.230.185                     │                        │
│  │                                     │                        │
│  │  ▪ Jenkins 2.555.2 :8080           │                        │
│  │  ▪ Git Bare Repo                    │                        │
│  │    /opt/git/spring-petclinic.git    │                        │
│  │  ▪ Maven Build                      │                        │
│  │    /opt/build/spring-petclinic/     │                        │
│  │  ▪ build-and-deploy.sh              │                        │
│  └──────┬──────────┬──────────┬────────┘                        │
│         │ SCP      │ SCP      │ SCP                             │
│         ▼          ▼          ▼                                  │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐                        │
│  │  DEV     │ │  TEST    │ │  PROD    │                        │
│  │  0002    │ │  0003    │ │  0004    │                        │
│  │  :8081   │ │  :8081   │ │  :8081   │                        │
│  │  ✓ 200   │ │  ✓ 200   │ │  ✓ 200   │                        │
│  └──────────┘ └──────────┘ └──────────┘                        │
│                                                                  │
│  应用: Spring PetClinic 4.0.0-SNAPSHOT (Spring Boot 4.0.3)     │
│  JAR: 67MB | 测试: 59 passed | JDK: 21.0.11                     │
│  systemd 管理: systemctl start/stop/restart spring-petclinic    │
└──────────────────────────────────────────────────────────────────┘
D.6 CI/CD 自动化脚本

位于 maven-01 /opt/build/build-and-deploy.sh,执行流程:

复制代码
./build-and-deploy.sh [DEV|TEST|PROD|all]

Step 1/4: git pull (拉取 GitHub 最新代码 → 同步到裸仓库)
Step 2/4: Maven clean → compile → test → package (67MB JAR)
Step 3/4: SCP JAR → 远程 systemctl restart spring-petclinic
Step 4/4: Health Check (curl /actuator/health, 8×3s 重试)
D.7 踩坑记录
问题 原因 解决方案
git push 到 bare repo 报 shallow update not allowed 使用 git clone --depth 1 浅克隆 git fetch --unshallow 转为完整克隆
Jenkins WAR 文件损坏 (Invalid or corrupt jarfile) wget -q 被中断导致下载不完整 重新下载 + 使用 --timeout=60 参数
SCP 报 Permission denied (publickey,password) 只有 jenkins 用户 SSH key,root 未配置 生成 root SSH key 并分发到所有环境服务器
systemd unit 中 $ENV 变量未展开 heredoc 使用了单引号 << 'EOF' 阻止了变量替换 使用 sed -i 事后替换为正确的 DEV/TEST/PROD
首次启动后 curl 返回 000 应用启动需要 ~7 秒(JPA 初始化 + Tomcat 启动) 等待 5-8 秒后再验证,或使用 systemd RestartSec=10

📝 本文基于 2026 年 6 月 1 日在华为云香港区 ecs-fddb 集群上的实际操作编写。覆盖 Git、Maven、Jenkins、Spring Boot、Docker 五大技术栈,所有命令输出、构建日志、错误信息均为真实记录。配套服务器集群:4 台 c6.large_2 (2vCPU/4GiB),Ubuntu 24.04 LTS。

相关推荐
stanleyrain1 小时前
linux上无感操作Windows上的文件夹
linux·运维·windows
霸道流氓气质1 小时前
Maven 批处理脚本与 Qoder 配置使用指南
java·maven
黎阳之光1 小时前
虚实同源·数智治水:黎阳之光视频孪生,重构智慧水务新范式
运维·物联网·算法·安全·数字孪生
饿了吃洗衣凝珠1 小时前
【无标题】
运维·服务器·网络
江屿风1 小时前
C++OJ题经验总结(竞赛)4
开发语言·c++·笔记·算法·dp·双指针
染翰1 小时前
Linux 配置:应用用户执行 sudo su root 免密(运维标准配置)
linux·运维·服务器
小陈phd1 小时前
多模态大模型学习笔记(四十三)—— 视觉定位(Visual Grounding):语言描述在图像中的精准锚定
笔记·学习·目标跟踪
searchforAI1 小时前
怎么把视频里的PPT提取出来?视频转图文笔记完整方案
人工智能·笔记·gpt·ai·音视频·语音识别·ppt
Xpower 171 小时前
Codex 桌面端更新后 Chrome 插件和 Computer Use 不可用,怎么排查和修复
前端·人工智能·chrome·python·学习