はじめに
CI/CDでEC2を自動デプロイ時にEBSのスナップショットが作成されるのですが、ケアしないとこれが溜まり続けてしまいます。
記事作成時点では東京リージョンで0.05USD/GB*1ヶ月です。
(料金はこちら:https://aws.amazon.com/jp/ebs/pricing/)
例えば20GBのEBSを使用している場合は1つのスナップショットあたり毎月1USDかかります。
開発環境でdevelopにPRがマージされるごとにデプロイされると毎日のようにこれが加算されていきます。
ケアしないと年間でかなりの額になります。
前提:EBSスナップショットとAMI
EC2インスタンス作成時にはAMIが作成されます。
AMIはOSやアプリを記録したテンプレートで、インスタンス起動時にこのテンプレートがEBSにコピーされます。
さらに、AMIにはEBSのスナップショットも含まれています。
そのため、EBSスナップショットを削除する際には関連するAMIを先に削除しておかなければエラーになります。
一方、AMIだけ削除してもEBSは削除してくれないので注意が必要です。
また、AMI自体にはコストはかからないのですがEBSスナップショットの方にコストがかかります。
この辺りの料金体系は複雑ですね。
AMIとEBSの関係についてはこちらの記事がわかりやすかったです:AMIとEBS、スナップショットの関係がよくわかっていなかった話
削除スクリプト
諸所の要望に応えるため下記の仕様にしました。
- AMIと対応するEBSスナップショットを削除します
- 削除するAMI名のプリフィックスが含まれるグループを指定できます(("")の場合はすべてが対象)
- 指定した数だけグループ内で最新のAMIを残すことができます
- aws-vaultを使用しています
#!/bin/bash
# profileを指定
PROFILE="dev" # aws-vaultで指定するprofile
# dry-runを指定。テストが終わったらコメントアウトする
DRY_RUN="--dry-run"
# 削除するAMI名のプリフィックスが含まれるグループを指定(""の場合はすべて対象)
GROUPS=("aaa" "bbb")
# 保持する数量
NUMBER_TO_KEEP=2
# 各グループに対してループ
for group in "${GROUPS[@]}"
do
echo "+++Deleting $group"
# グループ名を含むAMI IDとスナップショットIDを取得し、作成日時でソート
sorted_ids=$(aws-vault exec $PROFILE -- aws ec2 describe-images --filters Name=tag:Name,Values="$group*" --query "Images[].[CreationDate,ImageId,BlockDeviceMappings[0].Ebs.SnapshotId,Name]" --output text | sort -k1)
# 規定数以下の場合、削除しない
if [ $(echo "$sorted_ids" | wc -l) -le $NUMBER_TO_KEEP ]
then
echo "Nothing to delete for $group"
continue
fi
# 総数を取得
id_count=$(echo "$sorted_ids" | wc -l)
echo "id_count: $id_count"
# 最新の残す数を除いた数を取得
delete_count=$((id_count-$NUMBER_TO_KEEP))
echo "delete_count: $delete_count"
# 最新の残す数を除くすべてのスナップショットIDを取得
delete_ids=$(echo "$sorted_ids" | awk '{print $2,$3,$4 }' | head -n $delete_count)
# 古いAMIとスナップショットを削除
# delete_idsを一行ずつ読み込んでループ
echo "$delete_ids" | while read ids
do
# 分かりやすいように区切りを表示
echo "Deleting $(echo $ids | awk '{print $3}')-------------------"
# AMI削除
ami_id=$(echo $ids | awk '{print $1}')
echo "Deleting $ami_id"
aws-vault exec $PROFILE -- aws ec2 deregister-image --image-id $ami_id $DRY_RUN
# スナップショット削除
snapshot_id=$(echo $ids | awk '{print $2}')
echo "Deleting $snapshot_id"
aws-vault exec $PROFILE -- aws ec2 delete-snapshot --snapshot-id $snapshot_id $DRY_RUN
done
done
補足
溜まってしまったEBSのスナップショットは上記のスクリプトで一掃できますが、溜まらないようにする仕組みがあればコストの無駄がなくなります。
例えば削除スクリプトを定期実行する、デプロイ時に古いスナップショットを削除するなどがあります。
また、Amazon Data Lifecycle Managerというサービスがあり、古いバックアップを自動で削除できます。
Amazon Data Lifecycle Manager
おわりに
EBSスナップショットの概要と削除スクリプトをまとめました。
普段からコストエクスプローラーをチェックして不要なコストがかからないように気をつけたいですね。