Files
AI_Video_Factory/scripts/backup.sh
youbin 36f466ba11
Some checks failed
CI / Migrations, tests, build, and audit (push) Failing after 10m7s
CI / Production gate and container images (push) Successful in 20m35s
Release v1.0.0
2026-07-31 14:21:43 +08:00

104 lines
3.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_dir="$(cd "${script_dir}/.." && pwd)"
env_file="${FRAMEFLOW_ENV_FILE:-${repo_dir}/.env.production}"
backup_parent="${1:-${repo_dir}/backups}"
metrics_dir="${FRAMEFLOW_BACKUP_METRICS_DIR:-/var/lib/frameflow/metrics}"
timestamp="$(date -u +%Y%m%dT%H%M%SZ)"
backup_dir="${backup_parent%/}/frameflow-${timestamp}"
started_at_seconds="$(date +%s)"
metrics_tmp=""
cleanup() {
if [[ -n "${metrics_tmp}" && -f "${metrics_tmp}" ]]; then
rm -f "${metrics_tmp}"
fi
}
trap cleanup EXIT
if [[ ! -f "${env_file}" ]]; then
echo "Production environment file not found: ${env_file}" >&2
exit 1
fi
compose=(docker compose --env-file "${env_file}" -f "${repo_dir}/docker-compose.prod.yml")
mkdir -p "${backup_parent}"
if ! mkdir "${backup_dir}"; then
echo "Refusing to overwrite an existing backup directory: ${backup_dir}" >&2
exit 1
fi
postgres_container="$("${compose[@]}" ps -q postgres)"
redis_container="$("${compose[@]}" ps -q redis)"
minio_container="$("${compose[@]}" ps -q minio)"
for container in "${postgres_container}" "${redis_container}" "${minio_container}"; do
if [[ -z "${container}" ]]; then
echo "PostgreSQL, Redis, and MinIO must be running before backup." >&2
exit 1
fi
done
echo "Creating PostgreSQL logical backup..."
"${compose[@]}" exec -T postgres sh -c 'exec pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' > "${backup_dir}/postgres.dump"
echo "Flushing and archiving Redis persistence..."
"${compose[@]}" exec -T redis sh -c '
if [ -n "${REDIS_PASSWORD:-}" ]; then
redis-cli --no-auth-warning -a "$REDIS_PASSWORD" SAVE >/dev/null
else
redis-cli SAVE >/dev/null
fi
'
docker run --rm --volumes-from "${redis_container}" -v "${backup_dir}:/backup" alpine:3.20 \
tar -czf /backup/redis-data.tar.gz -C /data .
echo "Archiving MinIO object data..."
docker run --rm --volumes-from "${minio_container}" -v "${backup_dir}:/backup" alpine:3.20 \
tar -czf /backup/minio-data.tar.gz -C /data .
{
echo "created_at=${timestamp}"
echo "compose_project=$(docker inspect --format '{{ index .Config.Labels "com.docker.compose.project" }}' "${postgres_container}")"
echo "postgres_container=${postgres_container}"
echo "redis_container=${redis_container}"
echo "minio_container=${minio_container}"
} > "${backup_dir}/manifest.txt"
if command -v sha256sum >/dev/null 2>&1; then
(cd "${backup_dir}" && sha256sum postgres.dump redis-data.tar.gz minio-data.tar.gz > SHA256SUMS)
else
(cd "${backup_dir}" && shasum -a 256 postgres.dump redis-data.tar.gz minio-data.tar.gz > SHA256SUMS)
fi
"${repo_dir}/scripts/verify-backup.sh" "${backup_dir}"
completed_at_seconds="$(date +%s)"
backup_size_bytes=0
for backup_file in postgres.dump redis-data.tar.gz minio-data.tar.gz manifest.txt SHA256SUMS; do
file_size="$(wc -c < "${backup_dir}/${backup_file}" | tr -d '[:space:]')"
backup_size_bytes=$((backup_size_bytes + file_size))
done
mkdir -p "${metrics_dir}"
metrics_tmp="$(mktemp "${metrics_dir%/}/frameflow_backup.prom.tmp.XXXXXX")"
cat > "${metrics_tmp}" <<EOF
# HELP frameflow_backup_last_success_timestamp_seconds Unix timestamp of the last complete FrameFlow backup.
# TYPE frameflow_backup_last_success_timestamp_seconds gauge
frameflow_backup_last_success_timestamp_seconds ${completed_at_seconds}
# HELP frameflow_backup_last_size_bytes Total size of files in the last complete FrameFlow backup.
# TYPE frameflow_backup_last_size_bytes gauge
frameflow_backup_last_size_bytes ${backup_size_bytes}
# HELP frameflow_backup_last_duration_seconds Duration of the last complete FrameFlow backup.
# TYPE frameflow_backup_last_duration_seconds gauge
frameflow_backup_last_duration_seconds $((completed_at_seconds - started_at_seconds))
EOF
chmod 0644 "${metrics_tmp}"
mv -f "${metrics_tmp}" "${metrics_dir%/}/frameflow_backup.prom"
metrics_tmp=""
echo "Backup complete: ${backup_dir}"
echo "Backup metrics updated: ${metrics_dir%/}/frameflow_backup.prom"