按照需求,需要每天凌晨自动备份数据库,并删除历史备份。
PostgreSQL 免密登录
设置免密登录,也可以不设置,不设置需要在脚本中加入密码
vim ~/.pgpass
localhost:5432:mydatabase:postgres:yourpassword
# 配置权限
chmod 600 ~/.pgpass
编写执行脚本
#!/bin/bash
# === 配置部分 ===
PGUSER="postgres" # PostgreSQL 用户名
PGDATABASE="hnfuel" # 需要备份的数据库名
BACKUP_DIR="/data/pg_backup" # 备份目录
RETENTION_DAYS=7 # 保留最近 N 天的备份
# === 系统自动生成部分 ===
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/backup_${PGDATABASE}_${TIMESTAMP}.sql.gz"
# 确保备份目录存在
mkdir -p "$BACKUP_DIR"
# === 开始备份 ===
echo "[$(date)] 开始备份数据库 $PGDATABASE ..."
# 如果path中有这个路径,可以直接pg_dump执行
/opt/postgresql/bin/pg_dump -U "$PGUSER" "$PGDATABASE" | gzip > "$BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "[$(date)] 备份成功:$BACKUP_FILE"
else
echo "[$(date)] 备份失败!" >&2
exit 1
fi
# === 删除旧备份 ===
echo "[$(date)] 清理 $RETENTION_DAYS 天前的备份文件..."
find "$BACKUP_DIR" -type f -name "backup_${PGDATABASE}_*.sql.gz" -mtime +$RETENTION_DAYS -exec rm -f {} \;
echo "[$(date)] 备份流程完成。"
添加执行权限
chmod +x /data/pg_backup/pg_backup.sh
定时执行
0 2 * * * /bin/bash /data/pg_backup/pg_backup.sh >> /data/pg_backup/backup.log 2>&1
恢复数据
psql -U postgres -d hnfuel_restore -f backup_hnfuel_20250418_143550.sql
# 输入密码的方式
PGPASSWORD=yourpassword psql -U postgres -d hnfuel_restore -f yourfile.sql
可能存在的问题
在执行脚本测试的时候报错,信息如下:
-bash: ./pg_backup.sh: /bin/bash^M: 坏的解释器: 没有那个文件或目录
原因是脚本文件是 Windows 格式的文本文件(CRLF 行尾),里面的第一行 #!/bin/bash 末尾带了一个 隐藏的 ^M(回车符),Linux 无法识别解释器路径 /bin/bash^M。
解决方式为:
- vim 打开文件
- : 输入命令set ff=unix
- 保存退出wq
双机备份脚本
之前备份的文件是sql版本的,只能恢复数据库,不能指定恢复某一部分,而且明文可查看,单机备份也不够安全。这里换成双机备份,而且输出dump文件。
#!/bin/bash
# === 配置部分 ===
PGUSER="postgres"
PGDATABASE="fueldb"
BACKUP_BASE="/home/appuser/pgsql_data_backups/pg_backup_schedule"
RETENTION_DAYS=7
# 远程服务器信息(可选)
REMOTE_USER="backupuser"
REMOTE_HOST="192.168.1.22"
REMOTE_PORT=2222
REMOTE_BASE_DIR="/data/pg_backup_schedule"
# === 生成变量 ===
TODAY=$(date "+%Y-%m-%d")
TARGET_DIR="$BACKUP_BASE"
BACKUP_FILE="${TARGET_DIR}/${TODAY}_${PGDATABASE}.dump"
# === 创建目录 ===
mkdir -p "$TARGET_DIR"
# === 执行备份 === 如果没有环境变量,找不到命令就写绝对路径
echo "[$(date)] 开始备份数据库 $PGDATABASE..."
pg_dump -U "$PGUSER" -v -Fc -d "$PGDATABASE" --no-owner -f "$BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "[$(date)] 备份成功:$BACKUP_FILE"
else
echo "[$(date)] 备份失败!" >&2
exit 1
fi
# === 删除本地旧备份 ===
echo "[$(date)] 清理本地 $RETENTION_DAYS 天前的备份..."
find "$BACKUP_BASE" -type f -name "*_${PGDATABASE}.dump" -mtime +$RETENTION_DAYS -exec rm -f {} \;
# === 传输并清理远程备份(可选)===
echo "[$(date)] 正在将备份传输到远程服务器 $REMOTE_HOST..."
ssh -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" "mkdir -p $REMOTE_BASE_DIR/$TODAY"
scp -P "$REMOTE_PORT" "$BACKUP_FILE" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_BASE_DIR}/${TODAY}/"
echo "[$(date)] 清理远程旧备份..."
ssh -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" \
"find '${REMOTE_BASE_DIR}' -type f -name '*_${PGDATABASE}.dump' -mtime +${RETENTION_DAYS} -exec rm -f {} \;"
echo "[$(date)] 备份完成。"
dump文件恢复方式
恢复数据库
# 恢复到现有数据库
pg_restore -U postgres -d fueldb_restored -v /path/to/2025-05-19_fueldb.dump
# 恢复到新建数据库
createdb -U postgres fueldb_restored
pg_restore -U postgres -d fueldb_restored -v /path/to/2025-05-19_fueldb.dump
恢复特定对象(如单表)
# 恢复一个名为 user_logs 的表
pg_restore -U postgres -d fueldb_restored -t user_logs /path/to/2025-05-19_fueldb.dump
-t 指定表,-n 可以指定 schema,比如:
pg_restore -U postgres -d fueldb_restored -n public -t user_logs ...
查看 .dump 内容(先看再决定要恢复什么)
pg_restore -l /path/to/backup.dump
| 功能 | 命令示例 |
|---|---|
| 全部还原 | pg_restore -d dbname backup.dump |
| 指定表还原 | pg_restore -d dbname -t tablename backup.dump |
| 指定 schema | pg_restore -d dbname -n schema_name backup.dump |
| 只导出 SQL(不执行) | pg_restore -f out.sql backup.dump |
| 只导入结构(无数据) | pg_restore --schema-only ... |
添加文件加密
环境变量中添加加密密码
echo 'export GPG_PASSPHRASE="your_strong_passphrase"' >> ~/.bash_profile
source ~/.bash_profile
脚本修改
GPG_PASSPHRASE="${GPG_PASSPHRASE}"
echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 -c yourfile.dump
# === 删除原始压缩包 ===
rm -f "$BACKUP_FILE"
echo "[$(date)] 清理 $RETENTION_DAYS 天前的备份文件..."
find "$BACKUP_DIR" -type f -name "backup_${PGDATABASE}_*.sql.gz.gpg" -mtime +$RETENTION_DAYS -exec rm -f {} \;
文件解密
gpg --output backup.sql.tar.gz --decrypt backup.sql.tar.gz.gpg
