Movable Type の MySQL データを復旧して痛感したバックアップの大切さ。
サーバが半死状態に陥ってしまったので、Movable Typeの運用を別サーバに移した。
その際、MySQLのダンプしてあったファイルからエントリーその他を復旧しようとしたのだが、なかなか梃子摺ったのでメモしておく。
まず、Movable Type4になってからは知らないが、Movable Type3.XまではMovable Typeの管理メニューにある「エントリーの書き出し」では十分なバックアップは出来ない。なぜなら、書き出し→読み込みを行うと記事のエントリーIDが変わってしまうし、そもそもカスタマイズしたテンプレートの内容などは書き出されない。。。
そもそも完全なバックアップではないと公式に謳われている機能なので、余程使わない方が良く、RDBS を使っているならそっちでバックアップをした方が良い(エントリーもタグもコメントもTBもカテゴリーもテンプレートも全部丸ごと取り出せますから)。
そこで、例えば MySQL で運用しているなら、以下のようなコマンドでデータベースを書き出せます。
[基本形(MySQL3.2Xの頃)] *1行です
[最近はコレ(MySQL5.X)] *1行です
--opt は、容量の大きいデータベースをダンプする際に有効なオプション。
--default-character-set=binary は、ダンプする際に文字コード変換を行わないオプション。
オイラの場合、MySQL3.2X あたりから使っていて、データベースの文字コードがEUC-JP(ujis)だったりする。それが、MySQL4.X だか MySQL5.X だかで UTF-8 がシステムのデフォルト運用になった。だから、MySQL5.Xでオプションなしでデータを書き出すとおせっかいにも EUC-JP のデータを UTF-8 に勝手に変換してくれて化ける。それは書き出された時点で化けてしまっているので、後でどうこうしようとしても遅いので要注意。その変換を明示的に止めるのが「--default-character-set=binary」。
もともと UTF-8 で運用してるなら問題ないでしょうが、EUC-JP運用の場合はカナリ気をつけないといけないと思う。
さて、
そんなわけで、話が前後しますが、MySQL3.2X : EUC-JP(ujis) でダンプした Movable Type のデータを MySQL5.X にリストアした手順。
まず、/etc/my.cnf(MySQLの設定ファイル) に以下のような文字コード設定を記述。
default-character-set=ujis
[mysqld]
default-character-set=ujis
character-set-server=ujis
init-connect=SET NAMES ujis
[mysql]
default-character-set=ujis
その他の設定は全て省略して文字コード関連だけ書いてます。
/etc/my.cnf を編集したら mysql を再起動します。
次は、もしかしたらこの手順は飛ばしていきなりリストアしても良いのかもしれませんが、オイラはリストアするデータベース(mt_db)を予め作成して、文字コード(ujis, ujis_japanese_ci)を明示しました。
Enter password:
mysql> create database mt_db;
mysql> ALTER DATABASE mt_db DEFAULT CHARACTER SET ujis COLLATE ujis_japanese_ci;
mysql> flush privileges;
しかるのちに、データをリストア。
以上で、なんとか文字化けせずにデータが復旧しました(もちろん、MTの運用コードはEUC-JP)。
ちなみに、データベースのダンプファイル自体の文字コード変換(EUC-JP(ujis)→UTF-8(utf8))にも挑戦しましたが、どうも上手くいかず、システム側をEUC-JPで統一するアプローチでなんとかやり遂げました。最終的に文字化けなしでデータを飲み込むまで、およそ3時間半。。。><
という風に、障害をきっかけにデータの復旧作業をしたわけですが、こういうことを経験すると、本当にバックアップって大事だなあと思います。
実は、MySQLのデータをダンプしてバックアップする作業を、オイラは思いついたときに手動で行うことしかしていませんでした。なので、今回、障害が発生したときに手元に残っていた最新のデータは23日も前のもの。。。
マジ半泣きでおよそ20のエントリーとテンプレート全て(たまたま最近編集していた)を手動で復旧せざるを得ませんでした。。。ああ、肩と手が痛い。。。なぜ、オイラはサーバで遊ぶ(実験する)前にバックアップを取らなかったのだろうか。。。
もう、悔やんでも悔やみきれない、アホがもたらした無駄な作業。。。
そんなわけで、Movable Type の MySQL データを定期的に自動バックアップする Perl スクリプトを組みました。
データは圧縮してバックアップ保存しつつ、それをメールに添付して送信する2重の安心設計です。
*CPANモジュールの Net::SMTP と Net::POP3、それから MIME::Entity が必要です。
*MySQLのパスワードが含まれるので、見られない場所に保存してください。
*定期的な実行(オイラは1日1回)には cron を使います(解説は省略)。
*保存されるファイル名は [ MTBackUpYYYYMMDD.tar.gz ] です(添付ファイルも同名)。
*POP before SMTP 用にPOP3接続してからSMTP接続するようになっています。
*細かいエラー処理などしてません。
*メールサブジェクトに日本語を使用しないでください。
*もろもろ、それぞれの環境に合わせて書き換えてください(当然、そのままコピペでは動きません)。
以下、コード。
use strict;
use Net::SMTP;
use Net::POP3;
use MIME::Entity;
# 年月日取得
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
$mon += 1;
if($mon < 10){ $mon = "0$mon"; }
if($mday < 10){ $mday = "0$mday"; }
# MySQLデータ作成と圧縮
system "mysqldump -a --opt --user=USER --password=MySQL_USER_PASSWORD --default-character-set=binary DATABASE_NAME > /EXPORT/PATH/TO/BACKUP_FILE.mysql";
system "tar -czPf /COMPRESS/FILEPATH/MTBackUp$year$mon$mday.tar.gz /EXPORT/PATH/TO/BACKUP_FILE.mysql";
system 'rm /EXPORT/PATH/TO/BACKUP_FILE.mysql';
# データ添付してメール送信
# POP before SMTP (自前のSMTPサーバがあるなら不要)
my $pop = Net::POP3->new('POP3.Server.com');
if ($pop->login('POP3Account', 'POP3Password') >= 0) {
$pop->quit;
}else{
die 'Can not connect POP3';
}
our $SENDER = 'hoge@example.com'; # 送り主
our $RECIPIENT = 'fuga@example.com'; # 受取り
our $SUBJECT = "MTBackUP$year$mon$mday"; # メールタイトル*日本語不可
our $ATTACHED_FILE_1 = "/COMPRESS/FILEPATH/MTBackUp$year$mon$mday.tar.gz"; # 添付ファイル
my $smtp=Net::SMTP->new('SMTP.Server.com',
HELLO=>'SMTP.Server.com');
# 以下、変更不要
$smtp->mail($SENDER);
$smtp->to ($RECIPIENT);
$smtp->data();
my $mime = MIME::Entity->build(
From => $SENDER ,
To => $RECIPIENT,
Subject => $SUBJECT ,
Data => ['']);
$mime->attach(
Path => $ATTACHED_FILE_1,
Type => 'application/x-tar',
Encoding => 'Base64'
);
$smtp->datasend($mime->stringify);
$smtp->dataend();
$smtp->quit;
tar する対象は複数いけるので、MySQL のダンプファイル以外もまとめて圧縮することができます。
メール送信部分は、以下のエントリーから頂きました。
モジュールを使ってメールを送信するには、以下のようにする。
