perf: 优化 CI Docker 镜像构建速度

- 新增 CI 精简 Dockerfile,直接打包 drone 预编译 jar,避免在 Docker 内重复编译(省去 npm ci + mvn 全量编译 ~15min)
- build-docker-image 步骤改用精简 Dockerfile,去掉无效的 docker pull 缓存尝试
- maven-build 步骤优化:动态检测 CPU 核数设置并行度 -T 1C/2C、增加 JVM 内存、添加 --fail-at-end
- .dockerignore 优化:CI Dockerfile 仅需 par-api/target/*.jar,排除所有源码/pom/前端文件
- par-api/Dockerfile 标注为独立多阶段构建版本(本地使用)

参考 mediabot 项目的多阶段构建思路,但将编译前置到 drone host 缓存中,Docker 构建秒级完成
This commit is contained in:
mediabot-pt
2026-06-29 12:53:33 +08:00
parent d5fc73cad7
commit b24ec27905
4 changed files with 90 additions and 17 deletions

View File

@@ -1,17 +1,20 @@
# 构建产物
target/
*/target/
# 构建产物(jar 除外 — CI Dockerfile 需要拷贝 par-api/target/*.jar)
web/node_modules/
web/dist/
par-common/target/
par-core/target/
# 注意:不排除 par-api/target/,因为 CI Dockerfile 需要其中的 jar
# IDE
.idea/
*.iml
.vscode/
.codebuddy/
# Git
.git/
.gitignore
.gitattributes
# 文档
README.md
@@ -31,6 +34,22 @@ run.sh
.drone.yml
docker-compose.yml
# 项目文件(Docker 上下文不需要)
pom.xml
par-*/pom.xml
# Java 源码(CI Dockerfile 不需要)
par-common/src/
par-core/src/
par-api/src/
# 前端源码(CI Dockerfile 不需要)
web/
# 其他
*.md
*.log
*.iml
*.class
*.jar
!par-api/target/*.jar

View File

@@ -98,7 +98,7 @@ steps:
image: 192.168.31.253/library/maven-java21:3.9.9-alpine
pull: if-not-exists
environment:
MAVEN_OPTS: "-Dmaven.repo.local=/root/.m2/repository -Xms256m -Xmx512m"
MAVEN_OPTS: "-Dmaven.repo.local=/root/.m2/repository -Xms512m -Xmx1024m -Djava.awt.headless=true -Dmaven.compiler.forceJavacCompilerUse=true"
volumes:
- name: maven-cache
path: /root/.m2
@@ -143,12 +143,24 @@ steps:
echo "BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)" >> /drone/src/.version.env
echo "发布版本: $RELEASE_VERSION, 构建版本: $BUILD_VERSION"
# Maven 打包(使用阿里云镜像)
# 检测可用 CPU 核数,动态设置 Maven 并行度
CPU_CORES=$(nproc 2>/dev/null || echo 4)
echo "检测到 $CPU_CORES 个 CPU 核心"
if [ "$CPU_CORES" -ge 4 ]; then
MVN_THREADS="2C"
else
MVN_THREADS="1C"
fi
echo "Maven 并行度: -T $MVN_THREADS"
# Maven 打包(使用阿里云镜像 + 多线程并行编译 + 跳过测试 + 离线优先)
mvn -B clean package \
-s /root/.m2/settings.xml \
-DskipTests \
-T 1C \
--no-transfer-progress
-Dmaven.test.skip=true \
-T "$MVN_THREADS" \
--no-transfer-progress \
--fail-at-end
JAR_FILE=$(ls par-api/target/*.jar | head -1)
echo "构建成功!产物: $JAR_FILE ($(du -sh $JAR_FILE | cut -f1))"
@@ -157,6 +169,8 @@ steps:
- frontend-build
# ===================== Docker 镜像构建 =====================
# 参考 mediabot 优化:Drone 已在前序步骤完成编译(frontend-build + maven-build),
# 此处使用 CI 精简 Dockerfile,仅将预构建 jar 打包进 JRE 镜像,无需在 Docker 内重新编译。
- name: build-docker-image
image: 192.168.31.253/library/docker:cli
volumes:
@@ -176,21 +190,22 @@ steps:
fi
echo "版本: $APP_VERSION"
# 拉取之前的镜像作为缓存来源(加速 layer 复用)
echo "正在拉取缓存镜像..."
docker pull "$IMAGE_NAME:latest" 2>/dev/null || true
docker pull "$LOCAL_HARBOR_REG/$LOCAL_HARBOR_PROJ/$IMAGE_NAME:latest" 2>/dev/null || true
# 验证 jar 产物存在
JAR_FILE=$(ls par-api/target/*.jar 2>/dev/null | head -1)
if [ -z "$JAR_FILE" ]; then
echo "错误:未找到 jar 产物,maven-build 可能失败"
exit 1
fi
echo "jar 产物: $JAR_FILE ($(du -sh $JAR_FILE | cut -f1))"
# 使用 BuildKit 构建,启用缓存
# 使用 CI 精简 Dockerfile:仅 COPY jar + 设置运行环境,秒级完成
docker build \
--cache-from "$IMAGE_NAME:latest" \
--cache-from "$LOCAL_HARBOR_REG/$LOCAL_HARBOR_PROJ/$IMAGE_NAME:latest" \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg VERSION="$APP_VERSION" \
--build-arg BUILD_TIME="$(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M')" \
-t "$IMAGE_NAME:$BUILD_VERSION" \
-t "$IMAGE_NAME:latest" \
-f par-api/Dockerfile \
-f Dockerfile \
.
echo "Docker 镜像构建完成。"

38
Dockerfile Normal file
View File

@@ -0,0 +1,38 @@
# syntax=docker/dockerfile:1
# PAR Server - CI 专用精简镜像
# 参考 mediabot 的优化思路:Drone 流水线已完成编译,此处仅打包产物
# 完整多阶段构建版本见 par-api/Dockerfile(适用于本地独立构建)
FROM 192.168.31.253/library/eclipse-temurin:21-jre-alpine
ARG VERSION=unknown
ARG BUILD_TIME=unknown
ARG BUILDKIT_INLINE_CACHE=1
LABEL maintainer="PAR Team"
LABEL description="PT Adapter Registry Server"
LABEL version="${VERSION}"
LABEL build-time="${BUILD_TIME}"
# 创建非 root 用户
RUN addgroup -S par && adduser -S par -G par
WORKDIR /app
# 创建静态文件目录
RUN mkdir -p /app/static/configs && chown -R par:par /app
# 直接复制 drone 已构建好的 jar(无需在 Docker 内重新编译)
COPY par-api/target/*.jar app.jar
USER par
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
CMD wget -qO- http://localhost:8080/health || exit 1
# 启动参数
ENTRYPOINT ["java", "-jar", "app.jar"]

View File

@@ -1,6 +1,7 @@
# syntax=docker/dockerfile:1
# PAR Server - 前后端一体化 Docker 镜像
# 参考 mediabot 的多阶段构建方式
# PAR Server - 前后端一体化 Docker 镜像(完整多阶段构建)
# 参考 mediabot 的多阶段构建方式,适用于本地独立构建(不依赖 Drone CI 预编译)
# CI 流水线请使用项目根目录的 Dockerfile(精简版,仅打包 drone 预编译产物)
# 启用 BuildKit 以支持 cache mount
# 第一阶段:构建前端