災害時の備えとして、自宅NASのデータをすべてS3 Glacier Deep Archiveにバックアップしておく
自宅のNASなどにテラバイト級のデータを保有している場合、そのバックアップ先はなかなかに悩ましいものです。
RAIDで十分と考える人もいるかもしれませんが、肝心のバックアップデータが自宅内に置いてあるなら、地震などの災害で家ごと潰れてしまえば何の意味もないですし、それどころか最悪データを失うことが心の引っかかりになって逃げ遅れてしまう恐れすらあるので、クラウドバックアップは必須だと思っています。
お金が無限にあればDropboxやGoogleドライブのようなフルマネージドなクラウドストレージに同期しておけばよいのですが、数テラバイトにもなると毎月まあまあの金額になってしまいますし、あくまで非常時用のバックアップであってデータの読み書きはほとんどしない想定なので、DropboxやGoogleドライブはオーバースペックでもったいないと思ってしまいます。
そこで自分は日次バッチで S3 Glacier Deep Archive に保存しています。8TBぐらいのデータをバックアップしていますが、毎月500円ぐらいの費用で済んでいます。
というわけでそのやり方をメモがてら残しておきます。
ちなみにこの記事を書いたあとで知ったのですが ディザスタリカバリ という言葉があるようです。
1. S3バケットを作る
普通に非公開のS3バケットを作ってください。
その際、最も単価の安いus-east-2(オハイオ)かus-west-2(オレゴン)を選ぶようにしましょう。
2. cronでaws s3 syncを実行
crontabなどに以下のようなコマンドを設定します。
0 1 * * * aws s3 sync /path/to/nas s3://{バケット名}/ --delete --storage-class DEEP_ARCHIVE
これで、日次でNASのデータ全体をS3バケットにGlacier Deep Archiveストレージクラスを使用してバックアップすることができます。
s3 sync
コマンドは特にオプションをつけなくても下層ディレクトリを再帰的に辿ってくれます。
--delete
オプションは、同期元(NAS)になくて同期先(S3)にあるファイルを同期先(S3)から削除するためのものです。安全策をとりたい場合はこのオプションはつけなくてもよいかもしれません。
以上。簡単ですね👌
ちなみに、僕が実際に設定しているcrontabレコードは以下の内容です。
0 1 * * * /opt/homebrew/bin/flock -n /tmp/s3sync.lock /bin/bash -c 'if ls /Volumes/data >/dev/null 2>&1; then if ls /Volumes/data/** >/dev/null 2>&1; then start_time=$(date); /opt/homebrew/bin/aws s3 sync /Volumes/data s3://ttskch-synology-nas-backup/ --delete --storage-class DEEP_ARCHIVE; end_time=$(date); echo "$start_time: Executed - Ended at $end_time" >> ~/crontab.log; else echo "$(date): Skipped - No files found" >> ~/crontab.log; fi; else echo "$(date): Error - Source directory not accessible" >> ~/crontab.log; fi' || echo "$(date): Skipped - Another sync is running" >> ~/crontab.log
運用している中で、s3 sync
コマンドの --delete
オプションのせいで 同期先のS3バケットが空になってしまう という現象が何度か発生し、AIチャットと相談した結果、
- NASの接続が切れてマウントされていない状態で実行されるとマズいのかも?
-
s3 sync
コマンドが重複して起動されてしまうとマズいのかも?
あたりが原因として考えられたため、対症療法としてその辺りをガードするif文を追加し、実行結果を ~/crontab.log
に記録するようにしてあります。この内容にしてからは、今のところ同様の問題は再発していません。
3. Macの場合はcronジョブ実行直前に自動でスリープ解除させる
これはMacの場合のみ必要な対応です。
スリープ中はcronジョブが実行されないので、深夜にcronジョブを仕込む場合は、その直前にスリープが自動で解除されるようにスケジュールしておく必要があります。
具体的には、以下のようなコマンドを一度実行しておけば、毎日cronジョブの実行直前にスリープが解除されるようになります。(マシンを再起動しても有効です)
# 毎日の00:59:00にスリープ解除
sudo pmset repeat wake MTWRFSU 00:59:00
--storage-class DEEP_ARCHIVE
を付けずに aws s3 sync
を実行してしまった場合の対処方法
おまけ:間違えて これは僕の体験談ですが、メインのMacを買い替えたタイミングで、新しいマシンにcrontabを設定する際、間違えて aws s3 sync /path/to/nas s3://[バケット名]/ --delete
とストレージクラスを指定せずに設定してしまい、気づいたときにはS3バケット内の不特定複数のファイルだけがStandardストレージクラスに保存されている状態になってしまいました🙄
このときの対処内容も備忘録としてメモしておきます。
# バケット内の全ファイルの情報をダンプ(ファイル数が多いと数分程度かかる)
aws s3api list-objects-v2 --bucket {バケット名} > s3dump.json
# ストレージクラスがSTANDARDであるファイルのキーだけをリスト化
cat s3dump.json | jq '.Contents[] | select(.StorageClass == "STANDARD") | .Key' | tr -d '"' > keys.txt
# 当該ファイルのストレージクラスをDEEP_ARCHIVEに変更
cat keys.txt | xargs -I{} -S9999 aws s3 cp "s3://{バケット名}/{}" "s3://{バケット名}/{}" --storage-class DEEP_ARCHIVE
最後のコマンドで、xargs
に -S
オプションで大きめの数字を渡しているのは、一部ファイルがめちゃめちゃ深い階層にあってキーの文字数がデフォルトの上限を超えてしまい正常に xargs
に引数を渡せなくなる現象を回避するためです。(これに気づかず30分ぐらいハマりました…)
以上。お役に立てば嬉しいです。
参考
- AWSのS3 Glacierを使って写真のバックアップをしてみる - もつの雑記帳-日常ときどき探訪記-
- [新機能]S3で新しいストレージクラス Glacier Deep Archive が使えるようになりました | DevelopersIO
- AWS S3 sync の使い方 | Hakky Handbook
- S3 Glacier Deep Archive に写真を格安で保存しよう!(アップロード編) - Qiita
- AWS CLIからS3ストレージクラスを操作する | DevelopersIO
- list-objects-v2 — AWS CLI 1.27.151 Command Reference
#examples
- Macを自動起動してcronを実行する | mktia's note
Discussion