完善SpacetimeDB逐文件增量备份
新增data-dir逐文件CAS基线、history归档与安全清理 发布并校验OSS latest pointer,支持异机自动恢复 接入dev和release可选的files-history定时备份profile 补齐备份测试、生产门禁、环境示例与运维文档
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -514,6 +514,76 @@ const checks = [
|
||||
reason:
|
||||
'生产冷备份 service 必须用 node -- 分隔脚本参数,避免 Node 22 抢占业务 --env-file。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-database-backup.service',
|
||||
excludes: '--storage-format files',
|
||||
reason: '生产数据库备份主 service 必须继续保持 archive full 默认行为。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-database-backup-files-history.conf',
|
||||
includes: 'ExecStart=\nExecStart=/usr/bin/node -- /opt/genarrative/current/scripts/database-backup-to-oss.mjs --env-file',
|
||||
reason: 'files-history drop-in 必须先清空主 service 的 ExecStart,并使用 current release 脚本。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-database-backup-files-history.conf',
|
||||
includes: '--storage-format files --mode history --work-dir /var/lib/genarrative/database-backups/files-history',
|
||||
reason: 'files-history drop-in 必须只执行逐文件历史归档,并复用已建立基线的独立 work-dir。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-database-backup-files-history.conf',
|
||||
excludes: '--stop-service',
|
||||
reason: 'files-history 在线归档不可停止 SpacetimeDB。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-database-backup-files-history.conf',
|
||||
excludes: '--database',
|
||||
reason: 'files-history drop-in 不得写死数据库名,必须从环境文件读取。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-database-backup-files-history.conf',
|
||||
excludes: '--bucket',
|
||||
reason: 'files-history drop-in 不得写死 OSS bucket,必须从环境文件读取。',
|
||||
},
|
||||
{
|
||||
file: 'scripts/jenkins-server-provision.sh',
|
||||
includes: 'DATABASE_BACKUP_PROFILE="${DATABASE_BACKUP_PROFILE:-archive-full}"',
|
||||
reason: 'Server-Provision 的数据库备份 profile 必须默认保持 archive-full。',
|
||||
},
|
||||
{
|
||||
file: 'scripts/jenkins-server-provision.sh',
|
||||
includes: 'archive-full|files-history)',
|
||||
reason: 'Server-Provision 必须拒绝未知数据库备份 profile。',
|
||||
},
|
||||
{
|
||||
file: 'scripts/jenkins-server-provision.sh',
|
||||
includes: '--storage-format files --mode history --work-dir',
|
||||
reason: 'Server-Provision 启用 files-history 前必须用真实 current release 脚本执行只读 baseline 预检。',
|
||||
},
|
||||
{
|
||||
file: 'scripts/jenkins-server-provision.sh',
|
||||
includes: 'run_cmd rm -f "${DATABASE_BACKUP_FILES_HISTORY_DROP_IN}" "${DATABASE_BACKUP_LEGACY_DEV_DROP_IN}"',
|
||||
reason: 'Server-Provision 切回 archive-full 时必须移除托管及现场遗留的 history drop-in。',
|
||||
},
|
||||
{
|
||||
file: 'scripts/jenkins-server-provision.sh',
|
||||
includes: 'install_file "${rendered_drop_in}" "${DATABASE_BACKUP_FILES_HISTORY_DROP_IN}" 0644',
|
||||
reason: 'Server-Provision 必须从仓库模板安装托管的 files-history drop-in。',
|
||||
},
|
||||
{
|
||||
file: 'jenkins/Jenkinsfile.production-server-provision',
|
||||
includes: "choice(name: 'DATABASE_BACKUP_PROFILE', choices: ['archive-full', 'files-history']",
|
||||
reason: 'Server-Provision Job 必须显式暴露 archive-first 的数据库备份 profile。',
|
||||
},
|
||||
{
|
||||
file: 'jenkins/Jenkinsfile.production-server-provision',
|
||||
includes: "string(name: 'DATABASE_BACKUP_FILES_HISTORY_WORK_DIR', defaultValue: '/var/lib/genarrative/database-backups/files-history'",
|
||||
reason: 'Server-Provision Job 必须允许 dev/release 为 files-history 选择各自的 baseline state 目录。',
|
||||
},
|
||||
{
|
||||
file: 'jenkins/Jenkinsfile.production-server-provision',
|
||||
excludes: "params.DEPLOY_TARGET == 'release' && databaseBackupProfile == 'files-history'",
|
||||
reason: 'release 必须能在显式选择 profile 且 baseline 预检通过后启用 files-history。',
|
||||
},
|
||||
{
|
||||
file: 'scripts/database-backup-to-oss.mjs',
|
||||
includes: 'assertSufficientWorkDirSpace({dataDir, workDir, args, env})',
|
||||
@@ -6837,6 +6907,7 @@ const checks = [
|
||||
const nodeEnvFileCommandFiles = [
|
||||
'package.json',
|
||||
'deploy/systemd/genarrative-database-backup.service',
|
||||
'deploy/systemd/genarrative-database-backup-files-history.conf',
|
||||
'scripts/deploy/production-stdb-publish.sh',
|
||||
'scripts/deploy/pingora-direct-enable.sh',
|
||||
'scripts/deploy/pingora-direct-rollback.sh',
|
||||
|
||||
+1926
-66
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,11 @@ GENARRATIVE_OPENSSL_VERSION="${GENARRATIVE_OPENSSL_VERSION:-3.2.0}"
|
||||
GENARRATIVE_OPENSSL_PREFIX="${GENARRATIVE_OPENSSL_PREFIX:-/opt/genarrative/openssl-3.2.0}"
|
||||
GENARRATIVE_OPENSSL_SOURCE_URL="${GENARRATIVE_OPENSSL_SOURCE_URL:-https://github.com/openssl/openssl/releases/download/openssl-${GENARRATIVE_OPENSSL_VERSION}/openssl-${GENARRATIVE_OPENSSL_VERSION}.tar.gz}"
|
||||
GENARRATIVE_OPENSSL_SOURCE_SHA256="${GENARRATIVE_OPENSSL_SOURCE_SHA256:-14c826f07c7e433706fb5c69fa9e25dab95684844b4c962a2cf1bf183eb4690e}"
|
||||
DATABASE_BACKUP_PROFILE="${DATABASE_BACKUP_PROFILE:-archive-full}"
|
||||
DATABASE_BACKUP_FILES_HISTORY_WORK_DIR="${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR:-/var/lib/genarrative/database-backups/files-history}"
|
||||
DATABASE_BACKUP_FILES_HISTORY_DROP_IN_DIR="/etc/systemd/system/genarrative-database-backup.service.d"
|
||||
DATABASE_BACKUP_FILES_HISTORY_DROP_IN="${DATABASE_BACKUP_FILES_HISTORY_DROP_IN_DIR}/10-files-history.conf"
|
||||
DATABASE_BACKUP_LEGACY_DEV_DROP_IN="${DATABASE_BACKUP_FILES_HISTORY_DROP_IN_DIR}/10-dev-files.conf"
|
||||
|
||||
require_non_root_relative_path() {
|
||||
local label="$1"
|
||||
@@ -63,6 +68,21 @@ validate_server_names() {
|
||||
done
|
||||
}
|
||||
|
||||
validate_database_backup_profile() {
|
||||
case "${DATABASE_BACKUP_PROFILE}" in
|
||||
archive-full|files-history)
|
||||
;;
|
||||
*)
|
||||
echo "[server-provision] DATABASE_BACKUP_PROFILE 只能是 archive-full 或 files-history,当前值: ${DATABASE_BACKUP_PROFILE}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [[ ! "${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR}" =~ ^/var/lib/genarrative/database-backups/[A-Za-z0-9._/-]+$ || "${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR}" == *..* ]]; then
|
||||
echo "[server-provision] DATABASE_BACKUP_FILES_HISTORY_WORK_DIR 必须是 /var/lib/genarrative/database-backups/ 下不含连续点号的绝对路径,当前值: ${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_cmd() {
|
||||
echo "+ $*"
|
||||
if [[ "${DRY_RUN}" != "true" ]]; then
|
||||
@@ -917,6 +937,52 @@ render_database_backup_service() {
|
||||
deploy/systemd/genarrative-database-backup.service
|
||||
}
|
||||
|
||||
render_database_backup_files_history_drop_in() {
|
||||
local current_escaped env_escaped work_dir_escaped
|
||||
current_escaped="$(escape_sed_replacement "${CURRENT_LINK}")"
|
||||
env_escaped="$(escape_sed_replacement "${API_ENV_FILE}")"
|
||||
work_dir_escaped="$(escape_sed_replacement "${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR}")"
|
||||
sed \
|
||||
-e "s|/opt/genarrative/current|${current_escaped}|g" \
|
||||
-e "s|/etc/genarrative/api-server.env|${env_escaped}|g" \
|
||||
-e "s|/var/lib/genarrative/database-backups/files-history|${work_dir_escaped}|g" \
|
||||
deploy/systemd/genarrative-database-backup-files-history.conf
|
||||
}
|
||||
|
||||
configure_database_backup_profile() {
|
||||
local rendered_drop_in
|
||||
|
||||
if [[ "${DATABASE_BACKUP_PROFILE}" == "archive-full" ]]; then
|
||||
echo "[server-provision] 数据库备份 profile=archive-full,保留主 service 的全量冷备行为。"
|
||||
run_cmd rm -f "${DATABASE_BACKUP_FILES_HISTORY_DROP_IN}" "${DATABASE_BACKUP_LEGACY_DEV_DROP_IN}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "[server-provision] 数据库备份 profile=files-history,先只读验证 full baseline state。"
|
||||
if [[ "${DRY_RUN}" == "true" ]]; then
|
||||
echo "+ /usr/bin/node -- ${CURRENT_LINK}/scripts/database-backup-to-oss.mjs --env-file ${API_ENV_FILE} --storage-format files --mode history --work-dir ${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR} --dry-run"
|
||||
else
|
||||
if [[ ! -f "${CURRENT_LINK}/scripts/database-backup-to-oss.mjs" ]]; then
|
||||
echo "[server-provision] current release 缺少数据库备份脚本: ${CURRENT_LINK}/scripts/database-backup-to-oss.mjs" >&2
|
||||
exit 1
|
||||
fi
|
||||
/usr/bin/node -- "${CURRENT_LINK}/scripts/database-backup-to-oss.mjs" \
|
||||
--env-file "${API_ENV_FILE}" \
|
||||
--storage-format files \
|
||||
--mode history \
|
||||
--work-dir "${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR}" \
|
||||
--dry-run
|
||||
fi
|
||||
|
||||
run_cmd install -d -o genarrative -g genarrative -m 0750 "${DATABASE_BACKUP_FILES_HISTORY_WORK_DIR}"
|
||||
run_cmd install -d -o root -g root -m 0755 "${DATABASE_BACKUP_FILES_HISTORY_DROP_IN_DIR}"
|
||||
run_cmd rm -f "${DATABASE_BACKUP_LEGACY_DEV_DROP_IN}"
|
||||
rendered_drop_in="$(mktemp)"
|
||||
render_database_backup_files_history_drop_in >"${rendered_drop_in}"
|
||||
install_file "${rendered_drop_in}" "${DATABASE_BACKUP_FILES_HISTORY_DROP_IN}" 0644
|
||||
rm -f "${rendered_drop_in}"
|
||||
}
|
||||
|
||||
render_health_patrol_service() {
|
||||
local current_escaped
|
||||
current_escaped="$(escape_sed_replacement "${CURRENT_LINK}")"
|
||||
@@ -930,6 +996,7 @@ require_path deploy/systemd/genarrative-api.service
|
||||
require_path deploy/systemd/genarrative-external-generation-worker@.service
|
||||
require_path deploy/systemd/genarrative-external-generation-controller.service
|
||||
require_path deploy/systemd/genarrative-database-backup.service
|
||||
require_path deploy/systemd/genarrative-database-backup-files-history.conf
|
||||
require_path deploy/systemd/genarrative-database-backup.timer
|
||||
require_path deploy/systemd/genarrative-health-patrol.service
|
||||
require_path deploy/systemd/genarrative-health-patrol.timer
|
||||
@@ -951,9 +1018,10 @@ require_path scripts/deploy/maintenance-off.sh
|
||||
require_path scripts/deploy/maintenance-status.sh
|
||||
|
||||
validate_server_names
|
||||
validate_database_backup_profile
|
||||
require_non_root_relative_path "PROVISION_TOOLS_DIR" "${PROVISION_TOOLS_DIR}"
|
||||
|
||||
echo "[server-provision] target=${DEPLOY_TARGET}, dry_run=${DRY_RUN}, nginx_config_mode=${NGINX_CONFIG_MODE}, source_commit=$(cat .jenkins-source-commit)"
|
||||
echo "[server-provision] target=${DEPLOY_TARGET}, dry_run=${DRY_RUN}, nginx_config_mode=${NGINX_CONFIG_MODE}, database_backup_profile=${DATABASE_BACKUP_PROFILE}, source_commit=$(cat .jenkins-source-commit)"
|
||||
|
||||
run_cmd id
|
||||
require_root_for_real_provision
|
||||
@@ -1033,6 +1101,7 @@ else
|
||||
echo "[server-provision] 已存在环境文件,保留不覆盖: ${API_ENV_FILE}"
|
||||
fi
|
||||
ensure_api_runtime_env_defaults
|
||||
configure_database_backup_profile
|
||||
|
||||
if [[ ! -f "${WORKER_ENV_FILE}" ]]; then
|
||||
echo "+ create ${WORKER_ENV_FILE} from example"
|
||||
|
||||
Reference in New Issue
Block a user