こんにちは!AWS事業本部のおつまみです!
S3バケットを一撃で削除したいなぁと思ったことはありますか?私はあります。
そう思い昨日こちらのブログを執筆しました。
このブログのスクリプトでも問題なく動くのですが、とある方からTwitterでこちらのコメントをいただきました。
#DevelopersIO バージョニングが有効化された 大量のAmazon S3 バケットをシェルスクリプトで一撃削除してみた https://t.co/esjLT5Nq32
こんだけ呼び出してAPIのレート制限は大丈夫かな。🤔
— Kento.Yamada (@ymd65536) April 14, 2023
そしてアドバイスをいただきスクリプトを修正したのでver.2として公開したいと思います!
バージョニングが有効化された Amazon S3 バケットを削除するシェルスクリプト(ver.2)
修正したシェルスクリプトです。(修正箇所はハイライトがかかっている箇所になります。)
deleteS3.sh
#!/usr/bin/bash
bucket_name="$1"
page_size=999
# Abort the process if there is no argument
if [ $# != 1 ]; then
echo "Please enter an argument."
exit 1
fi
# Get the list of buckets to be deleted
backet_list=`aws s3api list-buckets | \
jq -r ".Buckets[].Name" | \
grep ${bucket_name} `
# There is no target bucket
if [ -z "${backet_list}" ]; then
echo "There was no target bucket."
exit 0
fi
# Confirm that you want to delete the bucket
echo "${backet_list}"
while true; do
read -p "Do you want to delete this buckets? (y/n)" yn
case $yn in
[Yy]* ) break;;
[Nn]* ) exit 0;;
* ) echo "Please answer yes or no.";;
esac
done
echo "Start deleting the bucket."
# Delete the bucket
echo "${backet_list}" | while read backet_name
do
echo "Deleting ${backet_name} ..."
next_token=""
while true; do
output=$(aws s3api list-object-versions --bucket "$bucket_name" --max-items "$page_size")
output=$(aws s3api list-object-versions --bucket "$bucket_name" --max-items "$page_size" --starting-token "$next_token")
delete_items=$(echo "$output" | jq '.Versions + .DeleteMarkers | {Objects: map({Key, VersionId}), Quiet: true}')
count=$(echo "$delete_items" | jq '.Objects | length')
next_token=$(echo "$output" | jq -r '.NextToken')
if [ -z "$count" ] || [ "$count" -eq 0 ]; then
echo "$bucket_name の全てのオブジェクトが削除されました。"
break
else
aws s3api delete-objects --bucket "$bucket_name" --delete "$delete_items"
echo "$bucket_name の$count 個のオブジェクトを削除しました。"
fi
if [ -z "$next_token" ] || [ "$next_token" == "null" ]; then
break
fi
done
aws s3 rb s3://$backet_name --force
done
echo "done"
こちらのシェルスクリプト、ほぼ先人(のんピさん)が作成されたものを流用させていただきました。ありがとうございました。
処理のフローは変わっていません。(のんピさんのブログより引用)
- 引数として文字列を受け取る
- 引数が1つじゃない = 正しいフォーマットではない場合は異常終了する
aws s3 api list-buckets
とjq
、grep
で、引数として受け取った文字列がマッチするS3バケット名を取得する
- マッチしたS3バケットが何もなければ正常終了する
- マッチしたS3バケットの一覧を出力し、処理を続けるのか入力を受け付ける
- 削除するのであれば
yes
で、次の処理に進む- 削除しないのであれば、
no
で、正常終了するyes
もしくはno
以外の文字列が入力された場合は、繰り返し確認する- マッチしたS3バケットを順に削除する
s3api delete-objectsの罠
aws s3api list-objects
は一度に指定出来るキーが最大 1,000 までという罠があります。
そのため、それ以上のオブジェクトを含むバケットの場合の考慮が必要でした。
AWS CLI のページ分割オプションの使用 - AWS Command Line Interface
デフォルトでは、AWS CLI は、個々のサービスによって決定されるページサイズを使用し、利用可能なすべての項目を取得します。例えば、Amazon S3 では、デフォルトのページサイズは 1,000 です。3,500 のオブジェクトを含む Amazon S3 バケットで
aws s3api list-objects
を実行すると、AWS CLI は Simple Storage Service (Amazon S3) に対して 4 つの呼び出しを自動的に実行し、サービス固有の分割ロジックをバックグラウンドで処理して、最終的な出力で 3,500 オブジェクトのすべてを返します。
よってs3api list-objects
で最大 1,000 に引っかからないよう、オプション--page-size
で1000未満を指定し、複数回delete-objects
でループするようにしました。
ちなみにこの指摘も先人(大瀧さん)が優しく教えてくれました。ありがとうございます。
list-object-versionsでページネーションを考慮していないので、削除漏れが出ちゃうかなと思いました。岩佐さん指摘の上限1000オブジェクトに引っかからないようにページサイズを1000未満にして複数回delete-objectsでループするのがよさそうですhttps://t.co/KjbBEJAW5U
— Ryuta Otaki (@takipone) April 14, 2023
そして修正はもちろんChatGPTにお願いしました。
実行してみた
Cloudshellから実行してみました。ログは以下のようになりました。
[cloudshell-user@ip-10-6-30-202 ~]$ sh deleteS3.sh aws-sam-cli-managed-default-samclisourcebucket-pz07v14ifkek
aws-sam-cli-managed-default-samclisourcebucket-pz07v14ifkek
Do you want to delete this buckets? (y/n)y
Start deleting the bucket.
Deleting aws-sam-cli-managed-default-samclisourcebucket-pz07v14ifkek ...
aws-sam-cli-managed-default-samclisourcebucket-pz07v14ifkek の80 個のオブジェクトを削除しました。
aws-sam-cli-managed-default-samclisourcebucket-pz07v14ifkek の全てのオブジェクトが削除されました。
remove_bucket: aws-sam-cli-managed-default-samclisourcebucket-pz07v14ifkek
done
オブジェクトが多いバケットでも問題なく削除できました!
さいごに
今回はバージョニングが有効化された Amazon S3 バケットをAWS CLIで一撃削除する方法(ver.2)をご紹介しました。
先人の方々のコメントでまた1つ学びが増えました。感謝です。
最後までお読みいただきありがとうございました!
どなたかのお役に立てれば幸いです。
以上、おつまみ(@AWS11077)でした!