Files
FruitServer/Dockerfile
T
jianghaifeng b567365460 feat(deploy): D1 后端部署就绪(配置外置 + prod fail-fast + 自包含 Compose + 冒烟/回滚)
为什么:用户下午要部署,但全仓没有任何部署产物;且生产漏配密钥会静默使用代码里的 dev 默认值,
属上线阻塞项(04-部署架构 / 12-上线检查清单)。

- 配置外置(三件):DB_URL、JWT 双密钥(**发现 app-secret 此前没外置,一直用 dev 默认值**)、
  MEDIA_SIGNATURE_SECRET、MEDIA_SIGNATURE_REQUIRED、CORS_ALLOWED_ORIGINS、MEDIA_ROOT_DIR
- 新增三份 application-prod.yml:签名强制开启、CORS 收紧、媒资指向挂载点、日志级别
- 新增 ProdSecretGuard(@Profile("prod")):密钥缺失/仍是 dev 默认值/不足 32 位、签名未开、
  DB_URL 或 CORS 为空 → 一次列全并终止启动(exit 1)
- 新增 /healthz 轻量健康端点:查明 /actuator/health 的"超时"是旧 jar 未重启所致,项目本就
  没有 actuator 依赖,故不引新依赖;同时把 /healthz 加进安全白名单
- Docker 化:多阶段 Dockerfile(非 root、tini、依赖层缓存、ffmpeg 只给 worker)、.dockerignore、
  自包含 docker-compose.yml(含 PostgreSQL 18 + Redis + 命名卷 + 按序初始化 sql + healthcheck)
- tools/smoke.sh(失败非 0 退出)+ DEPLOY.md(Compose 主线 / 裸 jar 兜底 / 回滚 / 故障速查)
- 实测:mvn test 83 条全过;两入口 package 通过;prod 缺密钥退出码 1 且报错明确、配齐后正常启动;
  冒烟脚本全 PASS;本机无 Docker,镜像与 compose 未经构建验证(已在回执如实标注)
2026-10-16 13:01:08 +08:00

73 lines
3.1 KiB
Docker
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.
# Author: fruit.com.cn
#
# 多阶段构建:maven 构建 fat jar -> JRE 运行(非 root、tini 做 1 号进程)。
# 三个可运行件共用一份 Dockerfile,用 MODULE 构建参数区分。
#
# 构建(在 FruitServer 目录下执行):
# docker build -t fruitshorts/app-api:latest --build-arg MODULE=fruitshorts-app-api .
# docker build -t fruitshorts/admin-api:latest --build-arg MODULE=fruitshorts-admin-api .
# docker build -t fruitshorts/transcode-worker:latest --build-arg MODULE=fruitshorts-transcode-worker \
# --build-arg INSTALL_FFMPEG=true .
#
# 注意:本机当前没有 Docker(见 DEPLOY.md),这份 Dockerfile 未经本机构建验证。
# ---------- 1. 构建阶段 ----------
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /build
# 先只拷各模块 pom 再拉依赖:依赖层可复用,改业务代码不会重新下载依赖
COPY pom.xml .
COPY fruitshorts-common/pom.xml fruitshorts-common/
COPY fruitshorts-framework/pom.xml fruitshorts-framework/
COPY fruitshorts-module-system/pom.xml fruitshorts-module-system/
COPY fruitshorts-module-content/pom.xml fruitshorts-module-content/
COPY fruitshorts-module-media/pom.xml fruitshorts-module-media/
COPY fruitshorts-module-user/pom.xml fruitshorts-module-user/
COPY fruitshorts-module-playback/pom.xml fruitshorts-module-playback/
COPY fruitshorts-module-interaction/pom.xml fruitshorts-module-interaction/
COPY fruitshorts-module-commerce/pom.xml fruitshorts-module-commerce/
COPY fruitshorts-module-creator/pom.xml fruitshorts-module-creator/
COPY fruitshorts-admin-api/pom.xml fruitshorts-admin-api/
COPY fruitshorts-app-api/pom.xml fruitshorts-app-api/
COPY fruitshorts-transcode-worker/pom.xml fruitshorts-transcode-worker/
RUN mvn -B -q -DskipTests dependency:go-offline || true
COPY . .
ARG MODULE=fruitshorts-app-api
RUN mvn -B -DskipTests -pl ${MODULE} -am package \
&& cp ${MODULE}/target/*.jar /build/app.jar
# ---------- 2. 运行阶段 ----------
FROM eclipse-temurin:21-jre
# ffmpeg 只有转码 worker 需要,用构建参数控制,避免把 80MB 装进两个 API 镜像
ARG INSTALL_FFMPEG=false
RUN apt-get update \
&& apt-get install -y --no-install-recommends tini curl \
&& if [ "$INSTALL_FFMPEG" = "true" ]; then \
apt-get install -y --no-install-recommends ffmpeg; \
fi \
&& rm -rf /var/lib/apt/lists/*
# 非 root 运行;/data/uploads 预留给媒资挂载卷
RUN groupadd -r fruitshorts \
&& useradd -r -g fruitshorts -d /app -s /sbin/nologin fruitshorts \
&& mkdir -p /app /data/uploads \
&& chown -R fruitshorts:fruitshorts /app /data/uploads
WORKDIR /app
COPY --from=build --chown=fruitshorts:fruitshorts /build/app.jar /app/app.jar
USER fruitshorts
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75 -XX:+UseG1GC -Duser.timezone=Asia/Shanghai" \
SPRING_PROFILES_ACTIVE=prod \
MEDIA_ROOT_DIR=/data/uploads
# 健康检查打 /healthz(不依赖 actuator,见 HealthController)
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
CMD curl -fsS http://127.0.0.1:${SERVER_PORT:-8080}/healthz || exit 1
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["sh", "-c", "exec java $JAVA_OPTS -jar /app/app.jar"]