Files
senmesh-zc/deploy/offline/scripts/export-images.sh
KodouWZF 4eb67e246e feat(交付): 客户侧两台服务器离线部署包
内网机/外网机各起一套栈,两台之间不开任何端口,文件只经光闸在
gate/out 与对端 gate/in 之间单向摆渡。一份 compose + 一份 config +
一份 nginx 模板,全部差异收在 .env 里。

- docker-compose.yml:5 服务只发布前端端口;app 容器 IP 锁死并由
  compose 注入 -Dcode.snowflake.workid.<IP>=<WORK_ID>,绕开兜底 99
  超雪花 5 位上限导致启动即崩的问题
- .env.iw / .env.ow:出厂配置与随机口令已填好,仅 MESHSAFE_SECRET
  故意留占位(以 MeshSafe 侧白名单为准);按 maintainer 决定原样入库
- install.sh iw|ow:按角色建 .env -> 自检 -> sha256 校验 tar -> 架构
  核对 -> docker load 后校验 tag -> 建目录/属主/SELinux 标签 -> 起栈
  并逐个等健康。修掉 pipefail 下 `grep | head -1` 静默中断、架构字段
  误读 manifest.json(实际在 Config blob)、die() 未定义先被调用
- export-images.sh:就地刷新 images/*.tar、sql、.env 的 tag 与
  SHA256SUMS,再打 dist 交付盘;tar 与 SHA256SUMS 由 .gitignore 排除
- sql/01+02:从 backend/db 的 PG 全量与初始数据覆盖拷贝。三个
  upgrade-*.sql 的 PG 段(x_upload_config、x_file_security)已在
  init-table-postgres-full.sql 内,空库跑 01->02 即完整现状
- smoke_test.py:18 条断言的现场验收,凭证全部走环境变量
- 部署说明.md:拓扑、交付清单、出厂口令表、iw/ow 差异、验收清单、
  13 条已知坑

镜像 tar 不进 git,装机包由 export-images.sh 出盘。
2026-11-02 20:40:16 +08:00

111 lines
5.1 KiB
Bash
Raw Permalink 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.
#!/usr/bin/env bash
# =============================================================================
# 出交付盘:在我方构建机上执行,把 deploy/offline/ 刷新成一个可直接带走的完整交付包
#
# ./scripts/export-images.sh 1.0.0 # 默认 linux/amd64
# TARGET_PLATFORM=linux/arm64 ./scripts/export-images.sh 1.0.0 # 鲲鹏/飞腾
#
# 刷新后的 deploy/offline/(现场照它装,不再依赖本仓库):
# ├── images/*.tar 五个镜像 + SHA256SUMS.txt
# ├── sql/01-init-table.sql 建表 02-init-data.sql 初始数据
# ├── .env.iw / .env.ow 内网机 / 外网机出厂配置
# └── docker-compose.yml config/ nginx/ scripts/ VERSION.txt
# 另外产出 deploy/offline/dist/sfile-offline-<版本>-<平台>.tar.gz(拷盘/刻录用)
#
# 前置:backend/target/s-file.jar 与 frontend/ 已构建好(见仓库根 README)
# =============================================================================
set -euo pipefail
VER="${1:?用法:export-images.sh <版本号>,如 1.0.0}"
PLATFORM="${TARGET_PLATFORM:-linux/amd64}"
PLATFORM_TAG="$(echo "$PLATFORM" | tr -d '/:')"
HERE="$(cd "$(dirname "$0")/.." && pwd)" # deploy/offline
ROOT="$(cd "$HERE/../.." && pwd)" # 仓库根
OUT="$HERE/dist/sfile-offline-$VER-$PLATFORM_TAG"
APP_IMAGE="sfile-app:$VER"
WEB_IMAGE="sfile-web:$VER"
PG_IMAGE="postgres:18" # 验证过的是 18.3,同大版本即可
REDIS_IMAGE="redis:8" # 验证过的是 8.6.3
MQ_IMAGE="rabbitmq:3.13-management-alpine" # 验证过的是 3.13.7
say() { printf '\033[1;36m==> %s\033[0m\n' "$1"; }
say "构建目标平台:$PLATFORM"
[ "$PLATFORM" = "linux/amd64" ] || say "非 amd64 需要 buildx/QEMU 模拟器,慢属正常"
# ---------- 1. 构建业务镜像 ----------
say "构建 $APP_IMAGE"
docker build --platform "$PLATFORM" -f "$ROOT/deploy/docker/Dockerfile.app" -t "$APP_IMAGE" "$ROOT/backend/target"
say "构建 $WEB_IMAGE(内含内网+外网两套前端,耗时较长)"
docker build --platform "$PLATFORM" -f "$ROOT/deploy/docker/Dockerfile.web" -t "$WEB_IMAGE" "$ROOT/frontend"
# ---------- 2. 基础镜像就位(本机没有才拉,避免交付时缺包) ----------
for img in "$PG_IMAGE" "$REDIS_IMAGE" "$MQ_IMAGE"; do
docker image inspect "$img" >/dev/null 2>&1 || {
say "本机没有 $img,拉取 $PLATFORM 版本"
docker pull --platform "$PLATFORM" "$img"
}
done
# ---------- 3. 镜像 tar 就地导出 ----------
say "docker save 导出镜像到 $HERE/images/(约 700M,耐心等)"
mkdir -p "$HERE/images"
rm -f "$HERE"/images/*.tar "$HERE/images/SHA256SUMS.txt"
docker save -o "$HERE/images/sfile-app.tar" "$APP_IMAGE"
docker save -o "$HERE/images/sfile-web.tar" "$WEB_IMAGE"
docker save -o "$HERE/images/postgres.tar" "$PG_IMAGE"
docker save -o "$HERE/images/redis.tar" "$REDIS_IMAGE"
docker save -o "$HERE/images/rabbitmq.tar" "$MQ_IMAGE"
( cd "$HERE/images" && sha256sum *.tar > SHA256SUMS.txt )
# ---------- 4. SQL 与 .env 就地刷新 ----------
# 建表脚本必须先于灌数据脚本执行,靠文件名前缀定序
say "刷新 sql/(来自 backend/db/)"
mkdir -p "$HERE/sql"
cp "$ROOT/backend/db/init-table-postgres-full.sql" "$HERE/sql/01-init-table.sql"
cp "$ROOT/backend/db/init-data.sql" "$HERE/sql/02-init-data.sql"
say "刷新 .env.iw / .env.ow 的镜像 tag 为 $VER"
for f in .env.iw .env.ow; do
[ -f "$HERE/$f" ] || { say "缺少 $HERE/$f,跳过"; continue; }
sed -i -E "s/^APP_IMAGE=.*/APP_IMAGE=sfile-app:$VER/; s/^WEB_IMAGE=.*/WEB_IMAGE=sfile-web:$VER/" "$HERE/$f"
done
# ---------- 5. 组交付目录并打包 ----------
say "组装 $OUT"
rm -rf "$OUT"
mkdir -p "$OUT/sql"
cp "$HERE/docker-compose.yml" "$HERE/.env.example" "$HERE/.env.iw" "$HERE/.env.ow" "$OUT/"
cp -r "$HERE/config" "$HERE/nginx" "$HERE/scripts" "$HERE/sql" "$HERE/images" "$OUT/"
cp "$HERE/.gitignore" "$OUT/" 2>/dev/null || true
{
echo "s-file 离线交付包 $VER"
echo "构建平台: $PLATFORM"
echo "导出时间: $(date '+%F %T')"
echo
echo "镜像清单(sha256 见 images/SHA256SUMS.txt):"
for t in "$OUT"/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 "SQL: sql/01-init-table.sql sql/02-init-data.sql"
echo
echo "现场步骤(两台服务器各执行一次):"
echo " 内网机 tar -xzf sfile-offline-$VER-$PLATFORM_TAG.tar.gz && cd sfile-offline-$VER-$PLATFORM_TAG"
echo " vi .env.iw # 至少改 MESHSAFE_SECRET,按需改口令/网段/目录"
echo " ./scripts/install.sh iw"
echo " 外网机 同上,改成 ./scripts/install.sh ow"
echo " 验证 python3 scripts/smoke_test.py"
} > "$OUT/VERSION.txt"
say "打包交付盘"
mkdir -p "$HERE/dist"
tar -czf "$OUT.tar.gz" -C "$(dirname "$OUT")" "$(basename "$OUT")"
du -h "$OUT.tar.gz" | awk '{print " 交付盘: "$1" "$2}'
echo " 两台服务器各自解压同一份盘,装完只差 install.sh 的参数(iw / ow)"