带有转储数据和迁移的 Django 备份策略

Posted

技术标签:

【中文标题】带有转储数据和迁移的 Django 备份策略【英文标题】:Django backup strategy with dumpdata and migrations 【发布时间】:2016-04-21 16:36:58 【问题描述】:

与this question 一样,我为我的数据库设置了一个基于dumpdata 的备份系统。该设置类似于运行一个调用dumpdata 并将备份移动到远程服务器的cron 脚本,目的是简单地使用loaddata 来恢复数据库。但是,我是not sure this plays well with migrations。 loaddata 现在有一个 ignorenonexistent 开关来处理已删除的模型/字段,但它无法解决使用一次性默认值添加列或应用 RunPython 代码的情况。

在我看来,有两个子问题需要解决:

使用每个应用的当前版本标记每个dumpdata 输出文件 将固定装置拼接到迁移路径中

我对如何在不引入大量开销的情况下解决第一个问题感到困惑。每次备份保存一个包含app_name: migration_number 映射的额外文件就足够了吗?

第一个问题解决后,我认为第二个问题会更容易,因为过程大致是:

    创建一个新数据库 将迁移向前运行到每个应用的适当点 使用给定的夹具文件调用loaddata 运行其余的迁移

this question(链接自错误报告)中有一些我认为可以用于此目的的代码。

由于这些是数据库的相当常规/大的快照,我不想将它们作为数据迁移保留在迁移目录中。

【问题讨论】:

这不能回答您的问题,但我发现使用数据库转储是一种非常简单的备份解决方案。我对 Postgres 使用 pg_dump,对 mysql 数据库使用 mysqldump 如何更简单?如果您在备份后应用迁移,您最终不会遇到同样的问题吗? 您的数据库转储包含数据库的完整副本。这包括django_migrations 表。在数据库转储之前创建的迁移将不会再次运行,只会运行比数据库转储更新的迁移。 【参考方案1】:

我正在采取以下步骤在我的项目的任何实例之间备份、恢复或传输我的 postgresql 数据库:

我们的想法是尽可能减少迁移,就像manage.py makemigrations 第一次在空数据库上运行一样。

假设我们的开发环境有一个工作数据库。此数据库是生产数据库的当前副本不应对任何更改开放。我们添加了模型、更改了属性等,这些操作产生了额外的迁移。

现在数据库已准备好迁移到生产环境,如前所述,该数据库不向公众开放,因此不会以任何方式进行更改。为了实现这一点:

我在开发环境中执行正常程序。 我将项目复制到生产环境。 我在生产环境中执行正常程序

我们在开发环境中进行更改。生产数据库中不应发生任何更改,因为它们将被覆盖

正常程序

首先,我有一个项目目录的备份(其中包括一个 requirements.txt 文件),一个数据库的备份 - 当然 - git 是我的朋友。

    我会备份dumpdata 以备不时之需。但是,dumpdata 在内容类型、权限或应使用natural foreignkey 的其他情况方面有一些严重 limitations:

    ./manage.py dumpdata --exclude auth.permission --exclude contenttypes  --exclude admin.LogEntry --exclude sessions --indent 2 > db.json
    

    我使用pg_dump 备份:

    pg_dump -U $user -Fc $database --exclude-table=django_migrations > path/to/backup-dir/db.dump
    

    仅当我想将现有迁移合并为一个时,我才会从每个应用程序中删除所有迁移。

    在我的情况下,migrations 文件夹是一个符号链接,所以我使用以下脚本:

    #!/bin/bash
    for dir in $(find -L -name "migrations")
    do
      rm -Rf $dir/*
    done
    

    我删除并重新创建数据库:

    例如,一个 bash 脚本可以包含以下命令:

    su -l postgres -c "PGPASSWORD=$password psql -c 'drop database $database ;'"
    su -l postgres -c "createdb --owner $username $database"
    su -l postgres -c "PGPASSWORD=$password psql $database -U $username -c 'CREATE EXTENSION $extension ;'"
    

    我从转储中恢复数据库:

    pg_restore -Fc -U $username -d $database path/to/backup-dir/db.dump
    

    如果迁移在第 3 步中被删除,我会通过以下方式重新创建它们:

    ./manage.py makemigrations <app1> <app2> ... <appn>
    

    ...通过使用以下脚本:

    #!/bin/bash
    apps=()
    for app in $(find ./ -maxdepth 1 -type d ! -path "./<project-folder> ! -path "./.*" ! -path "./")
    do
      apps+=($app#??)
    done
    all_apps=$(printf "%s "  "$apps[@]")
    
    ./manage.py makemigrations $all_apps
    

    我使用虚假迁移进行迁移:

    ./manage.py migrate --fake
    

万一出现完全错误并且一切都是 ***,(确实会发生这种情况),我可以使用备份将所有内容恢复到之前的工作状态。如果我想使用第一步中的db.json 文件,如下所示:

当 pg_dump 或 pg_restore 失败时

我执行以下步骤:

3(删除迁移) 4(删除并重新创建数据库) 6 (makemigrations)

然后:

应用迁移:

./manage.py migrate

从 db.json 加载数据:

./manage.py loaddata path/to/db.json

然后我试图找出为什么我之前的努力没有成功。

成功执行这些步骤后,我将项目复制到服务器并对该框执行相同的操作。

这样,我始终保持最少的迁移次数,并且我可以将pg_dumppg_restore 用于共享同一项目的任何盒子。

【讨论】:

首先,感谢您的完整解释!我想知道,如果有多个迁移,你会怎么做:a)安装 db b)migration1 c)dumpdb d)migration2。我认为你不能将你的转储数据库导入a),你必须先进行migration1。但是,如何防止系统进行第二次迁移? @JulienGreard 这是一种自相残杀但“舒缓”的方法,因为migrations 非常微妙,many times 无法自动复制。但是,想法是在应用所有迁移后,备份数据库,删除所有内容并重新安装。类似squahing 的东西在类固醇上......当项目已经部署时不是很有用,但是当你生气时很性感! 对不起,我不明白你的回答。如果我的备份不符合“原始”数据库(未应用迁移)并且不符合最新的数据库(应用了所有迁移),我不明白该怎么办。如果我的备份是在两次迁移之间进行的,我想我会被卡住。我必须先进行 N 次迁移,然后“加载数据”我的备份,然后再应用 M 次其他迁移。我不知道这种方法是如何告诉 Django 只应用前 N 个迁移。我不知道我是否让自己更清楚。告诉我这是否没有意义;-) @JulienGreard pg_restore 应该在反映数据库结构的代码上执行,就像执行pg_dump 时一样。 ./manage.py restore data 应该遇到一个空数据库,该数据库已经在反映数据库结构的代码上执行了./manage.py migrate,就像执行./manage.py dumpdata 时一样。但是,最好打开一个新问题,详细了解您所面临的情况。 为什么不在步骤 1 中使用--natural-foreign 标志?

以上是关于带有转储数据和迁移的 Django 备份策略的主要内容,如果未能解决你的问题,请参考以下文章

使用云祺虚拟机备份软件快速备份VMware vSphere虚拟机

hbase表数据备份策略

带有创建模式的 Mysql 备份

RMAN备份保留策略

使用虚拟机备份软件恢复VMware vSphere虚拟机

请教免费的esxi怎么备份虚拟机