Files
label_backend/docs/superpowers/plans/2026-04-09-deploy-optimization.md

518 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.xmlINFO 级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 环境(检测 /.dockerenvexec 前台运行,保持容器进程存活
# - 裸机 / VMnohup 后台运行,日志追加至 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
# 裸机 / VMnohup 后台运行
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.shDocker 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.sh0755 可执行) -->
<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>
<includeScope>runtime</includeScope>
</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.info11 文件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.info11 文件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.