はじめに
今携わっているシステムでは、AWSを使っています。
通常時はEC2インスタンスを東京リージョンで稼働させ、月次でバックアップ(AMI、EBSスナップショット)を取得したうえ大阪リージョンに転送しています。
東京リージョンに大規模災害が発生する際に、大阪リージョンに転送されたAMIから、EC2インスタンスをリストアするためです。
リストア方法
世の中的にCloudformationやTerraformなどのIaCを活用してリストアする方法が主流になっていますが、おとなの事情により、シェルスクリプトにAWS CLIを叩く処理を記載し、リストア時に実行するというやり方を取っています。
なお、パラメータ等は外部JSONファイルに記載し、AWS CLIコマンドのオプションとして渡すようにしています。
AMIのタグが引き継がれない問題
AMIからEC2をリストアするには、以下のようにrun-instancesコマンドにAMI IDを渡すという方法を取りますが、このまま実行してもAMIに含まれるタグが引き継がれないので、リストア後に手動でタグを付与するという手間が発生する(一部オプションを省略しています)。
aws ec2 run-instances --image-id $IMAGE-ID
AMIからタグを取得してインスタンスに付与する
run-instancesコマンドを実行する際に、tag-specificationオプションで
ResourceType=string,Tags=[{Key=string,Value=string},{Key=string,Value=string}]
のフォーマットに従ってタグを渡せば、タグ付きのインスタンスを作成できます。
でしたら、AMIからタグを取得し、それをtag-specificationに渡せば手動でタグをつける手間がなくなります。
AMIからタグを取得するには、以下のようにdescribe-imagesコマンドをフィルター付きで実行します。
aws ec2 describe-images --filters "Name=image-id,Values=$IMAGE_ID" --query 'Images[0].Tags[*]'
そしたらこのように、AMIのタグが返されます。
[
{
"Key": "Key1",
"Value": "Value1"
},
{
"Key": "Key2",
"Value": "Value2"
}
]
しかし、これをそのままtag-specificationに渡しても、エラーで終わってしまいます。
なぜなら、tag-specificationが必要としているフォーマットと異なるからです。
解決方法
以下のように、AMIから取得したタグから、
- 角括弧を削除
- ダブルクォーテーションを削除
- スペースを削除
- 改行を削除
- コロンを=に置換
などをし、整形します。
TAGS=`aws ec2 describe-images --filters "Name=image-id,Values=$IMAGE_ID" --query 'Images[0].Tags[*]' |tr -d '['|tr -d ']'|tr -d '"'|tr -d ' '|tr -d '\n'|tr ':' '='`
整形したタグを、変数化し、tag-specificationに渡します。
aws ec2 run-instances \
--image-id $IMAGE_ID \
--tag-specification ResourceType=instance,Tags="[$TAGS]" \
--cli-input-json file://${INSTANCE_NAME}.json \
--query "Instances[*].InstanceId" \
--output text
スクリプト
以上をまとめると、以下のようなスクリプトが出来上がります。
# リストア先のリージョン。今回は大阪リージョン
REGION="ap-northeast-3"
# インスタンス名。インスタンスのNameタグとしても定義されています。
INSTANCE_NAME="SAMPLE-INSTANCE"
# インスタンス名をキーに、作成日が一番新しいAMIのIDを取得する
IMAGE_ID=`aws ec2 describe-images \
--filters "Name=tag:Name,Values=$INSTANCE_NAME" \
--query "reverse(sort_by(Images[].{CreationDate:CreationDate, ImageId:ImageId},$CreationDate)) | [0].ImageId" --region $REGION |tr -d '"'`
# AMIから、タグを取得する
TAGS=`aws ec2 describe-images --filters "Name=image-id,Values=$IMAGE_ID" --query 'Images[0].Tags[*]' |tr -d '['|tr -d ']'|tr -d '"'|tr -d ' '|tr -d '\n'|tr ':' '='`
# AMIからインスタンスをリストアする。諸々パラメータは、${INSTANCE_JSON}.jsonという外部ファイルで渡しています。
INSTANCE_ID=`aws ec2 run-instances \
--image-id $IMAGE_ID \
--tag-specification ResourceType=instance,Tags="[$TAGS]" \
--cli-input-json file://${INSTANCE_NAME}.json \
--query "Instances[*].InstanceId" \
--output text`