一、前置准备:Docker PG备份核心前提
说到Docker里部署PostgreSQL的备份,很多朋友第一反应就是照搬MySQL的思路——建个用户、写个mysqldump脚本、挂个crontab,完事。可实际踩过坑的都知道,PostgreSQL在容器环境下的权限体系、命令语法、数据挂载方式都和MySQL差得不是一星半点,直接用老套路,很容易遇见权限报错、备份文件为空、恢复时各种失败。这篇文章专门为Docker容器里的PostgreSQL量身打造,从零搭建一套生产可用的、无侵入的、自动执行且自动清理的备份方案,适配PostgreSQL 10以上的所有容器版本,脚本复制即用,全程绕开容器特有的那些坑点,同时配套恢复验证流程,把容器化PG的数据安全痛点一次性解决。
适用场景也很明确:Docker或Docker Compose部署的PostgreSQL、中小规模PG实例(数据量100GB以内)、Linux宿主机环境。如果数据量更大、并发更高,可以在本方案基础上扩展pg_basebackup物理备份。

容器化PG备份的核心前提是数据目录持久化挂载,同时做好最小权限备份账号配置,杜绝超级用户滥用。
1. 确认PG容器信息与标准部署
首先确保PostgreSQL容器采用数据挂载方式启动——没有挂载数据卷的容器,容器一删数据全丢,备份就失去意义了。
Docker Run标准启动命令(含数据挂载):
docker run -d \ --name postgresql \ -p 5432:5432 \ -v /data/postgresql/data:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=你的超级密码 \ -e POSTGRES_USER=postgres \ --restart=always \ postgres:14Docker Compose部署方式:
version:'3'services: postgres: image: postgres:14 container_name: postgresql ports: - "5432:5432" volumes: - /data/postgresql/data:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: 你的超级密码 POSTGRES_USER: postgres restart: always然后执行以下命令查看运行中的容器,记录容器名称:
docker ps# 示例容器名:postgresql2. 创建Docker PG专用最小权限备份账号
生产环境千万不能直接用postgres超级用户去备份,得建一个专用备份账号,只给必需权限,把安全风险降到最低。
# 宿主机直接执行,进入容器PG命令行docker exec -it postgresql psql -U postgres# 创建备份账号(替换强密码)CREATE USER backup_user WITH PASSWORD '你的强密码';# 授予单库备份最小权限(以test_db为例,生产按需修改)GRANT CONNECT ON DATABASE test_db TO backup_user;GRANT SELECT ON ALL TABLES IN SCHEMA public TO backup_user;ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO backup_user;GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO backup_user;ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE ON SEQUENCES TO backup_user;# 退出命令行\q3. 宿主机创建备份目录
统一备份路径,方便管理,权限也容易管控,建议只允许root用户访问:
mkdir -p /data/backup/docker-postgresql/fullmkdir -p /data/backup/docker-postgresql/logschmod 700 /data/backup/docker-postgresql二、Docker PG备份核心原理
跟Docker MySQL备份的逻辑差不多——用docker exec -i在容器内部非交互地执行pg_dump,通过管道把备份数据流输出到宿主机。这样做无侵入,不阻塞业务,属于热备。PostgreSQL的MVCC机制默认不锁表,备份期间业务读写完全不受影响。
核心命令逻辑长这样:
PGPASSWORD=密码 docker exec -i 容器名 pg_dump [参数] > 宿主机备份文件安全提示:PGPASSWORD环境变量可以避免密码直接出现在命令行参数里,但在某些系统下仍可能通过进程环境变量被看到。高安全环境建议改用.pgpass文件或Docker secrets来管理凭据。另外,整个备份操作都在宿主机完成,不用进容器,不会污染业务环境。
三、实战1:Docker PG全量备份脚本
下面的脚本集成了防重复执行、自定义压缩、日志记录、异常处理、过期清理等功能,没有语法漏洞,拿过去改改配置就能用。注意:pg_dump默认是单线程,如果数据库超过50GB,建议用pg_dump -j并行导出,或者直接上物理备份(pg_basebackup)来提升效率。
#!/bin/bash########################################################### Docker PostgreSQL 全量备份脚本(生产级·容器专用)# 功能:MVCC无锁热备、压缩存储、防重复执行、日志记录、异常删除# 适配:PostgreSQL 10+ Docker版本##########################################################set -euo pipefail# ===================== 配置项(必须修改)=====================CONTAINER_NAME="postgresql" # PG容器名称PG_USER="backup_user" # 备份专用账号PG_PASSWORD="你的强密码" # 备份账号密码PG_DB="test_db" # 待备份数据库名# 宿主机备份路径BACKUP_ROOT="/data/backup/docker-postgresql"FULL_DIR="${BACKUP_ROOT}/full"LOG_DIR="${BACKUP_ROOT}/logs"RETENTION_DAYS=30 # 备份保留天数# ===========================================================# 变量初始化DATE=$(date +%Y%m%d_%H%M%S)BACKUP_FILE="${FULL_DIR}/pg_full_${PG_DB}_${DATE}.dump"LOG_FILE="${LOG_DIR}/pg_full_backup_${DATE}.log"LOCK_FILE="/tmp/docker_pg_backup.lock"# 初始化目录mkdir -p ${FULL_DIR} ${LOG_DIR}# 日志函数log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a ${LOG_FILE}}# 防重复执行加锁exec 99>${LOCK_FILE}flock -n 99 && log "脚本加锁成功" || { log "备份任务已在运行,退出"; exit 1; }log "==================== Docker PostgreSQL 全量备份开始 ===================="# 精确校验容器运行状态if ! docker ps --format '{{.Names}}' | grep -wq "^${CONTAINER_NAME}$"; then log "ERROR:容器 ${CONTAINER_NAME} 未运行,备份终止" exit 1fi# 校验数据库是否存在(权限隔离场景更稳定)if ! docker exec ${CONTAINER_NAME} psql -U ${PG_USER} -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='${PG_DB}'" | grep -q 1; then log "ERROR:数据库 ${PG_DB} 不存在,备份终止" exit 1fi# 执行容器内备份(无锁热备、自定义格式压缩,避免重复压缩)export PGPASSWORD=${PG_PASSWORD}docker exec -i ${CONTAINER_NAME} pg_dump \ -U ${PG_USER} \ -d ${PG_DB} \ --format=custom \ -Z 6 \ --no-owner \ --no-privileges > ${BACKUP_FILE}# 备份结果校验if [ $? -eq 0 ]; then SIZE=$(du -h ${BACKUP_FILE} | awk '{print $1}') log "✅ 备份成功 | 文件:${BACKUP_FILE} | 大小:${SIZE}"elselog "❌ 备份失败,删除无效备份文件" rm -f ${BACKUP_FILE} exit 1fi# 自动清理过期备份log "清理${RETENTION_DAYS}天前过期备份与日志"find ${FULL_DIR} -name "*.dump" -mtime +${RETENTION_DAYS} -deletefind ${LOG_DIR} -name "*.log" -mtime +${RETENTION_DAYS} -deletelog "==================== Docker PostgreSQL 备份完成 ===================="脚本使用步骤:
# 1. 创建脚本文件vim /usr/local/scripts/docker_pg_full_backup.sh# 2. 添加执行权限chmod +x /usr/local/scripts/docker_pg_full_backup.sh# 3. 手动测试执行/usr/local/scripts/docker_pg_full_backup.sh# 4. 查看日志与备份文件ls /data/backup/docker-postgresql/fullcat /data/backup/docker-postgresql/logs/对应日志文件四、实战2:定时任务配置(自动备份)
配置crontab定时任务,每天凌晨3点业务低峰期自动执行备份,尽量避免影响业务运行。
# 编辑定时任务crontab -e# 添加定时任务(每日凌晨3点执行)0 3 * * * /usr/local/scripts/docker_pg_full_backup.sh >> /var/log/cron/docker_pg_backup.log 2>&1# 查看定时任务crontab -l五、实战3:Docker PG备份恢复验证
备份有没有用,得恢复出来验证一下。下面这个脚本启动一个临时Docker PG容器来恢复备份,完全不碰生产数据库,彻底避免了误删数据的风险。而且示例里演示了“恢复到新库”的操作,更贴近生产实际。
#!/bin/bash########################################################### Docker PG备份验证脚本(临时容器·无生产污染)##########################################################set -euo pipefailBACKUP_ROOT="/data/backup/docker-postgresql"LOG_FILE="${BACKUP_ROOT}/logs/pg_verify_$(date +%Y%m%d).log"PG_IMAGE="postgres:14"TEMP_PWD="temp_verify_123"log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a ${LOG_FILE}; }BACKUP_FILE=$(ls -t ${BACKUP_ROOT}/full/*.dump 2>/dev/null | head -1)log "===== Docker PG备份有效性验证开始 ====="[ -z "${BACKUP_FILE}" ] && log "ERROR:无有效备份文件" && exit 1log "待验证备份:${BACKUP_FILE}"# 启动临时PG容器log "启动临时验证容器..."TEMP_CONTAINER=$(docker run -d \ -e POSTGRES_PASSWORD=${TEMP_PWD} \ --rm \ ${PG_IMAGE})# 循环等待PG启动(替代sleep 15,更可靠)log "等待临时PG容器启动..."until docker exec ${TEMP_CONTAINER} pg_isready -U postgres >/dev/null 2>&1; do sleep 2done# 执行恢复(修正gunzip误用,恢复到新创建的数据库,更贴合生产)export PGPASSWORD=${TEMP_PWD}# 1. 在临时容器内创建新的恢复数据库docker exec -i ${TEMP_CONTAINER} psql -U postgres -c "CREATE DATABASE test_restore;"# 2. 将备份恢复到新库(更专业,避免污染默认postgres库)docker exec -i ${TEMP_CONTAINER} pg_restore \ -U postgres \ -d test_restore \ --format=custom \ --no-owner \ --no-privileges < ${BACKUP_FILE}# 校验结果(查看新库是否有恢复的数据表)if docker exec ${TEMP_CONTAINER} psql -U postgres -d test_restore -c "\dt" | grep -q "public"; thenlog "✅ 备份验证通过,文件可正常恢复至新库"elselog "❌ 备份文件损坏,无法恢复"fi# 清理临时容器docker stop ${TEMP_CONTAINER}log "===== 备份验证完成 ====="六、Docker PG备份常见避坑指南
- 权限报错:确认备份账号已授予对应库的CONNECT、SELECT权限,容器名称配置正确。
- 备份失败:检查PG数据库名是否正确、容器网络正常、宿主机磁盘空间充足。
- 密码暴露:严禁在命令行直接明文写密码,统一使用PGPASSWORD环境变量。
- 恢复失败:自定义格式备份必须用pg_restore,不可用psql直接导入。
- 数据不一致:备份期间不要执行大规模DDL操作,PG的MVCC不保障DDL一致性。
七、生产优秀实践
- 备份目录权限设为700,仅root用户可访问,防止数据泄露。
- 定期执行备份验证,建议每周至少一次,确保备份有效性。
- 低峰期执行备份,避免占用业务资源;大数据库建议使用并行备份或物理备份。
- 重要数据建议开启异地备份,搭配本文脚本使用。
- 定时任务务必配置日志输出,方便异常排查。
