炊きたてのご飯が食べたい

定時に帰れるっていいね。自宅勤務できるっていいね。子どもと炊きたてのご飯が食べられる。アクトインディでは積極的にエンジニアを募集中です。

バックアップ取得編 - Amazon EC2(AWS) Amazon LinuxでWordPress運用


f:id:t-namikata:20160130132405p:plain

以前、ファーストサーバーで、サーバー上のファイル一式と、DBの情報が全部消去される障害がありました。僕はその被害者の一人です。結局のところ、削除されたデータは復旧されず、幸い、記事データは手元に手動で取得していたDBのdumpファイルがあったらから良かったのですが、問題は各種設定ファイルや画像データでした。これらについてはバックアップがなかった為、CMSを一から構築し直し、画像をローカルからかき集めて対応するといった地獄の日々が続いたのです。

それ以降、バックアップの取得の大切さに気付き、万が一何か起きたときの復旧手順書を作成することにしています。

今回はAWSで運用しているWordPressサイトを対象に、現在行っているバックアップ方法について紹介したいと思います。

●前提条件 バックアップの考え方として、「サーバーがふっとんでも10分以内に復旧できること」です。1日1回、バックアップファイルを取得し、その時点に戻せればOK。1週間分、世代管理します。

復旧は、データベースのみの復旧。サーバー丸ごと復旧の2つのケースを想定しています

データベースのみの復旧

データベースを間違えて消してしまった。または、何らかの原因でデータベースがクラッシュした場合

●復旧用ファイルの準備 MySQLのdumpファイルを使用。WordPressのWP-DBManagerを使用して、データベースのdumpファイルを1日1回取得。

●復旧方法 dumpファイルからデータベースを復旧する(復旧時間およそ10分※dumpファイルの容量で前後します)

サーバー丸ごと復旧

  • WinSCPputtyssh接続していて、重要なファイルを誤って削除してしまった場合
  • WordPressのバージョンアップに失敗した場合
  • phpmysqlのアップデートなど、ミドルウェア関係の設定に失敗した場合
  • サーバーがふっとんだ場合

●復旧用ファイルの準備 AWSのスナップショットを使用。AWSAPIを使用して、スナップショットを1日1回取得し、1週間分保存

●復旧方法 スナップショットから新規にEBSボリューム(HDD)を作成し、ごそっと切り替える(復旧時間およそ10分※EBSが50GBの場合)

それでは、それぞれのケースについて説明したいと思います。

データベースのみの復旧

手順を簡単にまとめると下記です。

  1. WordPressプラグイン「WP-DBManager」を使用して、データベースのdumpファイルを1日1回取得
  2. WordPressの管理画面にログインできる場合は、管理画面よりデータベースの復旧を行う
  3. WordPressの管理画面にログインできない場合は、sshログインし、mysqlコマンドを実行してデータベースの復旧を行う

1.WordPressプラグイン「WP-DBManager」を使用して、データベースのdumpファイルを1日1回取得

【1】プラグインをインストール

dumpファイルの取得は、WordPressプラグイン「WP-DBManager」を使用します。WP-DBManagerは、dumpファイルを取得するだけでなく、同時にデータベースの最適化も行ってくれるので、こちらのプラグインを使用させてもらってます。

MySQLでは、NSERT、DELETEを繰り返していくと、ゴミがたまり(未使用領域が増えること)パフォーマンスが落ちていきます。この問題をオーバーヘッドといい、オーバーヘッドを解消するにはテーブルに最適化処理(OPTIMIZE TABLE)を行う必要がありますが、WP-DBManagerでデータベースの最適化を有効にすることで、オーバーヘッドの解消を自動的に行ってくれるようになります。 WordPressが調子悪い理由が分かった -> MySQLテーブルのオーバーヘッド 参考link http://www.tsunematsu.cc/2009/10/31/2635/

