この記事は公開から1年以上が経過しています。内容が古い場合があるのでご注意下さい。

EC2インスタンスのバックアップを日次で取得したいと思います。
今ならLambdaなどを使うことが多いと思いますが、今回は稼働しているインスタンス自身でスナップショットを取得する方法についてです。

aws cliのインストール

APIを利用する為、対象サーバにAWS CLIをインストールします。
参考:CentOSにAWS CLIをインストールする

IAM Roleの作成

IAMには、最低限の下記のRoleを設定します。
対象サーバ自身からのみスナップショットを取得できるようにElasticIPで制限をかけています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1427276485000",
            "Effect": "Allow",
            "Action": [
                "ec2:CreateSnapshot",
                "ec2:DeleteSnapshot",
                "ec2:DescribeSnapshots",
                "ec2:DescribeInstances",
                "ec2:CreateTags"
            ],
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "<instance_elastic_ip>/32"
                    ]
                }
            },
            "Resource": [
                "*"
            ]
        }
    ]
}

IAM Roleが使えない場合

IAM Roleを設定していないインスタンス等、IAM Roleを追加できない場合は、同様のポリシーを持ったIAM Userを作成して、AWS CLIの設定にキー情報を設定します。

スナップショット取得スクリプトの設置

下記にて紹介されているAMIMOTOで利用されているスクリプトを流用させて頂こうと思います。
このスクリプトは、世代管理ができるので便利です。
Snapshot を自動で作成するには?

しかし、このスクリプトはスナップショットのNameタグが設定されません。
個人的に、Nameタグにインスタンス名_日付のような形で設定したいので、スクリプトを少し修正します。

具体的にはcreate_snapshot()の処理に下記を追加します。

SNAPSHOT_ID=`grep SnapshotId ${LOG_FILE} |cut -d"\"" -f4`
SNAPSHOT_DATE=`date +%Y%m%d`
HOSTNAME=`hostname`
aws ec2 create-tags --resources ${SNAPSHOT_ID} --tags Key=Name,Value=${HOSTNAME}_${SNAPSHOT_DATE}

スクリプトの修正

差分は以下の通りです。

--- create-snapshot.sh_20160229134807        2016-02-29 12:37:48.334968041 +0900
+++ create-snapshot.sh       2016-02-29 14:46:02.926520887 +0900
@@ -54,6 +55,13 @@
         logger -f ${LOG_FILE}
         exit 1
     fi
+    ### Custom Add
+    SNAPSHOT_ID=`grep SnapshotId ${LOG_FILE} |cut -d"\"" -f4`
+    SNAPSHOT_DATE=`date +%Y%m%d`
+    HOSTNAME=`hostname`
+    aws ec2 create-tags --resources ${SNAPSHOT_ID} --tags Key=Name,Value=${HOSTNAME}_${SNAPSHOT_DATE}
+
     print_msg "Create snapshot End"
 }

実際のスクリプトは以下の通りです。

#!/bin/sh
SHELLDIR=`dirname ${0}`
SHELLDIR=`cd ${SHELLDIR}; pwd`
SHELLNAME=`basename $0`

LOG_DIR="/var/log"
LOG_SAVE_PERIOD=5
LOG_FILE="${LOG_DIR}/${SHELLNAME}.log"

AZ=`curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone`
LN=`echo $((${#AZ} - 1))`
REGION=`echo ${AZ} | cut -c 1-${LN}`
SNAPSHOTS_PERIOD=3

AWS="/usr/bin/aws --region ${REGION}"

INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`

rotate_log() {
    (( cnt=${LOG_SAVE_PERIOD} ))
    while (( cnt > 0 ))
    do
        logfile1=${LOG_FILE}.$cnt
        (( cnt=cnt-1 ))
        logfile2=${LOG_FILE}.$cnt
        if [ -f $logfile2 ]; then
            mv $logfile2 $logfile1
        fi
    done

    if [ -f $LOG_FILE ]; then
        mv ${LOG_FILE} ${LOG_FILE}.1
    fi
    touch $LOG_FILE
}

print_msg() {
    echo "`date '+%Y/%m/%d %H:%M:%S'` $1" | tee -a ${LOG_FILE}
}

create_snapshot() {
    print_msg "Create snapshot Start"
    VOL_ID=`${AWS} ec2 describe-instances --instance-ids ${INSTANCE_ID} --output text | grep EBS | awk '{print $5}'`
    if [ -z ${VOL_ID} ] ; then
        echo ${VOL_ID}
        print_msg "ERR:ec2-describe-instances"
        logger -f ${LOG_FILE}
        exit 1
    fi
    print_msg "ec2-describe-instances Success : ${VOL_ID}"
    ${AWS} ec2 create-snapshot --volume-id ${VOL_ID} --description "Created by SYSTEMBK(${INSTANCE_ID}) from ${VOL_ID}" >> ${LOG_FILE} 2>&1
    if [ $? != 0 ] ; then
        print_msg "ERR:${SHELLDIR}/${SHELLNAME} ec2-create-snapshot"
        logger -f ${LOG_FILE}
        exit 1
    fi
    ### Custom Add
    SNAPSHOT_ID=`grep SnapshotId ${LOG_FILE} |cut -d"\"" -f4`
    SNAPSHOT_DATE=`date +%Y%m%d`
    HOSTNAME=`hostname`
    aws ec2 create-tags --resources ${SNAPSHOT_ID} --tags Key=Name,Value=${HOSTNAME}_${SNAPSHOT_DATE}

    print_msg "Create snapshot End"
}

delete_old_snapshot() {
    print_msg "Delete old snapshot Start"
    SNAPSHOTS=`${AWS} ec2 describe-snapshots --output text | grep ${VOL_ID} | grep "Created by SYSTEMBK" | wc -l`
    while [ ${SNAPSHOTS} -gt ${SNAPSHOTS_PERIOD} ]
    do
        ${AWS} ec2 delete-snapshot --snapshot-id `${AWS} ec2 describe-snapshots --output text | grep ${VOL_ID} | grep "Created by SYSTEMBK" | sort -k 11,11 | awk 'NR==1 {print $10}'` >> ${LOG_FILE} 2>&1
        if [ $? != 0 ] ; then
            print_msg "ERR:${SHELLDIR}/${SHELLNAME} ec2-delete-snapshot"
            logger -f ${LOG_FILE}
            exit 1
        fi
        SNAPSHOTS=`${AWS} ec2 describe-snapshots | grep ${VOL_ID} | grep "Created by SYSTEMBK" | wc -l`
    done
    print_msg "Delete old snapshot End"
}

rotate_log

print_msg "INF:$SHELLDIR/${SHELLNAME} START"
create_snapshot
delete_old_snapshot
print_msg "INF:$SHELLDIR/${SHELLNAME} END"

exit 0

尚、今回は個人的な利用なので、20行目で世代数を3世代にしています。
設置できたら実行権限を付けておきます。

$ chmod +x create-snapshot.sh

cronへの設定

毎晩2時にスナップショットを取る場合は以下のように設定します。

0 2 * * * /your_script_path/create-snapshot.sh | logger -i -t DailySnapshot

このスクリプトは標準出力に処理途中の内容が出力される為、実行される度にcronの設定によりroot宛にメールが送られてしまいます。
これを止めたかったので、上記のような設定にしています。

以上です。

関連記事:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です