#!/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" < $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"