「WP-DBManager」 は公式プラグインとして登録されているので、管理画面で簡単にインストールできます。WordPressの管理画面にログインし、プラグインページより、[ 新規追加 ] → キーワードに「wp-dbmanager」と入力し、[ プラグインの検索 ] を実行してインストールします。

【2】プラグインの有効化

プラグインを有効化します。プラグインを有効化すると、下記のような警告文がでると思います。

f:id:t-namikata:20160130132424p:plain

wp-contentのフォルダにbackup-dbが自動的に作成されているので、wp-content/plugins/wp-dbmanagerにあるhtaccess.txtファイルをbackup-dbに移して、ファイル名を.htaccessに変更してねって話です。

.htaccessの中身は下記のように書かれており、backup-dbのファイルをインターネット経由で参照することを拒否しています。.htaccessがないとブラウザからsqlファイルを取得できてしまうので、設置後も削除することのないようにお願いします。

[plain] order allow,deny deny from all [/plain]

作業が完了して、プラグインページを閲覧すると、先ほどのエラーは消えていると思います。ナビゲーションにある、Databaseをクリックし、Backup DBを選択。画像のようになっていれば、設定完了です。

f:id:t-namikata:20160130132435p:plain

【3】手動によるバックアップファイルの取得

まずは、正常にバックアップファイルが取得できるか確認してみましょう。Databaseをクリックし、Backup DBを選択。画面下のBackupをクリックして、成功すればOKです。

f:id:t-namikata:20160130132444p:plain

Manage Backup Databaseをクリックし、ファイルが出来ているか確認します。作られたdumpファイルは、先ほど.htaccessファイルを移したbackup-dbに作成されます。あとはそれぞれの環境で設定を微調整します。

【4】プラグインの設定

DB Optionsを開き、下記画像のように設定します。

f:id:t-namikata:20160130132453p:plain

・Path To Backup: /var/www/html/wp-content/backup-db 定期的に実行されるバックアップファイルの保管場所

・Maximum Backup Files: 7 何世代分バックアップファイルを取得するか

・Automatic Backing Up Of DB: どの頻度でバックアップを取得するかを選択します。サーバーでgzip圧縮が有効になっている場合は、gzip圧縮を利用しましょう。ファイルの容量をぐっと減らすことができます。また、「E-mail backup to」にメールアドレスを入れると、バックアップファイルをメールで送信してくれます。※サーバー側で25ポート(smtp)を開いていない場合、メールが送信されず、サーバー内で滞留してしまいます。メールでの送信が必要でない場合は空にしてください。

・Automatic Optimizing Of DB: DBの最適化を行う間隔の設定。

・Automatic Repairing Of DB DBの修復を行う間隔の設定。

以上、各種設定を行えば、あとは自動的にバックアップ、最適化、修復を行ってくれるようになり、1日1回DBのバックアップが取得されることになります。

dumpファイルからデータベースを復旧する(復旧時間およそ10分※dumpファイルの容量で前後します)

復旧方法は、WordPressの管理画面にログインできるか、できないかで変わります

2.WordPressの管理画面にログインできる場合は、管理画面よりデータベースの復旧を行う

先ほどインストールした、WP-DBManagerのリストア機能を利用して復旧します。

  1. Manage Backup DBをクリックし、取得したバックアップファイルの中から、いつの時点に復旧するかを決め、Selectの欄にチェックを入れる
  2. Restoreを実行
  3. 英語で「リストアしてもOKですか?」のアラートが表示されるので、OKをクリック

f:id:t-namikata:20160130132501p:plain

以上で復旧が完了しました。サイトを見て、おかしい箇所がないか確認しましょう。

3.WordPressの管理画面にログインできない場合は、sshログインし、mysqlコマンドを実行してデータベースの復旧を行う

puttyを使ってサーバーにログインし、バックアップ用に取得したsqlを実行します。

