如何在FastAPI项目中用Celery定时备份Docker中的PostgreSQL?
解决Celery任务中实现PostgreSQL备份的方案
方案1:在Celery容器中安装PostgreSQL客户端,直接执行pg_dump
这是最安全且常规的实现方式,由于Celery与PostgreSQL处于同一Docker网络,可直接通过服务名访问数据库。
步骤1:修改Dockerfile,添加PostgreSQL客户端
在项目的Dockerfile中加入安装命令(以Python基础镜像为例):
# 基础镜像声明后添加 RUN apt-get update && apt-get install -y postgresql-client && rm -rf /var/lib/apt/lists/*
步骤2:在tasks.py中编写备份逻辑
使用Python的subprocess模块执行pg_dump命令,注意用Docker服务名替代localhost作为数据库地址:
from celery import Celery import subprocess import os from datetime import datetime from celery.schedules import crontab # 初始化Celery,根据你的实际配置调整 celery = Celery('tasks', broker='redis://redis:6379/0') @celery.task def dump_dbase(): # 生成带时间戳的备份文件名,防止覆盖 backup_filename = f"db_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.dump" # 指定备份存储路径,建议使用Docker共享卷挂载的目录 backup_path = os.path.join('/backups', backup_filename) # 构造pg_dump命令,替换为你的数据库服务名、用户名、库名 cmd = [ 'pg_dump', '-U', 'postgres', '-d', 'dbase', '-h', 'postgr', # 对应你的PostgreSQL容器服务名 '-f', backup_path ] try: # 设置环境变量避免密码输入提示,建议从环境变量读取密码而非硬编码 env = os.environ.copy() env['PGPASSWORD'] = os.getenv('POSTGRES_PASSWORD', '默认密码') # 执行备份命令 subprocess.run(cmd, check=True, env=env) return f"备份成功:{backup_path}" except subprocess.CalledProcessError as e: return f"备份失败:{str(e)}" # 配置周期性任务(示例:每天凌晨2点执行备份) celery.conf.beat_schedule = { 'daily-db-backup': { 'task': 'tasks.dump_dbase', 'schedule': crontab(hour=2, minute=0), }, }
步骤3:配置Docker共享卷持久化备份
在docker-compose.yaml中给Celery服务添加卷挂载,确保备份文件不会随容器销毁丢失:
services: celery: # 其他配置... volumes: - ./backups:/backups # 本地目录映射到容器内的备份路径 environment: - POSTGRES_PASSWORD=你的数据库密码 # 与PostgreSQL服务的密码保持一致 postgr: # 其他配置... volumes: - postgres_data:/var/lib/postgresql/data - ./backups:/backups # 可选,让PostgreSQL容器也能访问备份目录 volumes: postgres_data:
方案2:通过docker exec在PostgreSQL容器中执行pg_dump(不推荐)
此方式需要Celery容器访问Docker Socket,存在安全风险,仅适合特殊场景:
步骤1:修改docker-compose.yaml挂载Docker Socket
celery: # 其他配置... volumes: - /var/run/docker.sock:/var/run/docker.sock - ./backups:/backups environment: - POSTGRES_PASSWORD=你的数据库密码
步骤2:在tasks.py中编写备份逻辑
@celery.task def dump_dbase(): backup_filename = f"db_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.dump" backup_path = f"/backups/{backup_filename}" # 构造docker exec命令,直接在PostgreSQL容器内执行pg_dump cmd = f"docker exec postgr pg_dump -U postgres dbase > {backup_path}" try: env = os.environ.copy() env['PGPASSWORD'] = os.getenv('POSTGRES_PASSWORD', '默认密码') subprocess.run(cmd, check=True, shell=True, env=env) return f"备份成功:{backup_path}" except subprocess.CalledProcessError as e: return f"备份失败:{str(e)}"
关键注意事项
- 密码安全:绝对不要硬编码数据库密码,通过Docker环境变量传递更安全。
- 备份清理:可额外编写Celery任务,定期删除指定天数前的旧备份,避免磁盘空间耗尽。
- 任务监控:可结合Flower监控Celery任务的执行状态,及时发现备份失败情况。
内容的提问来源于stack exchange,提问作者Evgeny Romensky
相关产品推荐
相关产品推荐

