Files
saasshop/scripts/db_snapshot_publish.sh

154 lines
4.8 KiB
Bash
Executable File
Raw 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
set -euo pipefail
# 将当前数据库导出并加密后推送到“私有数据仓库”Gitea
# - 不把明文 SQL 放入 git
# - 数据仓库建议单独授权/独立权限
#
# 依赖mysqldump / mysql / openssl / gzip / git
#
# 用法:
# 1) 设置密钥(不要写入仓库):
# export SAASSHOP_DB_SNAPSHOT_KEY='你的强密码'
# 2) 可选设置数据仓库地址(若不设则从 /app/working.secret/saasshop_data_repo_ssh 读取):
# export SAASSHOP_DATA_REPO_SSH='git@git.xxx:owner/saasshop-data(.wiki).git'
# 3) 执行:
# bash scripts/db_snapshot_publish.sh
REPO_DIR=$(cd "$(dirname "$0")/.." && pwd)
cd "$REPO_DIR"
DATA_REPO_SSH=${SAASSHOP_DATA_REPO_SSH:-""}
if [[ "$DATA_REPO_SSH" == "" && -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 "缺少数据仓库地址:"
echo "- 请设置环境变量 SAASSHOP_DATA_REPO_SSH"
echo "- 或创建文件 /app/working.secret/saasshop_data_repo_ssh内容为 ssh 地址)"
exit 11
fi
if [[ "${SAASSHOP_DB_SNAPSHOT_KEY:-}" == "" ]]; then
echo "缺少加密密钥:请先 export SAASSHOP_DB_SNAPSHOT_KEY='...'(不要写入仓库)"
exit 12
fi
# 读取 DB 连接(优先 .env其次 /app/working.secret/laravel.env.snapshot
ENV_FILE="$REPO_DIR/.env"
if [[ ! -f "$ENV_FILE" && -f /app/working.secret/laravel.env.snapshot ]]; then
ENV_FILE="/app/working.secret/laravel.env.snapshot"
fi
if [[ ! -f "$ENV_FILE" ]]; then
echo "找不到 .env 或 /app/working.secret/laravel.env.snapshot无法确定 DB 配置"
exit 13
fi
# shellcheck disable=SC1090
set -a
source "$ENV_FILE"
set +a
DB_HOST=${DB_HOST:-127.0.0.1}
DB_PORT=${DB_PORT:-3306}
DB_DATABASE=${DB_DATABASE:-}
DB_USERNAME=${DB_USERNAME:-}
DB_PASSWORD=${DB_PASSWORD:-}
if [[ "$DB_DATABASE" == "" || "$DB_USERNAME" == "" ]]; then
echo "DB 配置不完整DB_DATABASE/DB_USERNAME 不能为空"
exit 14
fi
STAMP=$(date +%Y%m%d_%H%M%S)
OUT_DIR=$(mktemp -d)
SQL_GZ="$OUT_DIR/${DB_DATABASE}_${STAMP}.sql.gz"
ENC_FILE="$OUT_DIR/${DB_DATABASE}_${STAMP}.sql.gz.enc"
MANIFEST="$OUT_DIR/manifest.json"
cleanup() {
rm -rf "$OUT_DIR" || true
}
trap cleanup EXIT
echo "[snapshot] dumping database '$DB_DATABASE' ..."
# 导出策略:单库结构+数据;保留 routines/triggers/events避免锁表
# 注意:--databases 会在 SQL 中带 CREATE DATABASE/USE
mysqldump \
--host="$DB_HOST" --port="$DB_PORT" \
--user="$DB_USERNAME" --password="$DB_PASSWORD" \
--databases "$DB_DATABASE" \
--single-transaction --quick --skip-lock-tables \
--routines --triggers --events \
--hex-blob \
--default-character-set=utf8mb4 \
| gzip -9 > "$SQL_GZ"
echo "[snapshot] encrypting ..."
openssl enc -aes-256-cbc -pbkdf2 -salt \
-pass env:SAASSHOP_DB_SNAPSHOT_KEY \
-in "$SQL_GZ" -out "$ENC_FILE"
SHA256=$(sha256sum "$ENC_FILE" | awk '{print $1}')
SIZE=$(wc -c < "$ENC_FILE" | tr -d ' ')
CODE_HEAD=$(git rev-parse --short HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
cat > "$MANIFEST" <<EOF
{
"generated_at": "$(date -Iseconds)",
"db": {
"host": "${DB_HOST}",
"port": ${DB_PORT},
"database": "${DB_DATABASE}"
},
"code": {
"repo": "saasshop",
"branch": "${BRANCH}",
"commit": "${CODE_HEAD}"
},
"snapshot": {
"filename": "latest.sql.gz.enc",
"source_filename": "$(basename "$ENC_FILE")",
"sha256": "${SHA256}",
"size": ${SIZE}
}
}
EOF
# 准备数据仓工作区
# 数据仓工作区:固定目录,但每次都会强制将 remote 指向当前 DATA_REPO_SSH避免曾经 clone 过其它仓(如 .wiki.git导致推错。
WORK_DIR="/tmp/saasshop-data-repo"
if [[ -d "$WORK_DIR/.git" ]]; then
echo "[data-repo] updating existing clone: $WORK_DIR"
git -C "$WORK_DIR" remote set-url origin "$DATA_REPO_SSH"
git -C "$WORK_DIR" fetch origin
git -C "$WORK_DIR" checkout main || git -C "$WORK_DIR" checkout -b main
git -C "$WORK_DIR" pull --rebase origin main || true
else
rm -rf "$WORK_DIR" || true
echo "[data-repo] cloning: $DATA_REPO_SSH -> $WORK_DIR"
git clone "$DATA_REPO_SSH" "$WORK_DIR"
git -C "$WORK_DIR" checkout main || git -C "$WORK_DIR" checkout -b main
fi
mkdir -p "$WORK_DIR/snapshots"
cp -f "$ENC_FILE" "$WORK_DIR/snapshots/latest.sql.gz.enc"
cp -f "$MANIFEST" "$WORK_DIR/snapshots/manifest.json"
# 同时保留一份带时间戳的历史(便于回滚/比对)
cp -f "$ENC_FILE" "$WORK_DIR/snapshots/${DB_DATABASE}_${STAMP}.sql.gz.enc"
git -C "$WORK_DIR" add snapshots
if git -C "$WORK_DIR" diff --cached --quiet; then
echo "[data-repo] no changes, skip commit"
else
git -C "$WORK_DIR" commit -m "snapshot: ${DB_DATABASE} ${STAMP} (code ${CODE_HEAD})"
git -C "$WORK_DIR" push origin main
fi
echo "[done] snapshot published to data repo"