2014年6月2日月曜日

壊れたZFSホームディレクトリを復旧する

Open ZFS on OS Xの1.2.7がリリースされました
おいおいちゃんとテストしてんのかよってツッコミたくなるような間隔でRCが乱発されていたので(ここらへん見るととってもヤバイ感じです)、ちょっと尻込みもしましたがまあ別に1.2.0もさして安定してないし入れてみました。

アプデ内容としては、1.2.0で全然使ってなかったメモリをちゃんと使うようになったのが大きいんじゃないかと思います。特に超遅かったzvolやzpool scrubに効果がありそう。「ありそう」なのはまだ試せてないからです。まだ社会人の生活リズムに慣れてないもんで時間が・・・


わかりやすいところだと、snapshotがマウントできるようになりました。1.2.0まではマウントができなかったため、snapshotにアクセスするためには一時的にzfs cloneしてからcloneファイルシステムをマウントし、使い終わったらcloneファイルシステムをdestroy、という煩雑な作業が必要でした。zfs mountだけでマウントできるようになったので、TimeMachine的な使い方がしやすくなりました。

で、今回はそのZFS snapshotを利用したTimeMachineごっこの話。

現在、メインの環境ではnetatalk+TimeMachineの環境を放棄し自家製snapshot+send+recv+launchdスクリプトによってバックアップシステムを運用しています。

そして、このスクリプトをホームディレクトリにも適用するために前回書いたようにホームディレクトリのZFS化を行っているのですが、これが時たま壊れます(例のZFSマウント前にホームディレクトリが自動生成されて混ざるというアレ)。具体的には10.9.3にアプデしたあたりとか。

ちょくちょくそういうことがあるので定期snapshotは必須です。snapshotをホームディレクトリ(SSD上)に溜め続けると容量を圧迫するので、1時間毎に差分snapshotをHDDのプールにsendして最新snapshotだけ残す、という運用を行っています。
更に純正TimeMachineと同じく1時間間隔で過去24時間、1日間隔で過去1ヶ月、1ヶ月間隔で過去1年・・・とバックアップするようになっていますがそこらへんの仕組みは本題ではないので別の機会に。ってこの前「別の機会に」と書いてから1年半経ってるんだけどね。

ということでSSD側に残っているのは過去1時間のsnapshotだけなので、「あ、ホームディレクトリ壊れた」となったら(Dockアイコンがデフォルトになったり起動項目が消えたりするのでわかる)、すぐにrollbackする必要があります(前回書いた手順)。

しかし今回はミスりました。ログイン画面で放置して風呂に入ってる間に定期snapshotが炸裂したのでSSD上に壊れる前のsnapshotが残っていません。ということでバックアップ先のHDDから復旧する必要があります。

まず状況はこんな感じ。
# zfs list -t snap -o name,mountpoint
NAME                                MOUNTPOINT
略
r1pool/Users/b00t@2014-0531      none
r1pool/Users/b00t@2014-0601-23   none
r1pool/Users/b00t@2014-0602-00   none
r1pool/Users/b00t@2014-0602-20   none
ssd/Users/b00t@2014-0602-20      /Users/b00t/.zfs/snapshot/2014-0602-20
ssdがホームディレクトリのあるプール、r1poolがバックアップ先のHDDです。@2014-0602-20の時点では既に壊れているので、@2014-0602-00を復元したい、ということになります(@2014-0602-01〜19が無いのは単にPCの電源が入ってなかったから)。

しかし、ZFSでは過去との逆差分?をsendすることはできません。つまり、差分転送先により新しいデータを送ることはできても古いデータを渡すことはできません。ということで最終的にはssd/Users/b00tは破棄してr1pool/Users/b00t@2014-0602-00をベースに作り直す、ということになります。

ただ、そもそもr1pool/Users/b00t@2014-0602-00が壊れる前なのかと、@2014-0602-20までの間に更新があったファイルが無いか調べる必要があります。ホームディレクトリがちゃんと機能しているかをファイルを見るだけで判断するのは難しいので、一旦r1pool/Users/b00t@2014-0602-00からのログインを試みます。しかし、リードオンリーのsnapshotではログインできないのでまずクローンを作ります(以下主に作業用アカウントを使用)。
# zpool import -N -a

# zfs set mountpoint=none ssd/Users/b00t
# zfs rename ssd/Users/b00t ssd/Users/b00t_old

# zfs clone r1pool/Users/b00t@2014-0602-00 r1pool/Users/b00t_2014-0602-00
# zfs set mountpoint=/Users/b00t r1pool/Users/b00t_2014-0602-00
# zfs mount -a
ここでは、-Nオプションを使ってimportすることでマウントせずにインポートしています(自動インポートスクリプトは停止済)。

これでb00tでログインするとクローンが使ってログインができるので、設定が壊れていないか確認し、古いファイルが無いか確認します(今回は実際にあったのでその場で/Users/b00t/.zfs/snapshot/2014-0602-20から回収した)。

確認が終わったので念のため再起動した上で再度作業用アカウントにログインし掃除。
# zpool import -N -a
# zfs destroy r1pool/Users/b00t_2014-0602-00
そしてようやくsnapshotをsendし、マウントポイントを設定します。
# zfs send r1pool/Users/b00t@2014-0602-00 | zfs recv ssd/Users/b00t
# zfs set mountpoint=/Users/b00t ssd/Users/b00t
# zfs mount -a
ログインできることを確認したら壊れたsnapshotと古いホームディレクトリを削除します。
# zfs destroy r1pool/Users/b00t@2014-0602-20
# zfs destroy ssd/Users/b00t_old@2014-0602-20
# zfs destroy ssd/Users/b00t_old
とまあこんな感じで復旧できました。ら、楽勝ですね。

ちなみに、自分の環境ではssd/Users/b00tの下に一時ファイル置き場としてtempというバックアップを行わないファイルシステムを置いていたので、ssd/Users/b00t_oldの削除前にclone+promoteで以下のように移管しました。
# zfs set mountpoint=none ssd/Users/b00t_old/temp

# zfs snapshot ssd/Users/b00t_old/temp@temp
# zfs clone ssd/Users/b00t_old/temp@temp ssd/Users/b00t/temp
# zfs set mountpoint=/Users/b00t/Desktoptemp ssd/Users/b00t/temp

# zfs promote ssd/Users/b00t/temp
# zfs destroy ssd/Users/b00t_old/temp
# zfs destroy ssd/Users/b00t/temp@temp
clone+promoteはプール内におけるファイルシステム階層の入れ替えに使えるのでとても便利です。

今回は特に用意したネタとかではなく、実際に起こったトラブルに対してsnapshot・clone・send・receive・promoteとZFSの機能をフルに使って対処することになったので良い備忘録になるかなと思って書いてみました。
こんなトラブルも解決できるZFSって凄いですね!って、ZFS使ってなけりゃ無縁だったわけだけど・・・トホホ

0 件のコメント:

コメントを投稿