docs(plan): 添加部署优化实施计划(deploy.md 8 条需求)
This commit is contained in:
517
docs/superpowers/plans/2026-04-09-deploy-optimization.md
Normal file
517
docs/superpowers/plans/2026-04-09-deploy-optimization.md
Normal file
@@ -0,0 +1,517 @@
|
||||
# Deploy Optimization Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 将 label_backend 从 Spring Boot fat JAR 方式改造为薄 jar + Maven Assembly 分发包,并统一日志级别为 INFO。
|
||||
|
||||
**Architecture:** 移除 `spring-boot-maven-plugin`,改用 `maven-jar-plugin`(薄 jar)+ `maven-dependency-plugin`(复制依赖到 `target/libs/`)+ `maven-assembly-plugin`(组装 zip/tar.gz)。新增 `start.sh`(Docker/VM 双模式启动)和 `logback.xml`(60 MB 滚动)。Dockerfile 改为多阶段构建,从 `target/libs/` 和 `src/main/resources/` 复制构建产物。
|
||||
|
||||
**Tech Stack:** Maven 3.9, JDK 17, Spring Boot 3.2.5, maven-assembly-plugin 3.x, logback 1.4.x (Spring Boot 管理版本)
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
| 操作 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| 新建 | `src/main/resources/logback.xml` | INFO 级,60 MB 滚动日志配置 |
|
||||
| 新建 | `src/main/scripts/start.sh` | Docker/VM 双模式启动脚本 |
|
||||
| 新建 | `src/main/assembly/distribution.xml` | Assembly 描述符 |
|
||||
| 新建 | `src/main/assembly/empty-logs/.gitkeep` | logs/ 目录占位(Assembly 引用) |
|
||||
| 修改 | `pom.xml` | 替换 spring-boot-maven-plugin |
|
||||
| 修改 | `Dockerfile` | 多阶段构建,复制 etc/ + libs/ |
|
||||
| 批量修改 | 11 个 Service 类 | `log.debug` → `log.info`(21 处) |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 创建 logback.xml
|
||||
|
||||
**Files:**
|
||||
- Create: `src/main/resources/logback.xml`
|
||||
|
||||
- [ ] **Step 1: 创建 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>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证文件存在**
|
||||
|
||||
```bash
|
||||
ls src/main/resources/logback.xml
|
||||
```
|
||||
|
||||
预期输出:`src/main/resources/logback.xml`
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/main/resources/logback.xml
|
||||
git commit -m "feat(deploy): 添加 logback.xml(INFO 级,60 MB 滚动)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: 创建 start.sh 启动脚本
|
||||
|
||||
**Files:**
|
||||
- Create: `src/main/scripts/start.sh`
|
||||
|
||||
- [ ] **Step 1: 创建目录并写入 start.sh**
|
||||
|
||||
```bash
|
||||
mkdir -p src/main/scripts
|
||||
```
|
||||
|
||||
文件内容 `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
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证文件存在**
|
||||
|
||||
```bash
|
||||
ls src/main/scripts/start.sh
|
||||
```
|
||||
|
||||
预期输出:`src/main/scripts/start.sh`
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/main/scripts/start.sh
|
||||
git commit -m "feat(deploy): 添加 start.sh(Docker exec / VM nohup 双模式)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 创建 Assembly 描述符和目录占位
|
||||
|
||||
**Files:**
|
||||
- Create: `src/main/assembly/distribution.xml`
|
||||
- Create: `src/main/assembly/empty-logs/.gitkeep`
|
||||
|
||||
- [ ] **Step 1: 创建 assembly 目录结构**
|
||||
|
||||
```bash
|
||||
mkdir -p src/main/assembly/empty-logs
|
||||
touch src/main/assembly/empty-logs/.gitkeep
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建 distribution.xml**
|
||||
|
||||
文件内容 `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(0755 可执行) -->
|
||||
<files>
|
||||
<file>
|
||||
<source>src/main/scripts/start.sh</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<fileMode>0755</fileMode>
|
||||
</file>
|
||||
</files>
|
||||
|
||||
<fileSets>
|
||||
<!-- etc/:application.yml + logback.xml -->
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>etc</outputDirectory>
|
||||
<includes>
|
||||
<include>application.yml</include>
|
||||
<include>logback.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<!-- libs/:薄 jar + 所有运行时依赖 -->
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/libs</directory>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*.jar</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<!-- logs/ 空目录占位 -->
|
||||
<fileSet>
|
||||
<directory>src/main/assembly/empty-logs</directory>
|
||||
<outputDirectory>logs</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
</assembly>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证文件存在**
|
||||
|
||||
```bash
|
||||
ls src/main/assembly/distribution.xml src/main/assembly/empty-logs/.gitkeep
|
||||
```
|
||||
|
||||
预期输出:两个文件路径均显示
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add src/main/assembly/
|
||||
git commit -m "feat(deploy): 添加 Assembly 描述符 distribution.xml"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 更新 pom.xml(替换 spring-boot-maven-plugin)
|
||||
|
||||
**Files:**
|
||||
- Modify: `pom.xml`
|
||||
|
||||
- [ ] **Step 1: 替换 `<build><plugins>` 段落**
|
||||
|
||||
将 `pom.xml` 的 `<build>` 段(当前仅含 spring-boot-maven-plugin)替换为:
|
||||
|
||||
```xml
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<!-- 薄 jar:仅打包编译后的 class,输出到 target/libs/ -->
|
||||
<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>
|
||||
|
||||
<!-- 将所有运行时依赖复制到 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>
|
||||
|
||||
<!-- 组装分发包(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>
|
||||
```
|
||||
|
||||
即用上述内容完整替换 `pom.xml` 中现有的 `<build>...</build>` 块(原内容为含 spring-boot-maven-plugin 的单插件配置)。
|
||||
|
||||
- [ ] **Step 2: 验证语法并试构建**
|
||||
|
||||
```bash
|
||||
mvn validate -q
|
||||
```
|
||||
|
||||
预期输出:无错误(只做 pom.xml 解析校验,不实际编译)
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add pom.xml
|
||||
git commit -m "feat(deploy): pom.xml 替换 fat JAR → 薄 jar + maven-dependency + maven-assembly"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 更新 Dockerfile
|
||||
|
||||
**Files:**
|
||||
- Modify: `Dockerfile`
|
||||
|
||||
- [ ] **Step 1: 替换 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"]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证 Dockerfile 语法**
|
||||
|
||||
```bash
|
||||
docker build --no-cache --dry-run . 2>/dev/null || echo "docker not available; syntax check skipped"
|
||||
```
|
||||
|
||||
预期:无语法错误(或 docker 不可用时跳过)
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add Dockerfile
|
||||
git commit -m "feat(deploy): Dockerfile 改为多阶段构建(薄 jar + start.sh)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 批量替换 log.debug → log.info(11 文件,21 处)
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/main/java/com/label/module/video/service/VideoProcessService.java` (5 处)
|
||||
- Modify: `src/main/java/com/label/module/source/service/SourceService.java` (2 处)
|
||||
- Modify: `src/main/java/com/label/module/user/service/UserService.java` (3 处)
|
||||
- Modify: `src/main/java/com/label/module/user/service/AuthService.java` (2 处)
|
||||
- Modify: `src/main/java/com/label/module/config/service/SysConfigService.java` (2 处)
|
||||
- Modify: `src/main/java/com/label/module/annotation/service/ExtractionApprovedEventListener.java` (2 处)
|
||||
- Modify: `src/main/java/com/label/module/task/service/TaskService.java` (1 处)
|
||||
- Modify: `src/main/java/com/label/module/annotation/service/QaService.java` (1 处)
|
||||
- Modify: `src/main/java/com/label/module/export/service/FinetuneService.java` (1 处)
|
||||
- Modify: `src/main/java/com/label/module/task/service/TaskClaimService.java` (1 处)
|
||||
- Modify: `src/main/java/com/label/module/export/service/ExportService.java` (1 处)
|
||||
|
||||
- [ ] **Step 1: 批量替换**
|
||||
|
||||
```bash
|
||||
find src/main/java -name "*.java" \
|
||||
-exec sed -i 's/log\.debug(/log.info(/g' {} +
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证替换完整,无 log.debug 残留**
|
||||
|
||||
```bash
|
||||
grep -r "log\.debug" src/main/java && echo "FAIL: 仍有 log.debug 残留" || echo "PASS: 无 log.debug"
|
||||
```
|
||||
|
||||
预期输出:`PASS: 无 log.debug`
|
||||
|
||||
- [ ] **Step 3: 验证替换数量正确(应有 21 处 log.info 新增)**
|
||||
|
||||
```bash
|
||||
git diff --stat src/main/java | tail -1
|
||||
```
|
||||
|
||||
预期:显示 11 个文件,21 处改动(`21 insertions(+), 21 deletions(-)`)
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add src/main/java/
|
||||
git commit -m "refactor(log): log.debug 全量替换为 log.info(11 文件,21 处)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 全量构建验证
|
||||
|
||||
**Files:** 只读操作,不修改文件
|
||||
|
||||
- [ ] **Step 1: 执行完整构建(跳过测试)**
|
||||
|
||||
```bash
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
|
||||
预期:`BUILD SUCCESS`,无 ERROR 输出
|
||||
|
||||
- [ ] **Step 2: 验证 target/libs/ 目录存在且包含 jar**
|
||||
|
||||
```bash
|
||||
ls target/libs/*.jar | head -5
|
||||
ls target/libs/label-backend-1.0.0-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
预期:显示薄 jar 及多个依赖 jar
|
||||
|
||||
- [ ] **Step 3: 验证分发包已生成**
|
||||
|
||||
```bash
|
||||
ls target/label-backend-1.0.0-SNAPSHOT.zip
|
||||
ls target/label-backend-1.0.0-SNAPSHOT.tar.gz
|
||||
```
|
||||
|
||||
预期:两个文件均存在
|
||||
|
||||
- [ ] **Step 4: 验证分发包内部结构**
|
||||
|
||||
```bash
|
||||
# 使用 unzip 检查 zip 内容(Windows Git Bash 或 Linux 均可用)
|
||||
unzip -l target/label-backend-1.0.0-SNAPSHOT.zip | grep -E "bin/|etc/|libs/|logs/"
|
||||
```
|
||||
|
||||
预期输出包含:
|
||||
```
|
||||
label-backend-1.0.0-SNAPSHOT/bin/start.sh
|
||||
label-backend-1.0.0-SNAPSHOT/etc/application.yml
|
||||
label-backend-1.0.0-SNAPSHOT/etc/logback.xml
|
||||
label-backend-1.0.0-SNAPSHOT/libs/label-backend-1.0.0-SNAPSHOT.jar
|
||||
label-backend-1.0.0-SNAPSHOT/logs/
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 验证 logback.xml 已包含在 etc/ 内**
|
||||
|
||||
```bash
|
||||
unzip -l target/label-backend-1.0.0-SNAPSHOT.zip | grep logback
|
||||
```
|
||||
|
||||
预期:`label-backend-1.0.0-SNAPSHOT/etc/logback.xml`
|
||||
|
||||
- [ ] **Step 6: Commit 构建验证记录(如有必要则修正问题后提交)**
|
||||
|
||||
若 Step 1-5 全部通过,无需额外提交。若发现问题(如缺少文件、路径错误),修正对应 Task 后重新执行本 Task。
|
||||
|
||||
---
|
||||
|
||||
## 自检
|
||||
|
||||
### Spec 覆盖检查
|
||||
|
||||
| deploy.md 需求 | 对应任务 |
|
||||
|---------------|---------|
|
||||
| 1. 分发包结构 bin/etc/libs/logs | Task 3 (distribution.xml) + Task 7 验证 |
|
||||
| 2. start.sh nohup 后台启动 | Task 2 |
|
||||
| 3. logback.xml INFO + 60 MB 滚动 | Task 1 |
|
||||
| 4. logback.xml + application.yml 在 etc/ | Task 3 (distribution.xml fileSets) |
|
||||
| 5. maven-jar-plugin + maven-dependency-plugin | Task 4 |
|
||||
| 6. Maven Assembly Plugin → zip/tar.gz | Task 3 + Task 4 |
|
||||
| 7. Dockerfile 复制 etc/ + 调用 start.sh | Task 5 |
|
||||
| 8. log.debug → log.info | Task 6 |
|
||||
|
||||
所有 8 条需求均有对应任务。✅
|
||||
|
||||
### 类型一致性
|
||||
|
||||
- `MAIN_CLASS="com.label.LabelBackendApplication"` — 与 `src/main/java/com/label/LabelBackendApplication.java` 一致 ✅
|
||||
- `maven-jar-plugin` 输出路径 `target/libs/` — 与 Dockerfile `COPY --from=builder /app/target/libs/` 一致 ✅
|
||||
- `distribution.xml` `<directory>${project.build.directory}/libs</directory>` — 与 `maven-dependency-plugin` 的 `outputDirectory` 一致 ✅
|
||||
|
||||
## GSTACK REVIEW REPORT
|
||||
|
||||
| Review | Trigger | Why | Runs | Status | Findings |
|
||||
|--------|---------|-----|------|--------|----------|
|
||||
| CEO Review | `/plan-ceo-review` | Scope & strategy | 0 | — | — |
|
||||
| Codex Review | `/codex review` | Independent 2nd opinion | 0 | — | — |
|
||||
| Eng Review | `/plan-eng-review` | Architecture & tests (required) | 0 | — | — |
|
||||
| Design Review | `/plan-design-review` | UI/UX gaps | 0 | — | — |
|
||||
|
||||
**VERDICT:** NO REVIEWS YET — run `/autoplan` for full review pipeline, or individual reviews above.
|
||||
Reference in New Issue
Block a user