#!/usr/bin/env bash # ============================================================================= # 出包脚本(我方构建机上执行,现场用不到) # # ./deployment/scripts/build-package.sh 1.0.1 # TARGET_PLATFORM=linux/arm64 ./deployment/scripts/build-package.sh 1.0.1 # 鲲鹏/飞腾 # # 版本号与 git tag 对应:出 1.0.1 的包就打 tag v1.0.1。 # 把 deployment/iw 与 deployment/ow 刷成两个可直接带走的完整部署包: # 1. 后端 jar(mvn package,SKIP_JAR=1 跳过) # 2. sfile-app:<版本> 镜像 # 3. 前端内/外网静态包 -> iw/web、ow/web(现场可直接改文件替换页面) # 4. sql/01、sql/02(来自 backend/db) # 5. images/*.tar + SHA256SUMS.txt(存一份到暂存目录再拷两侧,省一次 docker save) # 6. 两侧 VERSION.txt,并把 .env 的 APP_IMAGE tag 对齐 # # 不动两侧 volumes/(那是现场运行时数据)与 .env 里的口令。 # ============================================================================= set -euo pipefail VER="${1:?用法:build-package.sh <版本号>,如 1.1.0}" PLATFORM="${TARGET_PLATFORM:-linux/amd64}" PLATFORM_TAG="$(echo "$PLATFORM" | tr -d '/:')" HERE="$(cd "$(dirname "$0")" && pwd)" # deployment/scripts ROOT="$(cd "$HERE/../.." && pwd)" # 仓库根 DEP="$ROOT/deployment" APP_IMAGE="sfile-app:$VER" WEB_TMP="sfile-web:pkg-$VER" # 只为导出前端静态包,不交付这个镜像 NGINX_IMAGE="nginx:1.27-alpine" PG_IMAGE="postgres:18" REDIS_IMAGE="redis:8" MQ_IMAGE="rabbitmq:3.13-management-alpine" APP_JAR="$ROOT/backend/target/s-file.jar" STAGE="$DEP/.stage-images-$PLATFORM_TAG" say() { printf '\n\033[1;36m==> %s\033[0m\n' "$1"; } die() { printf '\033[1;31m!!! %s\033[0m\n' "$1" >&2; exit 1; } [ -d "$DEP/iw" ] && [ -d "$DEP/ow" ] || die "找不到 deployment/iw 或 deployment/ow" # 只重跑某几步:SKIP_JAR=1 SKIP_WEB=1 SKIP_SAVE=1 [ "${SKIP_JAR:-0}" = "1" ] || { say "1/6 构建后端 jar(JDK8)" [ -n "${JAVA_HOME:-}" ] || JAVA_HOME="/d/dev/jdk8/jdk8u504-b01" MVN="${MVN:-/d/dev/maven-tmp/apache-maven-3.8.8/bin/mvn}" command -v "$MVN" >/dev/null 2>&1 || die "找不到 maven:$MVN(用 MVN=<路径> 覆盖)" ( cd "$ROOT/backend" && "$MVN" -s /d/dev/maven-conf/settings.xml -q package -Dmaven.test.skip=true ) } [ -s "$APP_JAR" ] || die "$APP_JAR 不存在或为空,先构建后端" say " 使用 jar:$(ls -la "$APP_JAR" | awk '{print $5" 字节,"$6" "$7" "$8}')" say "2/6 构建 $APP_IMAGE(平台 $PLATFORM)" [ "$PLATFORM" = "linux/amd64" ] || say " 非 amd64 需要 buildx/QEMU 模拟器,慢属正常" docker build --platform "$PLATFORM" -f "$ROOT/deploy/docker/Dockerfile.app" -t "$APP_IMAGE" "$ROOT/backend/target" # 前端不打进镜像:静态包放 deployment/<侧>/web/,现场改页面直接替换文件 [ "${SKIP_WEB:-0}" = "1" ] || { say "3/6 构建前端并从临时镜像导出内/外网静态包" docker build --platform "$PLATFORM" -f "$ROOT/deploy/docker/Dockerfile.web" -t "$WEB_TMP" "$ROOT/frontend" cid="$(docker create "$WEB_TMP")" for side in iw ow; do src=/usr/share/nginx/$([ "$side" = iw ] && echo inside || echo outside) rm -rf "$DEP/$side/web" docker cp "$cid:$src" "$DEP/$side/web" [ -s "$DEP/$side/web/index.html" ] || die "$side/web 导出不完整(缺 index.html)" printf ' %-3s web/ %s\n' "$side" "$(du -sh "$DEP/$side/web" | cut -f1)" done docker rm "$cid" >/dev/null docker image rm "$WEB_TMP" >/dev/null 2>&1 || true } say "4/6 刷新 sql/(来自 backend/db)" for side in iw ow; do cp "$ROOT/backend/db/init-table-postgres-full.sql" "$DEP/$side/sql/01-init-table.sql" cp "$ROOT/backend/db/init-data.sql" "$DEP/$side/sql/02-init-data.sql" for u in "$ROOT"/backend/db/upgrade-*.sql; do cp "$u" "$DEP/$side/sql/upgrade/$(basename "$u")"; done done # Windows 上编辑器/工具很容易写出 CRLF:install.sh 带 \r 在 Linux 上第一行就报错, # .env 的值尾部带 \r 会让口令/JWT 对不上。出包前把随包文本统一成 LF。 say " 统一随包文本为 LF" for side in iw ow; do for f in $(find "$DEP/$side" -maxdepth 2 -type f \ \( -name '*.sh' -o -name '*.yml' -o -name '*.sql' -o -name '*.conf' \ -o -name '*.md' -o -name '*.txt' -o -name '.env' \) \ -not -path "*/images/*"); do tr -d '\r' < "$f" > "$f.lf" && mv "$f.lf" "$f" done done # ---------- 5. 镜像 tar ---------- for img in "$PG_IMAGE" "$REDIS_IMAGE" "$MQ_IMAGE" "$NGINX_IMAGE"; do docker image inspect "$img" >/dev/null 2>&1 || { say " 本机没有 $img,拉取 $PLATFORM 版本" docker pull --platform "$PLATFORM" "$img" } done [ "${SKIP_SAVE:-0}" = "1" ] || { say "5/6 docker save(先存暂存目录再拷两侧,约 640M × 2)" rm -rf "$STAGE"; mkdir -p "$STAGE" docker save -o "$STAGE/sfile-app.tar" "$APP_IMAGE" docker save -o "$STAGE/nginx.tar" "$NGINX_IMAGE" docker save -o "$STAGE/postgres.tar" "$PG_IMAGE" docker save -o "$STAGE/redis.tar" "$REDIS_IMAGE" docker save -o "$STAGE/rabbitmq.tar" "$MQ_IMAGE" ( cd "$STAGE" && sha256sum *.tar > SHA256SUMS.txt ) for side in iw ow; do mkdir -p "$DEP/$side/images" rm -f "$DEP/$side/images"/*.tar "$DEP/$side/images/SHA256SUMS.txt" cp "$STAGE"/*.tar "$STAGE/SHA256SUMS.txt" "$DEP/$side/images/" done rm -rf "$STAGE" } say "6/6 对齐 .env 的 APP_IMAGE tag 并写 VERSION.txt" for side in iw ow; do sed -i -E "s|^APP_IMAGE=.*|APP_IMAGE=$APP_IMAGE|" "$DEP/$side/.env" { echo "s-file 部署包 $VER($([ "$side" = iw ] && echo 内网机 iw || echo 外网机 ow))" echo "构建平台: $PLATFORM" echo "导出时间: $(date '+%F %T')" echo "后端 jar: $(cd "$ROOT" && git rev-parse --short HEAD)(+ 未提交改动则与本仓库当前源码一致)" echo echo "镜像清单(sha256 见 images/SHA256SUMS.txt):" for t in "$DEP/$side/images"/*.tar; do tags="$(tar -xOf "$t" manifest.json | tr -d '\n' \ | { grep -oE '"RepoTags":\[[^]]*\]' || true; } | awk 'NR==1{print}')" printf ' %-18s %-8s %s\n' "$(basename "$t")" "$(du -h "$t" | cut -f1)" "${tags:-?}" done echo echo "前端静态包: web/(内网包/外网包已分别就位,改页面直接替换文件)" echo "SQL: sql/01-init-table.sql sql/02-init-data.sql 老库增量: sql/upgrade/" echo echo "现场步骤(本机执行):" echo " 1) 整目录拷到服务器,例如 /opt/sfile-$side && cd /opt/sfile-$side" echo " 2) vi .env # 至少确认 MESHSAFE_ENABLED/SECRET、WEB_PORT、SFILE_DATA_ROOT、GATE_*" echo " 3) ./scripts/install.sh" } > "$DEP/$side/VERSION.txt" done say "完成" for side in iw ow; do printf ' deployment/%s %s(images %s)\n' "$side" "$(du -sh "$DEP/$side" | cut -f1)" "$(du -sh "$DEP/$side/images" | cut -f1)" done echo " 拷包即用:内网机拿 iw/,外网机拿 ow/,两份互不依赖" echo " 提醒:images/*.tar 与 SHA256SUMS.txt 已被 .gitignore 排除,只走交付盘"