概要

Go 製のバックアップツール restic を試してみたのでメモ。

バックアップをレポジトリ単位で一元的に管理できる。主な機能としては

  • バックエンドに複数サービス対応
  • スナップショット作成
  • インクリメンタルバックアップ
  • バックアップ対象の暗号化

サポートされるバックエンド(プロトコル)

  • Local
  • SFTP
  • REST Server
  • Amazon S3
  • Minio Server
  • OpenStack Swift
  • Backblaze B2

今回は S3 バックエンドを設定する。

環境

  • CentOS Linux release 7.2.1511 (Core)
  • restic 0.6.1 (v0.6.1-18-ga9a2798)

restic インストール

$ git clone https://github.com/restic/restic
$ cd restic
$ go run build.go

作成されたバイナリを適当なパスに展開

バックエンドに Amazon S3 を使う

credential を環境変数に設定

$ export AWS_ACCESS_KEY_ID=AK***************
$ export AWS_SECRET_ACCESS_KEY=**************************************

レポジトリを初期化
※指定した名前で S3 にもバケットが自動で作成される

$ restic -r s3:s3.amazonaws.com/quickguard-restic-test init
enter password for new backend:
enter password again:
created restic backend 61b47afaeb at s3:s3.amazonaws.com/quickguard-restic-test

Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.

環境変数 RESTIC_REPOSITORY と RESTIC_PASSWORD にレポジトリとパスワードを設定しておくと、以後の入力を省略可能となる

$ export RESTIC_REPOSITORY=s3:s3.amazonaws.com/quickguard-restic-test
$ export RESTIC_PASSWORD=*************

スナップショット作成

$ restic backup /data/html
scan [/data/html]
scanned 280 directories, 3012 files in 0:00
[0:13] 100.00%  7.834 MiB/s  101.848 MiB / 101.848 MiB  3292 / 3292 items  0 errors  ETA 0:00
duration: 0:13, 7.73MiB/s
snapshot 8ef85219 saved

特定ファイル除外

$ restic backup /data/html --exclude=*.log --exclude-file=exclude

標準入力からのスナップショット作成

mysqldump のスナップショット作成

$ mysqldump -u root -x --all-databases | restic backup --stdin --stdin-filename mysqldump-all.sql
[0:04] 10.210 MiB  2.553 MiB/s
duration: 0:04, 2.18MiB/s
archived as dbadd447

確認

$ restic snapshots --host DB001
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
dbadd447  2017-06-06 15:15:39  DB001                   mysqldump-all.sql

スナップショット一覧取得

全スナップショット取得
※Date は backup を実行したマシンの localtime が表示される

$ restic snapshots
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
8ef85219  2017-06-06 11:53:29  WEB001                  /data/html
23dfb53f  2017-06-06 11:59:41  WEB001                  /data/html
dbadd447  2017-06-06 15:15:39  DB001                   mysqldump-all.sql
11df38e8  2017-06-06 04:01:42  WEB002                  /data/html

Host, Directory で filter も可能

$ restic snapshots --host WEB002
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
11df38e8  2017-06-06 04:01:42  WEB002                  /data/html

$ restic snapshots --path /data/html
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
8ef85219  2017-06-06 11:53:29  WEB001                  /data/html
23dfb53f  2017-06-06 11:59:41  WEB001                  /data/html
11df38e8  2017-06-06 04:01:42  WEB002                  /data/html

json output

$ restic snapshots --json | jq .
[
  {
    "time": "2017-06-06T11:53:29.754786574+09:00",
    "tree": "4cdbdd0ca17c112a54bbb3b318a52580c3036d22035e8b06e2092b16e99c72c3",
    "paths": [
      "/data/html"
    ],
    "hostname": "WEB001",
    "username": "root",
    "id": "8ef85219b0aabed43b95f8b863712df85be108f44ff560968d402cc243586729"
  },
  {
    "time": "2017-06-06T11:59:41.863158034+09:00",
    "parent": "8ef85219b0aabed43b95f8b863712df85be108f44ff560968d402cc243586729",
    "tree": "3362dd121c4b748032d62b71508458c7953dee353a187497271089c3c4db59fc",
    "paths": [
      "/data/html"
    ],
    "hostname": "WEB001",
    "username": "root",
    "id": "23dfb53faa3b6f0b20512f0b884e0185605877503fbbdbb033c7769ac1c35a83"
  },
  {
    "time": "2017-06-06T04:01:42.168333564Z",
    "tree": "5cf40d8d3955c940d28ecfaa38e8d509f042c7bc5696247b86e9a9c4ca925536",
    "paths": [
      "/data/html"
    ],
    "hostname": "WEB002",
    "username": "user",
    "uid": 501,
    "gid": 496,
    "id": "11df38e8822022df07bfd182ffc8bc3b17f81ba49f5029563f41096c632afe50"
  }
]