※rootユーザーに切り替え
[ec2-user@ip-**-*-*-** backup-db]$ sudo su -
※復旧用のdumpファイルが置いてあるディレクトリに移動
[root@ip-**-*-*-** ~]# cd /var/www/html/wp-content/backup-db/
※最新ファイルを確認する
[root@ip-**-*-*-** backup-db]# ll
total 345492
-rw-r--r--. 1 apache apache  16044062 Dec 20 13:20 1356009627_-_******.sql.gz
-rw-r--r--. 1 apache apache  16058629 Dec 21 13:19 1356095933_-_******.sql.gz
-rw-r--r--. 1 apache apache  16062245 Jan  9 17:50 1357753845_-_ファイル名.sql.gz
※gzipの解凍
[root@ip-**-*-*-** backup-db]# gunzip ファイル名.sql.gz
[root@ip-**-*-*-** backup-db]# ll
total 534332
-rw-r--r--. 1 apache apache  16044062 Dec 20 13:20 1356009627_-******..sql.gz
-rw-r--r--. 1 apache apache  16058629 Dec 21 13:19 1356095933_-******..sql.gz
-rw-r--r--. 1 apache apache 209433754 Jan  9 17:50 ファイル名.sql
※復旧用のsql文の実行
[root@ip-**-*-*-** backup-db]# mysql -u ユーザー名 -p データベース名 < ファイル名.sql
Enter password:
[root@ip-**-*-*-** backup-db]# date
Mon Jan 21 04:36:03 EST 2013

これで復旧は完了です。サイトを見て、おかしい箇所がないか確認しましょう。以上で、MySQLのdumpファイルの取得~復旧までが出来るようになりました。

サーバーを復旧する必要がある場合

次は、もっとクリティカルな問題によって、サーバーを丸々復旧しないといけない場合の復旧方法について書きます。手順を簡単にまとめると下記です。

  1. AWSAPIを使用する為の事前準備
  2. スナップショットを取得するシェルスクリプトを作成し、cronで1日1回実行する
  3. 取得したスナップショットから、EBSボリュームを作成し、復旧するサーバーのEBSボリュームと差し替える

1.AWSAPIを使用する為の事前準備

スナップショットの料金の概算は下記になります。 ●EBSボリューム ・アジアパシフィック(東京) ・50GB ●料金 50(GB) * 0.10($/GB*月) = 5($/月) = 400(円/月) ※1$=80円で計算 7世代管理するので 400*7 = 2800(円/月) ※実際にバックアップを取り出して1ヶ月が経ちましたが、スナップショットの料金は7世代分で合計$3/月でした。なぜこんなに安いのか…。よく分かりませんが、上の計算は間違っているかもしれません。 詳細は、「Amazon Elastic Block Store(EBS)」のサイトを確認してください。 参考link http://aws.amazon.com/jp/ebs/

AWSAPIを使用する為には、下記3点が必要です。シェルスクリプトを作成する前に、事前準備として各種設定を行います。

api-toolsのインストール確認

AWSAPIを使用する為に、api-toolsを設置します。OSでAmazon Linuxを選択した場合はデフォルトでインストールされていますが、Red hat等を選択した場合はインストールする必要があります。まずは、インストール済みかどうかを確認しましょう。下記コマンドを実行して、ヘルプが表示されれば、インストールが完了しています。表示される場合は以降の手順はスキップしてください。

[root@ip-**-*-*-*** ~]# ec2-describe-regions -h

何も表示されなければ、ec2-api-toolsをインストールします。http://aws.amazon.com/developertools/351  にアクセスし、Download the Amazon EC2 API Toolsのリンク先をコピー。メモ帳かなんかに貼り付け、location以降のURLをコピーして、wgetを実行します。

[root@ip-**-*-*-*** ~]# wget http://s3.amazonaws.com/ec2-downloads/ec2-api-tools.zip&token=A80325AA4DAB186C80828ED5138633E3F49160D9
[root@ip-**-*-*-*** ~]# unzip ec2-api-tools.zip
[root@ip-**-*-*-*** ~]# mv ec2-api-tools-1.6.6.0/ ec2-api-tools/

以上で設置が完了です。

javaの実行環境

