障害でデータロストした話

これは[さくらインターネット（その２） Advent Calendar 2016](http://qiita.com/advent-calendar/2016/sakura2)の25日目の記事です。
さくらさんのtwitterアカウントが「Advent Calendarがあと1日だけ余っているから誰か書かない？(意訳)」とツイートしているのが目に入って「折角だから書いてみようかな」というのが動機なのですが、まさかの最終日が空いているとは思わず、しかも話す内容がちょっとDis風味で申し訳ないです。

## 契約しているサーバ

* さくらのVPSの1Gプランを契約
* 主な用途としてはメールサーバ、(権威)DNS、個人で契約している各サーバのアカウント情報の管理(これ重要)

## 2016年11月24日

夜、契約しているVPSにつながらなくなったことに気付く。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">あれ、さくらのVPSなにか起こってる？接続が切れてつながらなくなったん…。</p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/801778206026014722">2016年11月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

この時は回線障害を疑って「1時間もすれば復旧するんじゃないかな」と思って放置プレイしようかなーと思いつつ、twitterで検索すると同じようにさくらのVPS借りている人が「ディスクエラー吐いて死んでる」というツイートをしていて少し焦りはじめる。

「と、とりあえずさくらのVPSのコンパネに入ってコンソール見てみよう。あーでももう1年くらいログインしてないしアカウント情報覚えてないや。アカウント情報管理しているサーバに入って確認しよ…あ、そのサーバが落ちてる＼(^o^)／」

という状況に陥り、さくらのVPSのコンパネに入るにはサーバの復旧を待たないといけないというデッドロックを発生させる。ただ、さくらのVPSのアカウントについては古くから契約しているサーバだったこともあり、今のアカウント管理サーバを使い始める前のテキストファイルベースで管理していたファイルが手元にあったので無事にさくらのVPSのコンパネにログインできた。
そしてコンソールを確認するとうちのサーバも例にもれずディスクエラーの後、kernel panicで死んでいた。当時のkernel panicの画面キャプチャはこんな感じ。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">尚、うちのkernel panicはこんな感じ。 <a href="https://t.co/q9RjTrFPnI">pic.twitter.com/q9RjTrFPnI</a></p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/801782142166409216">2016年11月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

このまま放っておいても仕方ないので、コンパネから強制再起動かけてみると。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr">＼(^o^)／ <a href="https://t.co/E8nzenSNmd">pic.twitter.com/E8nzenSNmd</a></p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/801784075711197184">2016年11月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">さくらのVPSが起動しなーい(^q^)</p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/801784312181899264">2016年11月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

はい、起動すらできなくなりました。ここでもう自分ができる事は何もなくなりました。時を同じくしてさくらからも障害のアナウンスがでました。

* 障害発生のお知らせ<br />http://support.sakura.ad.jp/mainte/mainteentry.php?id=20700

今の上記URLは障害発生から復旧までが全て時系列で書かれています。

当時のリリースは「障害により意図しない再起動が発生した」との事で「再起動できないうちのサーバは問い合わせた方がいいかな」と思って、さくらに問い合わせを行う。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">しばらくチャレンジしても起動できそうになかったのでさくらへ問い合わせしてみた。まぁ明日のどこかで復活してくれればいいかな。<br>というわけでプライベートのメールサーバが死んでいますが、DNSは生きているので復活後の再送に期待しています。再送しないMTAは知ったことではない(強気)。</p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/801799252536008704">2016年11月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

夜に返事が来るとは思ってないので続きは明日かなと思っていたところ、障害アナウンスが更新されていた。

> 23時35分：ハードウェアの不具合が認められたため、ハードウェア交換を実施中です。

これは長くなりそうだな…と思った。

## 2016年11月25日

日をまたいで障害情報が更新されていた。

> 01時09分: ハードウェア交換の実施が完了いたしましたが、お客様のデータに不整合がございましたので、データの書き戻しを実施いたします。

今日は夜通し作業ですかね…担当者の方お疲れ様です(僕は寝ました)。僕が寝たその後も定期的に状況報告が行われていました。

> 05時20分: 現在も復旧作業を継続しております。
> 07時20分: 現在も復旧作業を継続しております。作業完了は本日午後を見込んでおります

夜も明けて昼間に入った頃、コンパネのステータスが変わっていることに気付く。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">お、さくらのVPSの管理画面みたらサーバのステータスが不明から停止中に変わってる。もしかして起動できるところまで復旧したのかな。<br>とりあえずは勝手に起動させずに様子をみようか…。</p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/801994244927811585">2016年11月25日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

もしかしてそのままサーバの起動をかけたら起動するかもしれないが、正式な復旧アナウンスなしで勝手に操作してまた問題を起こすのもいやなので、ここでは操作をせずにアナウンスを待つことに。その後、13時半ごろに勝手にサーバが起動してきた。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">さくらのVPS復活きたー。とりあえずログインしてみたところ、11/19あたりのデータに戻ってる??</p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/802007576720224256">2016年11月25日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

そして13時45分に最後の障害アナウンスの更新が行われる。

> 13時45分: お客様データの書き戻し及び、正常性の確認が取れましたので、以上をもって対応は完了いたしました。

障害アナウンスに「データの書き戻し」という表現があったのできっとバックアップから戻しているんだろうなと思っていた通り、サーバの状況を確認する限り11/19付近のデータに戻っているようだった。障害が発生したのが11/24なので約5日前のデータに戻っていることになる。

こうして僕は障害によりデータを5日分ロストしたのでした…。

## さくらのVPSのバックアップについて

と、ロストした話を延々と話しただけだと、何も得るものもないですしもう少し色々書いていきます。
今まで特に気にしてなかったのですがさくらのVPSのバックアップ体制について調べてみました。
Webサイト上のサービス案内には細かい事は書いてないので約款に当ってみました。さくらのVPSに関する約款はたぶんこの2つかな。

* 基本約款<br />https://www.sakura.ad.jp/agreement/[a]yakkan0_kihon.pdf
* さくらのVPSサービス約款<br />https://www.sakura.ad.jp/agreement/[a]yakkan2_vps.pdf

大雑把に書くと「バックアップは各自、自身の金を使ってバックアップしてね」という事でバックアップについては特に保証も何もしていないことが分かります。
なお、発生した障害に対してさくらに重過失がある場合は月の利用額を上限に賠償するとも書いています。そのため、障害によって何百万と損失を出したときに、もしさくらが過失を認めても賠償費用は月の支払いが上限という事ですね。ただ、これはどこのレンタルサーバ屋やクラウドサービス屋も同じように書いていると思います。
※正確な内容については約款をご覧ください。

というわけで約款に沿えばさくら側のバックアップは約款で明言して行っているわけではないけど、障害に備えてバックアップはとっているという事ですね。恐らくバックアップ体制について問い合わせても細かくは教えてくれないんじゃないかと思います(実際に問い合わせてはいません)。

個人的には各サーバ、週1くらいのペースでバックアップしているのでは？っと思っています。

## 自分でバックアップしよう

ここから本題です。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">とりあえず完全にサーバがお亡くなりになったとしても毎日バックアップを違う会社のVPSに投げているのでまぁそこから昨日の状態までは復元できるかな。<br>作業はちょいと面倒だけど。</p>&mdash; soushi@脱法エンジニア (@_so4) <a href="https://twitter.com/_so4/status/801792252947222528">2016年11月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

こんなツイートもしており実は独自に毎日バックアップしていました。さくらのVPSとは別に2社のサーバを使っており、相互にバックアップを取るようにしています。バックアップ先は同じさくらのVPS(の別リージョン)でもいいのですが、色々な会社のサービスを触ってみるのもいいかなとという事で複数社のサーバを借りています。

僕の場合はサーバ自体も自分で作っているので最悪「流動的に変化するデータが残っていればサーバが完全に死んでもなんとかなる」という事で次の内容を別のサーバに送っています。

* Webサーバのコンテンツ(サーバ構築時のメモをここに書いている)
* メールのスプール
* MySQLのデータ
* apache/MySQL/postfix/PHP等の設定ファイル
* 自分のhomeディレクトリ以下のファイル
* ログファイル(これは最悪なくてもいい)

さくらのVPSサーバをサーバA(srvA)、バックアップ送り先のサーバをサーバB(srvB)として次のような処理を行っています。

1. サーバAのMySQLのdumpを作成
2. サーバAからサーバBにssh接続(ポートフォワードによるrsyncデータ転送)
3. サーバAの必要なデータをサーバBに送る
4. サーバBの必要なデータをサーバAに送る
5. SSHを閉じる

### 前準備:srvBにrsyncサーバを立てる

rsyncサーバの立て方は長くなるので他のサイトを参考にしてください(なげやり)。設定ファイルな次の通りです。

```
#
# rsync config
#
hosts allow = 127.0.0.1
hosts deny = *
use chroot = yes
max connections = 2

[srvA]
    comment = srvA backup
    path = /usr/local/backup/srvA/
    uid = root
    gid = root
    read only = no

[srvB_home]
    comment = srvB Home
    path = /home/
    uid = root
    gid = root
    read only = no

[srvB_minecraft]
    comment = minecraft backup
    path = /PATH_TO/minecraft/
    uid = root
    gid = root
    read only = no

# …他にも色々
```

sshのポートフォワードを使うので「hosts allow」は127.0.0.1だけで十分です。srvAのバックアップの受け先と、srvB自身が送りたいバックアップの設定が入っています。

### 前準備:srvAからsrvBに対してssh接続できるようにする

パスフレーズを空にした秘密鍵/公開鍵を用意してsrvAのrootユーザからsrvBのhogeユーザにログインできるようにします(やっぱりなげやり)。

* srvAのrootユーザの~/.ssh/config

```
# for srvB
Host srvB
 User hoge
 Hostname srvB
 PreferredAuthentications publickey
 IdentityFile ~/.ssh/[srvAの秘密鍵のパス]
```

* srvBのhogeユーザの~/.ssh/authorized_keys

```
ssh-rsa [srvAの公開鍵の内容] root@srvA
```

ちなみにsrvBはrootユーザである必要はありません。

### srvAでMySQLバックアップ(dump)実行

前準備でとりあえずrsyncによるデータ転送ができるようになりました。
MySQLについてもdataディレクトリ配下をまるっとrsyncしてもいいのですが、データの整合性等が気になるので一度dumpしたものをrsyncで送るようにします。
その時に作ったスクリプトは次の通り。

```bash
#!/bin/sh
#
# backup database
#

tail=`/bin/date +"%a"`
/usr/local/mariadb/bin/mysqldump -u root -p --password='パスワード' --all-databases > /DBBACKUP_TO/dumpall_${tail}.sql
```

あ、使ってるDBはMySQLじゃなくてmariadbだった。まぁどちらでも大丈夫です。

やる気のない2行スクリプトですが、これをcronで毎日実行してあげると/DBBACKUP_TO/ディレクトリ配下に7世代のmariadb(MySQL)バックアップが作成されます。一週間前のバックアップは勝手に上書きされるので放置プレイでもディスクを食いつぶすこともありません。

### srvAでrsyncバックアップ実行

rsyncのスクリプトは次のような感じです。

```bash
#!/bin/sh
#
#  data sync to srvB
#

OPTION='-az --delete'

# Start port forward
/usr/bin/ssh -N -L 30873:127.0.0.1:873 srvB &

# wait
sleep 5

# srvA -> srvB
/usr/bin/rsync $OPTION /etc/ rsync://127.0.0.1:30873/srvA/etc/
/usr/bin/rsync $OPTION /home/ rsync://127.0.0.1:30873/srvA/home/
/usr/bin/rsync $OPTION /usr/local/etc/ rsync://127.0.0.1:30873/srvA/usr_local_etc/
/usr/bin/rsync $OPTION /var/spool/cron/ rsync://127.0.0.1:30873/srvA/var_spool_cron/
/usr/bin/rsync $OPTION /var/www/ rsync://127.0.0.1:30873/srvA/var_www/
/usr/bin/rsync $OPTION /DBBACKUP_TO/ rsync://127.0.0.1:30873/srvA/db_backup/

# srvB -> srvA
/usr/bin/rsync $OPTION rsync://127.0.0.1:30873/srvB_minecraft/ /BACKUP_srvB/minecraft/
/usr/bin/rsync $OPTION rsync://127.0.0.1:30873/srvB_home/ /BACKUP_srvB/home/
# …他にも色々

# End port forward
kill %1
```

実際に使っているのを少しシンプルにしています(srvBでマインクラフトサーバを動かしていて、srvAに送った後に更に世代管理なんかもしています)。

動作としてはsrvAからsrvBにssh接続をした際にポートフォワードを行い、30873/TCPからsrvBのrsyncにつながるようにしています。そこから必要なデータをrsyncで同期した後にssh接続を切断しています。

なお、わざわざssh接続を使っているのは単なるrsyncデーモンの接続だと暗号化せずに送られてしまうからです。送られるデータの中には先述したように僕のさくらのVPSのコンパネパスワードとかもあるので。。。

あとrsync自体にもsshを使って送る方法もありますが、rsyncデーモンを使わないタイプになるので今回は採用していません。

というわけでこれを毎日1回実行させてさくらのVPSにあるデータを別のサーバ送っています。

### リストアと注意点

実際にリストアを行いたい時はrsyncコマンドを反対にして実行すればOKです。不安な場合は事前にテストしてリストア用のスクリプトファイルを用意しておいた方がいいかもしれません。

また、障害を起こしていたsrvAが復活した時にそのまま放置プレイすると次のcron実行により古いデータで上書きされてしまいます。その時はsrvAの障害後に慌てずsrvBのrsyncを止めておけば上書きされる事故を防げます。

## 結論

__バックアップは自分でしっかりとっておこう。障害時の保証はそこまで手厚くないぞ。__

自分でバックアップまで面倒みたくない場合はバックアップまでしっかりやってくれるフルマネージド系のサービスを契約しましょう。お高いですが、値段相応に色々やってくれます。

逆にこの低価格帯でサービスを提供していくれているという事は、その分自分でやらなければならない運用があるという事ですね。フルマネージド系のサービスとVPSの価格やサービス内容を比較すると色々見えてくるものがあるかもしれません。

なお、僕が遭遇した障害についてはさくらさんが11/19にまで復旧してくれて、独自のバックアップで12/23までは復活させました。12/24のデータは完全にロストしましたが、そこまでフォローしたい場合は自身のバックアップ方式を更に見直す必要がありますね。同期間隔を1日数回にするだけでもいいかも…ただ個人環境ではsrvBでマイクラサーバを動かしている関係上、あんまり負荷をかけたくないという事もありまして、特に同期間隔を短くすることは考えていません。

最後にさくらのVPSはお手軽でもう長年便利に使わせていただいておりまして(今のサーバがVPS3代目)、今後も解約するつもりなく末永く使っていこうと思っていますのでこれからもどうぞよろしくお願いします。
バックアップは自分でしっかり取ります。でもさくらさんでも今後も取ってくれてると嬉しいですw