レポジトリをマウント

$ mkdir -p ~/mnt/restic
$ restic mount ~/mnt/restic

エラー発生

fusermount: exec: "fusermount": executable file not found in $PATH
unable to umount (maybe already umounted?): exec: "fusermount": executable file not found in $PATH

fusermount が必要らしいので以下インストール

$ sudo yum install -y fuse

再度マウント

$ restic mount ~/mnt/restic
Now serving the repository at ~/mnt/restic
Don't forget to umount after quitting!

スナップショット取得のタイミングのディレクトリが確認できる(ReadOnly)

$ ls ~/mnt/restic/
snapshots

$ ls ~/mnt/restic/snapshots/
2017-06-06T11:53:29+09:00  2017-06-06T11:59:41+09:00

アンマウント

$ fusermount -u ~/mnt/restic

スナップショットをリストア

全ファイルをリストア

$ restic restore 23dfb53f --target /tmp/restore
restoring <Snapshot 23dfb53f of [/data/html] at 2017-06-06 11:59:41.863158034 +0900 JST by user@WEB001> to /tmp/restore

遅すぎる。 111MB 程度のリストアに 15分 かかる。

real    15m44.892s
user    0m4.896s
sys     0m1.375s

特定ファイル(パス)のみリストアも出来ないっぽい。

スナップショット削除

$ restic forget 8ef85219

ロックされてるっぽい

repository is already locked by PID 10523 on WEB001 by root (UID 0, GID 0)
lock was created at 2017-06-06 13:11:49 (13m22.283550245s ago)
storage ID 6adf6afd
the `unlock` command can be used to remove stale locks

ロック解除

$ restic unlock 8ef85219
successfully removed locks

再度実行

$ restic forget 8ef85219
removed snapshot 8ef85219

データも削除する場合は prune を実行

$ restic prune
counting files in repo
building new index for repo
[0:10] 100.00%  129 / 129 packs
repository contains 129 packs (41196 blobs) with 587.506 MiB bytes
processed 41196 blobs: 0 duplicate blobs, 0B duplicate
load all snapshots
find data that is still in use for 2 snapshots
[35:47] 100.00%  2 / 2 snapshots
found 40946 of 41196 data blobs still in use, removing 250 blobs
will delete 0 packs and rewrite 19 packs, this frees 1.073 MiB
[2:29] 100.00%  19 / 19 packs rewritten
counting files in repo
[0:10] 100.00%  128 / 128 packs
finding old index files
saved new index as fd6b9098
remove 3 old index files
done

これも 40分 程度かかる。

ポリシーベースのスナップショットローテーション

forget に対して以下のポリシーが設定できる

  • --keep-last n never delete the n last (most recent) snapshots
  • --keep-hourly n for the last n hours in which a snapshot was made, keep only the last snapshot for each hour.
  • --keep-daily n for the last n days which have one or more snapshots, only keep the last one for that day.
  • --keep-weekly n for the last n weeks which have one or more snapshots, only keep the last one for that week.
  • --keep-monthly n for the last n months which have one or more snapshots, only keep the last one for that month.
  • --keep-yearly n for the last n years which have one or more snapshots, only keep the last one for that year.

最新のスナップショットを1個残して不要データ削除

$ restic forget --keep-last 1 --prune

結果

snapshots for host WEB002, paths: [/data/www]:

keep 1 snapshots:
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
11df38e8  2017-06-06 04:01:42  WEB002                    /data/html

snapshots for host WEB001, paths: [/data/html]:

keep 1 snapshots:
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
23dfb53f  2017-06-06 11:59:41  WEB001                  /data/html

レポジトリ内のファイル検索

レポジトリ内の index.php を検索

$ restic find index.php

結果

$ restic find index.php
enter password for repository:
Found matching entries in snapshot 23dfb53faa3b6f0b20512f0b884e0185605877503fbbdbb033c7769ac1c35a83
/html/index.php
...

実行時間

real    32m25.850s
user    0m7.464s
sys     0m0.540s

ローカルバックエンドで実行した場合は、S3 バックエンドでは 数十分かかっていた restore, find が3秒程度で結果が返ってきたため、S3 バックエンドのせいで諸々の動作がクソ重いと思われる。