ops: add oneclick deploy bundle builder

This commit is contained in:
萝卜
2026-03-18 12:04:09 +08:00
parent 8ea5646be5
commit 83332f265d

172
scripts/build_oneclick_bundle.sh Executable file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env bash
set -euo pipefail
# 构建“一键部署包”(代码 + vendor + 加密数据库快照)
# 目标:下载压缩包 → 解压 → 运行 install.sh → 即可恢复到最新数据并可访问。
#
# 依赖git / tar / gzip
# 可选composer仅当需要现装 vendor
#
# 用法:
# bash scripts/build_oneclick_bundle.sh
# 输出:
# /app/working/dist/saasshop_bundle_<timestamp>.tar.gz
# /app/working/dist/saasshop_bundle_latest.tar.gz
REPO_DIR=$(cd "$(dirname "$0")/.." && pwd)
cd "$REPO_DIR"
DIST_DIR="/app/working/dist"
mkdir -p "$DIST_DIR"
DATA_REPO_SSH=""
if [[ -f /app/working.secret/saasshop_data_repo_ssh ]]; then
DATA_REPO_SSH=$(cat /app/working.secret/saasshop_data_repo_ssh)
fi
if [[ "$DATA_REPO_SSH" == "" ]]; then
echo "缺少数据仓地址:/app/working.secret/saasshop_data_repo_ssh"
exit 31
fi
STAMP=$(date +%Y%m%d_%H%M%S)
BUNDLE_ROOT=$(mktemp -d)
trap 'rm -rf "$BUNDLE_ROOT" || true' EXIT
APP_DIR="$BUNDLE_ROOT/saasshop"
mkdir -p "$APP_DIR"
# 1) 打包代码(不带 .git
echo "[bundle] copying app files ..."
# 使用 tar 管道复制(比 cp -a 更容易排除)
tar \
--exclude=".git" \
--exclude="node_modules" \
--exclude="storage/logs" \
--exclude="storage/framework/cache" \
--exclude="storage/framework/sessions" \
--exclude="storage/framework/views" \
--exclude="storage/app/private" \
--exclude=".env" \
-cf - . | (cd "$APP_DIR" && tar -xf -)
# 2) 确保 vendor 存在(无构建链/傻瓜部署,优先直接随包携带)
if [[ ! -d "$APP_DIR/vendor" ]]; then
echo "[bundle] vendor 不存在,尝试 composer install --no-dev ..."
if command -v composer >/dev/null 2>&1; then
(cd "$APP_DIR" && composer install --no-dev --prefer-dist --no-interaction)
else
echo "[bundle] composer 不存在且 vendor 缺失,无法构建傻瓜包"
exit 32
fi
fi
# 3) 拉取数据仓最新快照
echo "[bundle] fetching latest encrypted snapshot from data repo ..."
DATA_TMP="$BUNDLE_ROOT/data_repo"
git clone "$DATA_REPO_SSH" "$DATA_TMP" >/dev/null
if [[ ! -f "$DATA_TMP/snapshots/latest.sql.gz.enc" ]]; then
echo "数据仓缺少 snapshots/latest.sql.gz.enc"
exit 33
fi
mkdir -p "$APP_DIR/bundle/snapshots"
cp -f "$DATA_TMP/snapshots/latest.sql.gz.enc" "$APP_DIR/bundle/snapshots/latest.sql.gz.enc"
if [[ -f "$DATA_TMP/snapshots/manifest.json" ]]; then
cp -f "$DATA_TMP/snapshots/manifest.json" "$APP_DIR/bundle/snapshots/manifest.json"
fi
# 4) 写入 install.sh真正一键入口
cat > "$APP_DIR/install.sh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
# SaaSShop 一键部署脚本(随 bundle 一起发放)
# 用法:
# export SAASSHOP_DB_SNAPSHOT_KEY='解密密钥'
# bash install.sh
#
# 你也可以先准备好 .env推荐脚本会优先读取项目根目录 .env。
APP_DIR=$(cd "$(dirname "$0")" && pwd)
cd "$APP_DIR"
if [[ ! -f .env ]]; then
if [[ -f .env.example ]]; then
cp .env.example .env
echo "[install] 已生成 .env来自 .env.example请按需修改 DB_* / APP_URL 等配置。"
else
echo "[install] 缺少 .env 与 .env.example无法继续"
exit 41
fi
fi
# 读取 .env仅用于 DB 连接)
set -a
# shellcheck disable=SC1091
source .env
set +a
DB_HOST=${DB_HOST:-127.0.0.1}
DB_PORT=${DB_PORT:-3306}
DB_DATABASE=${DB_DATABASE:-appdb}
DB_USERNAME=${DB_USERNAME:-appuser}
DB_PASSWORD=${DB_PASSWORD:-}
if [[ "${SAASSHOP_DB_SNAPSHOT_KEY:-}" == "" ]]; then
echo "[install] 缺少 SAASSHOP_DB_SNAPSHOT_KEY无法解密并恢复完整数据。"
echo "[install] 请先export SAASSHOP_DB_SNAPSHOT_KEY='...密钥...'"
exit 42
fi
# 权限准备
mkdir -p storage bootstrap/cache
chmod -R ug+rwX storage bootstrap/cache || true
# APP_KEY
if ! grep -q '^APP_KEY=' .env || [[ "${APP_KEY:-}" == "" ]]; then
echo "[install] 生成 APP_KEY ..."
php artisan key:generate --force
fi
echo "[install] 导入最新数据库快照 ..."
ENC_FILE="bundle/snapshots/latest.sql.gz.enc"
if [[ ! -f "$ENC_FILE" ]]; then
echo "[install] 缺少快照文件:$ENC_FILE"
exit 43
fi
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR" || true' EXIT
SQL_GZ="$TMP_DIR/latest.sql.gz"
openssl enc -d -aes-256-cbc -pbkdf2 \
-pass env:SAASSHOP_DB_SNAPSHOT_KEY \
-in "$ENC_FILE" -out "$SQL_GZ"
gzip -dc "$SQL_GZ" | mysql \
--host="$DB_HOST" --port="$DB_PORT" \
--user="$DB_USERNAME" --password="$DB_PASSWORD"
echo "[install] 清理缓存 ..."
php artisan optimize:clear
echo "[done] 部署完成。接下来:配置 nginx 指向 public/,即可访问。"
EOF
chmod +x "$APP_DIR/install.sh"
# 5) 打包
OUT_FILE="$DIST_DIR/saasshop_bundle_${STAMP}.tar.gz"
LATEST_FILE="$DIST_DIR/saasshop_bundle_latest.tar.gz"
echo "[bundle] creating tar.gz ..."
(
cd "$BUNDLE_ROOT"
tar -czf "$OUT_FILE" saasshop
)
cp -f "$OUT_FILE" "$LATEST_FILE"
echo "[bundle] output: $OUT_FILE"
echo "[bundle] latest: $LATEST_FILE"