站点图标 茶栗栗屋

究极个人备份方案 – 基于 restic 与 rclone

不要等到亡了羊再来补牢。

你会学到什么

我好像不太懂

作为南京大学 IT 侠的组员,笔者近期接触的案例中有数个数据丢失的案例。有将所有照片放在 U 盘被一波带走的,有误删用户根目录而无法找回的(SSD 的 TRIM 机制使得找回误删文件几乎不可能!),有硬盘直接坏掉的,有误操作在格盘前把数据放到内存盘,重启发现全没了的。

这些案例之所以造成了严重后果,都有一个共同的原因:数据备份的缺失。保护数据免受丢失的唯一方案就是备份。对于数据备份,我们应该遵守一些原则性的东西,比如业界较主流的3-2-1备份模式。

3-2-1模式与其实践

3-2-1模式就是指:

这种模式看上去很高端,不是什么个人用户可以达到的,但事实绝非如此。考虑这样的一种配置:一份存电脑里,一份放移动硬盘,还用OneDrive之类的同步一份到云上。这样就是最基本的一种对3-2-1的实践——可以解决大部分的问题。实际上,若您的数据主要是照片、文档等较“简单”的文件,上面的配置是很合适的。对于南大的同学而言,您可以用学校的OneDrive实现大容量存储。

我还建议您将您的重要数据集中存储 ——不要先急着开喷,这里的集中指的是「在您的电脑上,不要把数据东一个文件夹,西一个文件夹地到处放,而应该集中整理到一些文件夹中,且这样的文件夹不要放杂七杂八的东西」。这样做的好处在于方便进行备份、恢复。在帮数据不集中的同学备份C盘数据时我总是提心吊胆的——我不知道哪里有有用的东西,因为就连对方都不知道。

在做到了集中存储后,我们就可以:首先,买一个移动硬盘;其次,准备好您的云帐号(我用的是Office 365带的5T云盘,但您也可以用天翼云盘、百度云盘等,只要支持同步就OK)。您需要定期将新的数据拷到移动硬盘,而至于云,您可以下载用的云服务的同步客户端,再将客户端的同步目录中加上保存重要数据的目录,设置好开机自启即可。

进阶的备份

然而,如您的数据有点多(或复杂),或您想要增量备份、版本控制,或您是个我这样的nerdy的geek,抑或是您是我样的自动化狂魔,那让我们踏上更高一级的台阶吧。Meet restic and rclone。

restic是一个强大的增量备份工具,可以把本地的文件备份到本地的另一地方,或云端。rclone则是一个云存储的「通用客户端」,可以连上云盘进行同步、上传、下载等操作 。当我们通过自动化访问各种云盘时,用rclone是很方便的。

下文在教程中夹杂了我配这个的历程,大家看个乐就好。同时,这篇不是“手把手”的教程,您应该有一定的计算机基础。

当前情况

我们先看看我的个人数据是怎么放的。我所有的个人重要数据放在了C盘的用户目录下,如学校相关的(作业、文书、课件、表格等)在「文档」中,照片和收集的图在「图片」中,音乐库在「音乐」中,至于我的代码,是全部堆在用户目录的「source」目录中的。但我还有一些杂七杂八的东西,如Conan的本地缓存(这个比较重要,很多本地编译的东西,换个环境不一定能再弄出来)、SSH证书等(很重要!!),好在它们全在用户目录里。

用户目录中不用备份的东西就是QQ的所有文件(聊天记录有别的备份了)、「AppData」里的数据(特别混乱)。电脑中用户目录外的的其他数据多数都是网上能找到的资源(下的软件之类的),考虑的空间因素,不进行备份。

理想愿景

先看看我手头有什么:

  1. 4T的外接硬盘(最快,但大部分时间没接电脑上)
  2. 5T OneDrive个人帐号(已经用了很多了,比较乱)
  3. 5T OneDrive学校帐号(世纪互联,较快)
  4. 5T OneDrive E5 bp得来的帐号(在东京,较慢)
  5. 200G 南大网盘(很大,最快)

考虑过后,我的规划是,用 1. 作本地备份,在周末接上进行备份;用3.和4.作为异地备份,3天运行一次。

rclone 配置

连E5 OneDrive:轻而易举

