docs(spec): 补充九、部署与发布章节(deploy.md 需求落地)
- TOC 添加第九章入口 - 九.1 Maven 构建:移除 fat JAR,添加 maven-jar-plugin + maven-dependency-plugin + maven-assembly-plugin - 九.2 分发包结构:bin/etc/libs/logs 四级目录 - 九.3 start.sh:Docker 用 exec 前台、VM 用 nohup 后台 - 九.4 logback.xml:INFO 级别,60 MB 滚动,30 天保留 - 九.5 Dockerfile 更新:多阶段构建,复制 etc/ 配置并调用 start.sh - 九.6 log.debug → log.info:11 文件 21 处,附批量替换命令 - 八 合规清单新增 #12-14:包结构、start.sh Docker 兼容、日志级别
This commit is contained in:
@@ -45,6 +45,13 @@
|
||||
- [7.4 状态机越界拒绝测试](#74-状态机越界拒绝测试)
|
||||
- [7.5 多租户隔离测试](#75-多租户隔离测试)
|
||||
- [八、宪章合规检查清单](#八宪章合规检查清单)
|
||||
- [九、部署与发布](#九部署与发布)
|
||||
- [9.1 Maven 构建配置变更](#91-maven-构建配置变更)
|
||||
- [9.2 分发包结构](#92-分发包结构)
|
||||
- [9.3 start.sh 启动脚本](#93-startsh-启动脚本)
|
||||
- [9.4 logback.xml 配置](#94-logbackxml-配置)
|
||||
- [9.5 Dockerfile 更新](#95-dockerfile-更新)
|
||||
- [9.6 日志级别规范(log.debug → log.info)](#96-日志级别规范logdebug--loginfo)
|
||||
|
||||
---
|
||||
|
||||
@@ -1478,12 +1485,14 @@ volumes:
|
||||
|
||||
**Dockerfile(backend):**
|
||||
|
||||
> 完整的多阶段构建 Dockerfile 见 [9.5 Dockerfile 更新](#95-dockerfile-更新)。
|
||||
> 以下为旧版占位,已被新版替代(使用薄 jar + start.sh 方式)。
|
||||
|
||||
```dockerfile
|
||||
FROM eclipse-temurin:17-jre-alpine
|
||||
WORKDIR /app
|
||||
COPY target/label-backend-*.jar app.jar
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
# 已废弃——使用 fat JAR 方式,不符合新部署规范
|
||||
# FROM eclipse-temurin:17-jre-alpine
|
||||
# COPY target/label-backend-*.jar app.jar
|
||||
# ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
```
|
||||
|
||||
[↑ 返回目录](#目录)
|
||||
@@ -1599,5 +1608,336 @@ PR 合并前评审人**必须**逐条核对以下清单:
|
||||
| 9 | 只追加审计日志、AOP 切面、审计失败不回滚业务 | `AuditAspect`、`@OperationLog` | `sys_operation_log` 无 UPDATE/DELETE;审计异常仅 error 日志 |
|
||||
| 10 | RESTful URL、统一响应格式、分页必须 | `Result<T>`、各 Controller | 无动词路径;无裸 POJO 返回;所有列表接口有分页参数 |
|
||||
| 11 | YAGNI:业务在 Service,Controller 只处理 HTTP | 包结构 | Controller 无业务判断逻辑;无未使用的抽象层 |
|
||||
| 12 | 部署包结构规范(bin/etc/libs/logs 四级) | `pom.xml`、`distribution.xml` | fat JAR 已移除;assembly 产出 zip + tar.gz;libs/ 含薄 jar + 所有依赖 |
|
||||
| 13 | start.sh 启动可执行、Docker 兼容 | `src/main/scripts/start.sh` | Docker 内 exec 前台运行;VM 内 nohup 后台运行;日志写入 logs/ |
|
||||
| 14 | 日志级别统一 INFO、无 log.debug 残留 | 全体 Service 类 | `grep -r "log\.debug"` 返回 0 结果;logback.xml root level=INFO |
|
||||
|
||||
[↑ 返回目录](#目录)
|
||||
|
||||
---
|
||||
|
||||
## 九、部署与发布
|
||||
|
||||
### 9.1 Maven 构建配置变更
|
||||
|
||||
**目标**:用薄 jar(thin jar)替代 Spring Boot fat JAR,由 Assembly Plugin 组装可分发压缩包。
|
||||
|
||||
**移除** `spring-boot-maven-plugin`(fat JAR),**替换为**以下三个插件:
|
||||
|
||||
```xml
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<!-- 1. 薄 jar:仅打包编译后的 class 文件,Manifest 声明 Main-Class -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.label.LabelBackendApplication</mainClass>
|
||||
<addClasspath>false</addClasspath>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- 2. 将所有运行时依赖复制到 target/libs/ -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals><goal>copy-dependencies</goal></goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<excludeScope>test</excludeScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- 3. 组装分发包(zip + tar.gz) -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>create-distribution</id>
|
||||
<phase>package</phase>
|
||||
<goals><goal>single</goal></goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/distribution.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
```
|
||||
|
||||
**Assembly 描述符** `src/main/assembly/distribution.xml`:
|
||||
|
||||
```xml
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0
|
||||
https://maven.apache.org/xsd/assembly-2.1.0.xsd">
|
||||
<id>dist</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
|
||||
<!-- bin/start.sh(可执行权限) -->
|
||||
<files>
|
||||
<file>
|
||||
<source>src/main/scripts/start.sh</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<fileMode>0755</fileMode>
|
||||
</file>
|
||||
</files>
|
||||
|
||||
<!-- etc/ 配置文件 -->
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>etc</outputDirectory>
|
||||
<includes>
|
||||
<include>application.yml</include>
|
||||
<include>logback.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<!-- logs/ 空目录占位(确保解压后目录存在) -->
|
||||
<fileSet>
|
||||
<directory>src/main/assembly/empty-logs</directory>
|
||||
<outputDirectory>logs</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
<!-- libs/:薄 jar(project artifact)+ 所有运行时依赖 -->
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
<useProjectArtifact>true</useProjectArtifact>
|
||||
<scope>runtime</scope>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
</assembly>
|
||||
```
|
||||
|
||||
> **注意**:需在项目根创建空目录占位文件 `src/main/assembly/empty-logs/.gitkeep`,
|
||||
> 否则 Assembly Plugin 会因源目录不存在而报错。
|
||||
|
||||
---
|
||||
|
||||
### 9.2 分发包结构
|
||||
|
||||
`mvn clean package` 后在 `target/` 生成:
|
||||
|
||||
```
|
||||
target/
|
||||
├── libs/
|
||||
│ ├── label-backend-1.0.0-SNAPSHOT.jar ← 薄 jar(仅 class)
|
||||
│ ├── spring-boot-starter-web-3.2.5.jar
|
||||
│ ├── mybatis-plus-boot-starter-3.5.9.jar
|
||||
│ └── ... (全部运行时依赖)
|
||||
├── label-backend-1.0.0-SNAPSHOT.zip
|
||||
└── label-backend-1.0.0-SNAPSHOT.tar.gz
|
||||
```
|
||||
|
||||
压缩包解压后的内部结构:
|
||||
|
||||
```
|
||||
label-backend-1.0.0-SNAPSHOT/
|
||||
├── bin/
|
||||
│ └── start.sh # 启动脚本(0755)
|
||||
├── etc/
|
||||
│ ├── application.yml # Spring 配置(生产环境按需修改)
|
||||
│ └── logback.xml # 日志配置(INFO + 60 MB 滚动)
|
||||
├── libs/
|
||||
│ ├── label-backend-1.0.0-SNAPSHOT.jar
|
||||
│ └── ... (所有依赖 jar)
|
||||
└── logs/ # 空目录,运行时写入日志
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9.3 start.sh 启动脚本
|
||||
|
||||
新增文件:`src/main/scripts/start.sh`
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# label-backend 启动脚本
|
||||
# - Docker 环境(检测 /.dockerenv):exec 前台运行,保持容器进程存活
|
||||
# - 裸机 / VM:nohup 后台运行,日志追加至 logs/startup.log
|
||||
|
||||
set -e
|
||||
|
||||
BASEDIR=$(cd "$(dirname "$0")/.." && pwd)
|
||||
LIBDIR="$BASEDIR/libs"
|
||||
CONFDIR="$BASEDIR/etc"
|
||||
LOGDIR="$BASEDIR/logs"
|
||||
|
||||
mkdir -p "$LOGDIR"
|
||||
|
||||
JVM_OPTS="${JVM_OPTS:--Xms512m -Xmx1024m}"
|
||||
MAIN_CLASS="com.label.LabelBackendApplication"
|
||||
JAVA_ARGS="$JVM_OPTS \
|
||||
-Dspring.config.location=file:$CONFDIR/application.yml \
|
||||
-Dlogging.config=file:$CONFDIR/logback.xml \
|
||||
-cp $LIBDIR/*"
|
||||
|
||||
if [ -f /.dockerenv ]; then
|
||||
# Docker 容器:exec 替换当前进程,PID=1 接管信号
|
||||
exec java $JAVA_ARGS $MAIN_CLASS
|
||||
else
|
||||
# 裸机 / VM:nohup 后台运行
|
||||
nohup java $JAVA_ARGS $MAIN_CLASS >> "$LOGDIR/startup.log" 2>&1 &
|
||||
echo "label-backend started, PID=$!"
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9.4 logback.xml 配置
|
||||
|
||||
新增文件:`src/main/resources/logback.xml`
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds">
|
||||
|
||||
<property name="LOG_PATH" value="${LOG_PATH:-logs}"/>
|
||||
<property name="APP_NAME" value="label-backend"/>
|
||||
<property name="LOG_PATTERN"
|
||||
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出(Docker 日志采集依赖 stdout) -->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder charset="UTF-8">
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 滚动文件:60 MB / 个,按日分组,保留 30 天,总上限 3 GB -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/${APP_NAME}.log</file>
|
||||
<encoder charset="UTF-8">
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<maxFileSize>60MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
<totalSizeCap>3GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
```
|
||||
|
||||
> **说明**:`LOG_PATH` 可通过环境变量或 JVM 参数覆盖,默认指向相对于工作目录的 `logs/`。
|
||||
> Docker Compose 中如需持久化日志,挂载 `/app/logs` 卷并设置 `LOG_PATH=/app/logs`。
|
||||
|
||||
---
|
||||
|
||||
### 9.5 Dockerfile 更新
|
||||
|
||||
替换 `Dockerfile` 全文:
|
||||
|
||||
```dockerfile
|
||||
# 构建阶段:Maven + JDK 17 编译,生成薄 jar 及依赖
|
||||
FROM maven:3.9-eclipse-temurin-17-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# 优先复制 pom.xml 利用 Docker 层缓存(依赖不变时跳过 go-offline)
|
||||
COPY pom.xml .
|
||||
RUN mvn dependency:go-offline -q
|
||||
|
||||
COPY src ./src
|
||||
RUN mvn clean package -DskipTests -q
|
||||
|
||||
# 运行阶段:仅含 JRE 的精简镜像
|
||||
FROM eclipse-temurin:17-jre-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# 复制部署结构:bin/ libs/ etc/
|
||||
COPY --from=builder /app/src/main/scripts/start.sh bin/start.sh
|
||||
COPY --from=builder /app/target/libs/ libs/
|
||||
COPY --from=builder /app/src/main/resources/application.yml etc/application.yml
|
||||
COPY --from=builder /app/src/main/resources/logback.xml etc/logback.xml
|
||||
|
||||
RUN mkdir -p logs && chmod +x bin/start.sh
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
# start.sh 检测到 /.dockerenv 后自动以 exec 前台方式运行
|
||||
ENTRYPOINT ["bin/start.sh"]
|
||||
```
|
||||
|
||||
**Docker Compose 中配置日志路径持久化(可选):**
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
build: ./label_backend
|
||||
volumes:
|
||||
- ./logs/backend:/app/logs
|
||||
environment:
|
||||
LOG_PATH: /app/logs
|
||||
# ... 其他环境变量保持不变
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9.6 日志级别规范(log.debug → log.info)
|
||||
|
||||
代码约定:**所有业务 Service 的正常流程日志使用 `log.info`**,`log.debug` 仅保留在需要
|
||||
开发期详细追踪的工具类(当前项目无此场景,全部改为 `log.info`)。
|
||||
|
||||
**需修改的文件(共 11 个,21 处):**
|
||||
|
||||
| 文件 | `log.debug` 数量 |
|
||||
|------|-----------------|
|
||||
| `module/video/service/VideoProcessService.java` | 5 |
|
||||
| `module/source/service/SourceService.java` | 2 |
|
||||
| `module/user/service/UserService.java` | 3 |
|
||||
| `module/user/service/AuthService.java` | 2 |
|
||||
| `module/config/service/SysConfigService.java` | 2 |
|
||||
| `module/annotation/service/ExtractionApprovedEventListener.java` | 2 |
|
||||
| `module/task/service/TaskService.java` | 1 |
|
||||
| `module/annotation/service/QaService.java` | 1 |
|
||||
| `module/export/service/FinetuneService.java` | 1 |
|
||||
| `module/task/service/TaskClaimService.java` | 1 |
|
||||
| `module/export/service/ExportService.java` | 1 |
|
||||
|
||||
**执行方式**(实现阶段批量替换):
|
||||
|
||||
```bash
|
||||
# 验证变更范围
|
||||
grep -rn "log\.debug" src/main/java
|
||||
|
||||
# 批量替换
|
||||
find src/main/java -name "*.java" \
|
||||
-exec sed -i 's/log\.debug(/log.info(/g' {} +
|
||||
|
||||
# 确认清零
|
||||
grep -r "log\.debug" src/main/java && echo "FAIL" || echo "PASS"
|
||||
```
|
||||
|
||||
[↑ 返回目录](#目录)
|
||||
|
||||
Reference in New Issue
Block a user