ops: add encrypted db snapshot publish/import scripts
This commit is contained in:
99
scripts/db_snapshot_import.sh
Executable file
99
scripts/db_snapshot_import.sh
Executable file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# 从“私有数据仓库”(Gitea)拉取最新加密快照并导入到本地数据库。
|
||||
#
|
||||
# 用法:
|
||||
# export SAASSHOP_DB_SNAPSHOT_KEY='你的强密码'
|
||||
# export SAASSHOP_DATA_REPO_SSH='git@git.xxx:owner/saasshop-data(.wiki).git'
|
||||
# bash scripts/db_snapshot_import.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 21
|
||||
fi
|
||||
|
||||
if [[ "${SAASSHOP_DB_SNAPSHOT_KEY:-}" == "" ]]; then
|
||||
echo "缺少解密密钥:请先 export SAASSHOP_DB_SNAPSHOT_KEY='...'"
|
||||
exit 22
|
||||
fi
|
||||
|
||||
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 23
|
||||
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 24
|
||||
fi
|
||||
|
||||
WORK_DIR="/tmp/saasshop-data-repo"
|
||||
if [[ -d "$WORK_DIR/.git" ]]; then
|
||||
echo "[data-repo] updating existing clone: $WORK_DIR"
|
||||
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
|
||||
|
||||
ENC_FILE="$WORK_DIR/snapshots/latest.sql.gz.enc"
|
||||
MANIFEST="$WORK_DIR/snapshots/manifest.json"
|
||||
|
||||
if [[ ! -f "$ENC_FILE" ]]; then
|
||||
echo "数据仓未找到快照:$ENC_FILE"
|
||||
exit 25
|
||||
fi
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_DIR" || true' EXIT
|
||||
|
||||
SQL_GZ="$TMP_DIR/latest.sql.gz"
|
||||
|
||||
echo "[snapshot] decrypting ..."
|
||||
openssl enc -d -aes-256-cbc -pbkdf2 \
|
||||
-pass env:SAASSHOP_DB_SNAPSHOT_KEY \
|
||||
-in "$ENC_FILE" -out "$SQL_GZ"
|
||||
|
||||
echo "[snapshot] importing into mysql ($DB_DATABASE) ..."
|
||||
# 注意:快照里使用了 --databases,会包含 CREATE DATABASE/USE
|
||||
# 这里直接交给 mysql 执行。
|
||||
gzip -dc "$SQL_GZ" | mysql \
|
||||
--host="$DB_HOST" --port="$DB_PORT" \
|
||||
--user="$DB_USERNAME" --password="$DB_PASSWORD"
|
||||
|
||||
echo "[done] imported snapshot"
|
||||
if [[ -f "$MANIFEST" ]]; then
|
||||
echo "[info] manifest:"
|
||||
cat "$MANIFEST"
|
||||
fi
|
||||
151
scripts/db_snapshot_publish.sh
Executable file
151
scripts/db_snapshot_publish.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/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
|
||||
|
||||
# 准备数据仓工作区
|
||||
WORK_DIR="/tmp/saasshop-data-repo"
|
||||
if [[ -d "$WORK_DIR/.git" ]]; then
|
||||
echo "[data-repo] updating existing clone: $WORK_DIR"
|
||||
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"
|
||||
Reference in New Issue
Block a user