実行にはjavaが必要なのでjavaがインストールされているか確認。javaがインストールされていない場合は、インストールしてください。

[root@ip-**-*-*-*** ~]# java -version

AWS秘密鍵と証明書ファイル

すでに、AWS秘密鍵(pk-.pem)と証明書ファイル(cert-.pem)を取得済みの方はスキップしてください。ない場合は、AWSの管理画面から「X.509証明書」と秘密鍵をダウンロードします。

f:id:t-namikata:20160130132513p:plain

[ My Account ] → [ セキュリティ証明書 ] → 「X.509証明書」のタブを選択して「新しい証明書を作成する」をクリックして証明書を作成します。作成が完了すると、証明書のダウンロード画面が開きます。

X.509証明書、秘密鍵。この2つは必ずセットで使用します。画面を閉じると、秘密鍵はもうダウンロードできなくなります。表示されたダウンロード画面を閉じることなく、両方ともダウンロードしてください。ダウンロードしたファイルは大切に保存し、なくさないようにしてください。

もし失敗した場合は、「無効にする」を実行して、証明書使えなくしてから、もう一度新しい証明書を作成します。

AWSアクセス証明書の取得(EC2) 参考link http://koujinogaku.wiki.fc2.com/wiki/AWS%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E5%8F%96%E5%BE%97(EC2)

これで準備が整いました。あとは、スナップショットを作成するシェルスクリプトを準備し、cronで実行するだけです。

2.スナップショットを取得するシェルスクリプトを作成し、cronで1日1回実行する

AWSAPIを利用したシェルスクリプトを作成します。

【1】複製したいEBSボリュームのVolume IDをメモ

[ AWS Management Console ] → [ EC2 ] → 「ELASTIC BLOCK STORE」の「Volumes」をクリック。表示されているVolume ID(vol-12ab34cd)をメモします。

f:id:t-namikata:20160130132524p:plain

【2】JAVA_HOMEへのパスを確認

[root@ip-**-*-*-*** ~]$ echo $JAVA_HOME
/usr/lib/jvm/jre

【3】EC2_HOMEの確認

[root@ip-**-*-*-*** ~]$ echo $EC2_HOME
/opt/aws/apitools/ec2

手動でインストールした場合は、ec2-api-toolsを設置したディレクトリがパスになります(今回の例では/root/ec2-api-tools)

【4】秘密鍵とX.509証明書ファイルを置くフォルダの作成

[root@ip-**-*-*-*** ~]# mkdir .aws
[root@ip-**-*-*-*** ~]# chmod 700 .aws

apiの実行には、秘密鍵とX.509証明書ファイルが必要な為、先ほどダウンロードした秘密鍵とX.509証明書ファイルを、WinSCPなどを利用して、rootユーザーでログインし、作成した.awsフォルダにアップロードする。

【5】シェルスクリプトの作成

[root@ip-**-*-*-*** ~]# vi ec2_create_snapshot
#!/bin/sh
export JAVA_HOME=/usr/lib/jvm/jre #【2】で確認したJAVA_HOMEへのパス
export EC2_HOME=/opt/aws/apitools/ec2 #【3】で確認したEC2_HOMEへのパス。自分で配置した場合は/root/ec2-api-tools
export PATH=${PATH}:/bin:/usr/bin:${EC2_HOME}/bin

AWS_PRIVATE_KEY=/root/.aws/pk-******.pem #【4】でアップロードしたX.509証明書ファイル
AWS_CERTIFICATE=/root/.aws/cert-******.pem #【4】でアップロードした秘密鍵
AWS_REGION=`curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/[a-z]$//'`

EBS_VOLUME_ID="vol-12ab34cd" #【1】でメモしたEBSのボリュームIDを入力

SNAPSHOT_DESCRIPTION="asobicocoro Daily Backup" #Snapshot欄に表示されるDescriptionのテキスト
SNAPSHOT_GENERATION=7 #何世代分管理するかを指定