我们的第一件事是让我们可以连上3.和4.两个云盘。两者都是OneDrive for Business协议的,而rclone包含其支持,用就完了。下载最新的rclone并放到可以被PATH找到的位置,再参照 https://rclone.org/onedrive/ 中的指示,我们先需要在E5的Azure AD域中建一个应用程序并分配正确的权限与密钥(如果看不懂官方教程,可以参考另一篇教程。需要的设置基本和该教程中的一样,区别是我们不会仅仅用 restic authorize "onedrive" 登录而不创建Remote,而是会完整地创建一个Remote)。然后在 restic config 命令中可以轻松建一个Remote,连上 E5 OneDrive。

注意,建议把Remote的名字取成一个“ID”应有的样子,如只用大小写字母、数字和下划线,不要写中文或空格。在这个过程中rclone会打开一个浏览器窗口,让您登录 E5 帐号。登录后就会自动找到您的OneDrive中的「Drive」(一般形如「https://组织名-my.sharepoint.com/personal/邮箱/Documents」 ),保存配置即可。

然而,在添加南大365的OneDrive时,我发现我的Office 365并没有创建应用程序的权限——这很正常,学校的AAD域怎么可能让用户随意建应用?

连南大OneDrive:困难重重

注:如果您没有在学校365上搭rclone的需求,也无兴趣看我的碎碎念,那可以跳过该段。

WebDAV:并不成功

rclone的官方教程和GitHub上的讨论中都谈了在权限严格的AAD域如何配置rclone,其中一个方法就是用SharePoint自带的WebDAV连接。把SharePoint的“经典OneDrive”界面的URL截掉最后的“Forms/All.aspx”就可以得到形如 https://组织名-my.sharepoint.com/personal/邮箱/Documents 的URL。参照 https://rclone.org/webdav/ 中的指示(注意对于SharePoint的WebDAV的特别配置)添加一个WebDAV格式的Remote,用自己的365邮箱和密码登录即可。

然而,南大的AAD的登录使用了第三方登录(南大的统一身份认证),这导致根本没有365密码这种东西。我试图参照其它的处理MFA多因素验证的方法,创建一个「应用密码」作为登录WebDAV的凭据。但我也没有在南大365上对应的位置找到设置应用密码的链接(Office Portal)。貌似南大的365也没有允许用户创建应用密码。

在不知道什么位置,我看到了有人说:SharePoint WebDAV可以用Cookies作验证,而IE登录后的Cookies和Windows的WebDAV客户端是互通的。于是我尝试了:

两种方法都以失败告终。我也没有找到好的支持自定义Cookies的WebDAV客户端。

与学校部门交涉:意外惊喜

同时,考虑到SharePoint的WebDAV实现有些缺陷(参考rclone WebDAV文档),我们最好还是用原生的rclone OneDrive协议进行连接。此时我不得不与南大的ITSC部门(不抱希望地)发E-Mail,希望可以允许我在南大Azure AD域上新建应用。对方在数个小时后回复了我——回复效率远远超出预料。但其称后台仅有全局开关,没法按应用配置。

我在自己的E5 AAD域上进行了一些测试,发现可以给用户一个“Application Developer”管理员角色,特定用户就可以创建应用。于是我,帮我新建并配置一个Azure AD应用,或给我Application Developer管理员权限。第二天ITSC的老师通过找M$的工程师,给我开了一个配置了rclone权限的应用,并给了我Client Secret——Client ID没给!!!!但好在虽然在网页上管理应用的权限被禁止了,我还是可以用Azure AD PowerShell列出AAD域上的所有应用程序,在其中找到rclone的Client ID。

然而,在连接的时候,报了这样的错误:

显然权限配置有问题。我又在自己的AAD域上进行一通测试,发现了:

因此我就回信指出这两点,ITSC的老师又转到微软,终于配好了权限,在rclone中成功登录了世纪互联的南大Office 365 OneDrive。在此也是很感谢南大ITSC的杨老师对我的大力支持,帮助我配置AAD域。

restic 与 autorestic

看完了rclone的配置,我们转到restic的配置上。restic是一个CLI工具,但缺了一些关键的功能,如定时备份,且其所有设置都要通过命令行参数给定,很不方便。autorestic是restic的一个「包装器」,通过自动调用restic的方法,加上了配置文件、定时执行(伪)等功能。在看下面的教程前,我推荐您先看看restic的官方Quick Start文档,了解一下其基本概念和常用命令。

简单地说,restic会把数据备份到称作「存储库」的地方,这个存储库就是一个有特定目录结构的一组文件,可以在本地也可以在云上。每次备份会创建一个「快照」,表示一个备份源的当前所有数据。随着时间推移,快照会越来越多,但快照间的数据是去重的,多个快照中的相同数据只会存一份,有效节约了空间。

我们先按restic的文档初始化好三个存储库,设置好密码(备份数据会用这个加密)。

遗憾的是,autorestic并没有官方的Windows支持,但这是个Golang编写的程序,而在其GitHub页面上,我看到了有位dalao在autorestic的构建脚本上加了Windows构建,且其称功能上,据其它用户称,除了install和upgrade命令没法用(这两个是用来安装和升级restic本体的),其它功能都能用,于是我就装了这个编译的版本。

autorestic还引入了一些不同的概念。「location」指一个备份源,而「backend」指一个 repository 的存储位置,以下配置中的locations和backends就反映了这一点。

autorestic是用YAML编写配置的,结合我在上文写的我的备份目标,我写了以下的autorestic配置。下面的配置大幅简化了(如没有考虑外接硬盘和云的备份频度不同),您可以参照autorestic的文档进行复杂的配置。


version: 2

locations:
  user_data:
    from: 'C:\Users\charlie'
    to:
      - external_hdd
      - onedrive_nju
      - onedrive_e5
    cron: '0 4 * * 0'    # 定时操作设置
    options:             # 这些都是传给 restic 的参数
      all:               # 这些会传给所有的 restic 命令
        tag: home
      forget:            # 会传给 restic forget 命令,下面的 backup 同理
        keep-last: 15    # 指定保留快照的策略
        keep-weekly: 4
        keep-monthly: 6
        keep-yearly: 2
      backup:
        use-fs-snapshot: true   # 在 Windows 上会用 Windows VSS 打一个临时的分区快照,这样不会受运行的进程占用、写入数据的影响
        exclude-caches: true    # 一些个人的排除选项
        exclude-larger-than: 2G
        exclude:
          - '*/AutoPCH'
          - '*/.vs'
          - '*/Tencent Files'
          - '*/AppData'
          - '*/NTDATA*'
          - '*/OneDrive'

backends:
  external_hdd:
    type: local                          # 本地的源,很直接
    path: 'E:\Backups\UserDirectory_Restic'
    key: ''                              # 您的源的密码,前面 restic init 时设置的,下同
  onedrive_e5:
    type: rclone
    path: 'onedrive_e5:/Backup_UserData' # 注意这里和手动跑 restic 不同,不需要写 rclone:onedrive_e5:/path/xxxxxxxxxxxx 了
    key: ''
  onedrive_nju:
    type: rclone
    path: 'onedrive_nju:/Backup_UserData'#这种写法的意思是,存在这个 OneDrive 空间的 Backup_UserData 文件夹下
    key: ''

放好后,我们可以执行 autorestic backup --config C:\您的autorestic配置文件路径 执行全面备份了。执行的结果大概长这样:

计划任务

autorestic 的定时运行不是直接配置好的,要我们通过计划任务的方式配置一个(唯一)的定时运行restic的任务。在Linux/macOS上当然是用cron或systemd解决,而在Windows上我们用Windows任务计划完成吧。以下的配置仅做参考,且必须配合您在autorestic的cron配置完成。

forget 与 prune

快照是会越积越多的,因此我们需要定期/不定期地执行 autorestic forget 命令根据我们的配置删除过期的快照,在执行的同时带上 --prune 参数可以一并删掉不再被用到的存储块。只有这些块被删掉,空间才真正被节约了!目前我没有配这个的定期执行,等空间告急了再手动跑吧(

可改进的地方

restic 的功能缺失和bug

restic有一个bug没有解决。在接rclone做后端的时候,restic是开一个子进程并用stdin/stdout管道和其进行HTTP通信。然而,如果在一个控制台窗口执行restic,restic在Windows上开子进程的时候,子进程会被挂到亲进程所在的控制台上。在这个控制台上发Ctrl+C会把SIGINT信号发到所有的挂接的进程上!rclone接到信号会马上退出,但restic在退出的时候不能马上退出,还要删除备份目标上的锁等。

问题就在于,此时rclone已经退出、stdio管道已经关了,restic的删除指令没法发送。restic会不断重试,把整个控制台卡住。因此我开了一个 PR,通过在开子进程时不挂接控制台解决这个问题:https://github.com/restic/restic/pull/3602。

同时,restic有一些我认为应该有而没有的功能,如压缩。但最重要的莫过于自定义数据包文件大小的选项

restic的备份方法是把文件拆成小片进行Hash,再把一堆小片打成一个个包传到云上,但默认的包大小是4M。这对本地备份还好,但对云端备份就是一个灾难——300G的数据至少要76800个文件!已经有人做了补丁加一个调这个数的选项(https://github.com/restic/restic/pull/2750)。但貌似这个数字和很多别的设计相关联,因此这个PR还没有被合并,短期也没有有进展的迹象。因此我是用的自己编译的一个、引入了这个补丁的restic在做本地的备份。我调到了32M,显示出了良好的性能提升。

rclone 的权限问题

前面说了,rclone的文档没有写到其请求了Sites.Read.All权限,我认为这是一个纰漏。该请求是在解决一个造成没法找到自定义SharePoint站点的存储库的时候增加的(https://github.com/rclone/rclone/issues/1770)。但这一增加 1) 没有在文档中提到;2) 对不用自定义SharePoint的用户而言是多余的。

因此我写了一个补丁,加了一个Remote配置项(disable_site_permission),使用户可以选择是否请求这个权限。我已经开了一个 PR ,待rclone方处理(https://github.com/rclone/rclone/pull/5883)。

南大 365 的权限问题

南大 365 目前是专门为我开了一个rclone应用,通过发Client Secret的方式让我可以连接。但这是不具备泛用性的,不可能为所有师生都搞一套Secret(实际上应该可以配置成一个Secret可用于所有人可用,当然有兴趣搞这个的估计也不多),乱发Client Secret 也不是特别安全(不过其实还好,Application只有OneDrive读写权限,且必须在有用户登录的前提进行)。因此,我们需要有一套自动化的分发Access Token的机制,让用户可以轻易地登录入南大的365 OneDrive。

然而,目前rclone的OAuth实现尚不完善,没有很好支持不使用Client Secret的鉴权方法,如「Interactive Provider」,见https://docs.microsoft.com/en-us/graph/sdks/choose-authentication-providers。考虑到目前rclone完全依赖OAuth框架进行鉴权,目前较易实现的就是基于现有OAuth方法进行的鉴权。我的构想如下:

首先,用户登录一个Web应用,应用后台通过Client ID/Secret进行请求,通过OAuth引导用户登录Office 365并同意应用权限。Web应用会得到一个Access Code,并用这个Code请求到相应的Access Token呈现给用户。用户将这个JSON形式的Access Token(连同Refresh Token)输入rclone完成登录。具体的实现有时间再考虑,同时给rclone加入Interactive Provider等更灵活的方法也值得考虑(需要写Golang 呜呜)。

autorestic 可以利用 restic 的copy

目前autorestic在处理单个源备份到多个储存库的情况时,是通过对同一个源多次执行backup命令,每次带不同的repository实现的,这对资源的消耗有些大,也不节约时间。

restic有个copy命令,可以把一个库的全部或部分(通过tag之类的筛选)快照传到另一库上(且不会传对方已经有的数据块)。因此我开了一个Issue,请求加上这个功能:https://github.com/cupcakearmy/autorestic/issues/145。

错误处理

当 restic 被强制结束

如果restic出了问题(如网络问题),造成其卡在那里一直运行,那Windows任务计划会在3d(我的配置)后把其强制结束。考虑到Windows上没有“优雅”地结束一个纯命令行程序的方法,这个基本就是直接结束进程了。那restic就来不及进行清理,造成:存储库上的锁没有释放;Windows VSS没有删除,这会造成VSS吃空间、降低性能,锁影响下次运行。

这个暂时没找到换掉Windows任务计划外的解决方法,可能要换用其它的定时执行方法了。

各位如果有好的数据备份经验,也欢迎和我交流。

退出移动版