内网机/外网机各起一套栈,两台之间不开任何端口,文件只经光闸在 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 出盘。
111 lines
5.1 KiB
Bash
111 lines
5.1 KiB
Bash
#!/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)"
|