ec2-create-snapshot --private-key ${AWS_PRIVATE_KEY} --cert ${AWS_CERTIFICATE} --region ${AWS_REGION} --description "${SNAPSHOT_DESCRIPTION}" ${EBS_VOLUME_ID}

SNAPSHOTS=`ec2-describe-snapshots --private-key ${AWS_PRIVATE_KEY} --cert ${AWS_CERTIFICATE} --region ${AWS_REGION} | grep ${EBS_VOLUME_ID} | grep "${SNAPSHOT_DESCRIPTION}" | sort -k5 -r | awk '{print $2}'`

COUNT=1
for SNAPSHOT in ${SNAPSHOTS}; do
  if [ ${COUNT} -gt ${SNAPSHOT_GENERATION} ]; then
    echo "deleting ${SNAPSHOT}";
    ec2-delete-snapshot --private-key ${AWS_PRIVATE_KEY} --cert ${AWS_CERTIFICATE} --region ${AWS_REGION} ${SNAPSHOT}
  fi
  COUNT=`expr ${COUNT} + 1`
done

【6】作成が終わったら、無事スナップショットが作成されるか確認します。

[root@ip-**-*-*-*** ~]# sh ec2_create_snapshot

AWSの管理画面にログインし、[ AWS Management Console ] → [ EC2 ] → 「ELASTIC BLOCK STORE」の「Snapshots」をクリックし、スナップショットが作成されているか確認します。

f:id:t-namikata:20160130132533p:plain

【7】無事、作成されることが確認できたら、シェルスクリプトを1日1回実行されるcron.dairyフォルダに入れ、実行権限を付与

[root@ip-**-*-*-*** ~]# mv ec2_create_snapshot /etc/cron.daily/
[root@ip-**-*-*-*** ~]# cd /etc/cron.daily/
[root@ip-**-*-*-*** cron.daily]# chmod 755 ec2_create_snapshot

以上で7世代分のスナップショットを自動的に取得するバックアップが設定されました。

復旧方法(スナップショットから新規にEBSボリュームを作成し、ごそっと切り替える ※復旧時間およそ10分)

【1】スナップショット欄を開き、asobicocoro Daily Backupの中で最新のファイルを確認する

f:id:t-namikata:20160130132542p:plain

復旧するスナップショットを右クリック → Create Volume Snapshot を選択

  • Volume Type:Standard
  • Size:50GB
  • Availability Zone:ap-northeast-1*(※復旧するインスタンスと同じZoneを指定)

Yes, Createで実行

【2】Volume IDのメモ

使用した「Snapshot ID(snap-*)」を控え、Volume欄を開き、検索し、作成日時を見て、作成されたEBS Volumeを見つけ、「Volume ID(vol-)」をメモ

【3】Instance欄を開き、復旧するインスタンスをStopする

【4】インスタンスに紐付けるEBSの変更

Stopされたのが確認できたら、紐づいているEBSVolumeをdetachします。「Volumes」をクリック。EBS(7GB)を選択し、「Volume ID(vol-*)」と「Attachmentに表示されている内容(i- (test):/dev/sda1)」をメモ

f:id:t-namikata:20160130132556p:plain

Detach Volumeをクリック Yes, Detachをクリック ※Detachは削除ではなく、インスタンスとの紐付けを外すだけです。DetachしたEBSはavailableといったステータスで残ります。

Detach後、【1】で作成したEBS VolumeをAttachする Attachする際、Deviceには、先ほどメモしたAttachmentのパスを入力する Device:/dev/sda1 を入れる

【5】停止していたインスタンスをStart 【6】サーバにログインし、mysqlapacheを起動 【7】サービスの確認 【8】経過監視後、インスタンスに元々紐づいていたEBS Volume(【4】でdetachしたEBSボリューム)を削除する

以上で、サーバーを丸ごとバックアップ~復旧まで完了しました。サイトを確認し、おかしい箇所がないか確認しましょう。

問題が起きない事が一番ですが、世の中何が起こるか分からないので、バックアップはきちんと取っておきましょう。