プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

【EC2】 自動スナップショットとローテーション

ソースコード管理をAWS上のSubversionでおこなってます(詳しくはこちらの記事)。今まで、リポジトリのバックアップはS3と自宅ローカルストレージへ取っているのですが、EC2インスタンスのバックアップは取っていませんでした。時間ができたので、EC2インスタンスのスナップショットを自動的に取る方法を実現してみました。

 

なお、次のサイトを参考にさせていただきました。

やってることは、これらのサイトで紹介していただいているものとほとんど変わりません。自分のメモ用にまとめました。

インスタンスは、Ubuntu12.04.1 (BitNami Redmine) です。

 

自動スナップショットを取る方法

EC2のAPIツールを使って実現します。私が書いたシェルスクリプトは次のようなものです。

 

/etc/ec2/ec2-snapshot.sh

#!/bin/bash
#
# auto snapshot of EC2 instance
#
# written by Junichi MORI, 2013/4/11

# variables
#   this script doesn't use --region option,
#   because uses default region defined by EC2_URL variable in EC2_ENV file
EC2_ENV=/etc/ec2/bash_ec2env
EBS_VOL=xxxxxxxxxxxx

# functions
function message() {
    echo `date +"%F %T %Z"` : $*
}
function usage() {
    echo "Usage: ec2-snapshot.sh  generation  description"
    echo "   generation : number of old backup, positive number(grater than 0)"
    echo "   description: description of snapshot"
}

# argement
if [ $# != 2 ]
then
    usage
    exit -1
fi
# argument #1 should be natural number
ISNUM=`expr "$1" : '^[1-9][0-9]*$'`
if [ ${ISNUM} -eq 0 ]
then
    usage
    exit -1
fi
SS_GENERATION=$1
SS_DESC=$2


# environment setting
if [ ! -f $EC2_ENV ]
then
    message "error: ec2 environment difinition file is missing"
    exit -1
fi
. $EC2_ENV

# auto snapshot
LOGMSG=`ec2-create-snapshot --private-key ${EC2_PRIVATE_KEY} --cert ${EC2_CERT} --description "${SS_DESC}" ${EBS_VOL}`
message "create: "${LOGMSG}

# list of snapshots
#   first, get snapshots list filtered by description and volume-id.
#   next, sort snapshots by issued timestamp (field #5) descending order.
#   last, get snapshot-ids list, i.e. get only field #2.
SNAPSHOTS=`ec2-describe-snapshots --private-key ${EC2_PRIVATE_KEY} --cert ${EC2_CERT} --owner self --filter description="${SS_DESC}" --filter volume-id=${EBS_VOL} | sort -k5 -r | cut -f 2`
#echo ${SNAPSHOTS}

# snapshot rotation
COUNT=1
for SS_ID in ${SNAPSHOTS}
do
    if [ ${COUNT} -gt ${SS_GENERATION} ]
    then
        LOGMSG=`ec2-delete-snapshot --private-key ${EC2_PRIVATE_KEY} --cert ${EC2_CERT} ${SS_ID}`
        message "delete: "${LOGMSG}
    fi
    COUNT=$((COUNT + 1))
done
message "auto snapshot done."

 

EC2のコマンドラインツールのセットアップについては、こちらの記事をご参考にしてください。コマンドラインツールに必要な環境のセットアップについてもこの記事に書いています。

 

やってる処理内容は参考サイトとほとんど同じ処理です。異なるのは、世代管理の世代数とdescriptionを引数で渡せるようにしたところです。

一応、処理の流れを書いておくと次のようになります。

  • 引数で指定されたdescriptionを与えてスナップショットを作成します。
  • 次に、世代管理をおこなうためスナップショット一覧を取得し、作成時刻の降順でソートして、スナップショットidをのリストを取ります。
  • これを時刻の新しいほうから数えて、世代数より多い分(古いスナップショット)は削除するというものです。

 

実際のバックアップでは、このスクリプト呼び出す形で、daily用とweekly用のスクリプトを作ります。

 

/etc/ec2/ec2-snapshot-daily.sh

 

#!/bin/bash
#
# auto snapshot of EC2 instance daily
#
# written by Junichi MORI, 2013/4/11

# variables
SS_GENERATION=6
SS_DESC="Daily Backup"
LOG=/var/log/ec2snapshot.log

/etc/ec2/ec2-snapshot.sh ${SS_GENERATION} "${SS_DESC}" >> ${LOG} 2>&1

/etc/ec2/ec2-snapshot-weekly.sh

#!/bin/bash
#
# auto snapshot of EC2 instance weekly
#
# written by Junichi MORI, 2013/4/11

# variables
SS_GENERATION=4
SS_DESC="Weekly Backup"
LOG=/var/log/ec2snapshot.log

/etc/ec2/ec2-snapshot.sh ${SS_GENERATION} "${SS_DESC}" >> ${LOG} 2>&1

それぞれのスクリプトへのシンボリックリンクを、/etc/cron.daily, /etc/cron.weekly から張ればあとは自動的に実行してくれます。

これで、スナップショットも自動で取れるようになりました。

 

スナップショットを別リージョンにコピーすることもできます(次の記事などが参考になります)が、それはまた必要性を考えてから試したいと思います。

2013/4/15追記

実際に、/etc/cron.daily、/etc/cron.weekly の各ディレクトリに上記スクリプトへのシンボリックリンクを張ってみたら、なぜかうまく動きません。不審に思って調べてみると、シンボリックリンクのファイル名が問題でした。

定期実行は /etc/crontab に書かれている下記コマンドで呼び出されています。

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

このとき、run-parts は指定されたディレクトリ内のコマンドを実行するのですが、コマンド名に使える文字が制限されています。要は ec2-snapshot-daily.sh のようにピリオドは使えませんでした。そこで、

 

cd /etc/cron.daily
ln -s ../ec2/ec2-snapshot-daily.sh ec2-snapshot-daily

 

のようにしてシンボリックリンクを張れば問題なく動きました。