ops: add oneclick deploy bundle builder
This commit is contained in:
172
scripts/build_oneclick_bundle.sh
Executable file
172
scripts/build_oneclick_bundle.sh
Executable 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"
|
||||
Reference in New Issue
Block a user