From 8ecce60eba453d59417c7b5fa4f54fbc9ca70a4d Mon Sep 17 00:00:00 2001 From: cnphpbb Date: Sun, 27 Apr 2025 14:27:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(backup):=20=E6=B7=BB=E5=8A=A0PostgreSQL?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=A4=87=E4=BB=BD=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加两个备份脚本,pg_backup.sh和pgDump.sh,用于定期备份PostgreSQL数据库。pg_backup.sh支持自动备份所有数据库并保留最近7天的备份,pgDump.sh支持备份单个数据库或表,并生成日志文件。这些脚本通过Docker容器执行备份操作,确保环境一致性。 --- crontab/posrgres/pgDump.sh | 130 ++++++++++++++++++++++++++++++++++ crontab/posrgres/pg_backup.sh | 74 +++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 crontab/posrgres/pgDump.sh create mode 100644 crontab/posrgres/pg_backup.sh diff --git a/crontab/posrgres/pgDump.sh b/crontab/posrgres/pgDump.sh new file mode 100644 index 0000000..bda2321 --- /dev/null +++ b/crontab/posrgres/pgDump.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +# @author: cnphpbb@hotmail.com +# @date: 2025-04-27 +# @desc: PostgreSQL数据库备份脚本 + +## 基础配置 +TOYEAR=$(date "+%Y") +TOMONTH=$(date "+%Y%m") +TODATE=$(date "+%Y%m%d") +NOWDATE=$(date "+%Y%m%d-%H%M%S") +BACKDIR=/data/backups/pg_backs # 备份目录 +TARLOGDIR=/data/backups/pg_tar_logs # 日志目录 +DAYDIR=${BACKDIR}/${TOMONTH}/${TODATE} +BACKLOGSDIR=${TARLOGDIR}/${TOMONTH}/logs/${TODATE} +BACKTARDIR=${TARLOGDIR}/${TOMONTH}/db_tars +LOGFILE=${BACKLOGSDIR}/pg-Dump.${NOWDATE}.log +BACKSQLFILE="" +FileSize=0 + +## PostgreSQL配置 +USERNAME=${PGSQL_USER} +PASSWORD=${PGSQL_PASS} +HOST=${PGSQL_HOST} +PORT=${PGSQL_PORT} +DOCKER_IMAGE="postgres:latest" + +## 创建目录 +if [ ! -d "${BACKLOGSDIR}" ]; then + mkdir -p ${BACKLOGSDIR} +fi + +if [ ! -d "${BACKTARDIR}" ]; then + mkdir -p ${BACKTARDIR} +fi + +cd ${BACKDIR} +if [ ! -d "${DAYDIR}" ]; then + mkdir -vp "$DAYDIR" >> ${LOGFILE} +fi + +## 工具函数 +curTime() { + NOWDATE=$(date "+%Y%m%d-%H%M%S") +} + +getLogFile(){ + curTime + LOGFILE=${BACKLOGSDIR}/pg-Dump.${NOWDATE}.log +} + +# 备份整个数据库 +db_full_backup() { + curTime + BACKSQLFILE=${DAYDIR}/$1-${NOWDATE}.sql + docker run --rm \ + -e PGPASSWORD="${PASSWORD}" \ + -v "${DAYDIR}:/backups" \ + "${DOCKER_IMAGE}" \ + pg_dump -h "${HOST}" -p "${PORT}" -U "${USERNAME}" -d "$1" \ + --no-password \ + --clean \ + --if-exists \ + -f "/backups/$1-${NOWDATE}.sql" + + gzip ${BACKSQLFILE} + getLogFile + if [ $? -ne 0 ]; then + echo "$NOWDATE PostgreSQL数据库 $1 备份失败!" >> ${LOGFILE} + else + echo "$NOWDATE PostgreSQL数据库 $1 备份成功!" >> ${LOGFILE} + fi +} + +# 备份单个表 +sigle_table_backup(){ + curTime + BACKSQLFILE=${DAYDIR}/$1_$2-${NOWDATE}.sql + docker run --rm \ + -e PGPASSWORD="${PASSWORD}" \ + -v "${DAYDIR}:/backups" \ + "${DOCKER_IMAGE}" \ + pg_dump -h "${HOST}" -p "${PORT}" -U "${USERNAME}" -d "$1" \ + --no-password \ + --clean \ + --if-exists \ + -t "$2" \ + -f "/backups/$1_$2-${NOWDATE}.sql" + + gzip ${BACKSQLFILE} + getLogFile + if [ $? -ne 0 ]; then + echo "$NOWDATE PostgreSQL表 $1.$2 备份失败!" >> ${LOGFILE} + else + echo "$NOWDATE PostgreSQL表 $1.$2 备份成功!" >> ${LOGFILE} + fi +} + +selfHelp() { + echo "pgDump.sh 帮助文档" + echo "-----------------------------------" + echo "-h --help 显示帮助信息" + echo + echo "\$1 数据库名 (备份整个数据库)" + echo "示例: pgDump.sh memos_db" + echo + echo "\$2 表名 (备份单个表)" + echo "示例: pgDump.sh memos_db users" +} + +## 主逻辑 +case $1 in + -h|--help|help ) + selfHelp + ;; + *) + if [ $# -eq 1 ]; then + echo "开始备份PostgreSQL数据库 $1..." + db_full_backup $1 + FileSize=$(stat -c %s ${BACKSQLFILE}) + echo "备份文件: ${BACKSQLFILE} ${FileSize} bytes" + echo "完成备份PostgreSQL数据库 $1" + else + echo "开始备份PostgreSQL表 $1.$2..." + sigle_table_backup $1 $2 + FileSize=$(stat -c %s ${BACKSQLFILE}) + echo "备份文件: ${BACKSQLFILE} ${FileSize} bytes" + echo "完成备份PostgreSQL表 $1.$2" + fi + ;; +esac \ No newline at end of file diff --git a/crontab/posrgres/pg_backup.sh b/crontab/posrgres/pg_backup.sh new file mode 100644 index 0000000..f6fc28c --- /dev/null +++ b/crontab/posrgres/pg_backup.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# PostgreSQL 备份脚本 +# 配置参数 +DB_HOST=${PGSQL_HOST} +DB_PORT=${PGSQL_PORT} +DB_USER=${PGSQL_USER} +DB_PASSWORD=${PGSQL_PASSWORD} +DOCKER_IMAGE="postgres:latest" + +# 备份目录设置 +BACKUP_DIR="/data/backups/posrgres/$(date +%Y)/$(date +%Y%m)" +DATE=$(date +%Y%m%d_%H%M%S) + +# 创建备份目录 +mkdir -p "$BACKUP_DIR" + +# 获取用户可以访问的所有数据库列表 +echo "获取可访问数据库列表..." +DB_LIST=$(docker run --rm \ + -e PGPASSWORD="${DB_PASSWORD}" \ + "${DOCKER_IMAGE}" \ + psql -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d postgres -t -c "SELECT datname FROM pg_database WHERE datname NOT IN ('template0', 'template1', 'postgres') AND datistemplate = false;") + +# 检查数据库列表 +if [ -z "$DB_LIST" ]; then + echo "没有找到可备份的数据库" + exit 1 +fi + +# 备份每个数据库 +for DB_NAME in $DB_LIST; do + echo "开始备份数据库 ${DB_NAME}..." + BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql" + + docker run --rm \ + -e PGPASSWORD="${DB_PASSWORD}" \ + -v "${BACKUP_DIR}:/backups" \ + "${DOCKER_IMAGE}" \ + pg_dump -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d "${DB_NAME}" \ + --no-password \ + --clean \ + --if-exists \ + -f "/backups/${DB_NAME}_${DATE}.sql" + + if [ $? -eq 0 ]; then + echo "备份成功: ${BACKUP_FILE}" + else + echo "备份失败: ${DB_NAME}" + fi +done + +# 保留本月的最近7天备份 +find "$BACKUP_DIR" -name "*_*.sql" -mtime +7 -type f -exec rm -f {} \; +# 删除非本年&本月的备份目录(仅在每月2号执行) +if [ $(date +%d) -eq 2 ]; then + CURRENT_YEAR=$(date +%Y) + CURRENT_MONTH=$(date +%m) + find "/data/backups/posrgres/" -maxdepth 1 -type d -name "20*" | while read -r year_dir; do + year=$(basename "$year_dir") + if [ "$year" != "$CURRENT_YEAR" ]; then + echo "删除非本年目录: $year_dir" + rm -rf "$year_dir" + else + find "$year_dir" -maxdepth 1 -type d -name "20*" | while read -r month_dir; do + month=$(basename "$month_dir" | cut -c5-6) + if [ "$month" != "$CURRENT_MONTH" ]; then + echo "删除非本月目录: $month_dir" + rm -rf "$month_dir" + fi + done + fi + done +fi \ No newline at end of file