S3のバケット毎の使用量が欲しいんです
最近、S3のバケット毎の使用量が欲しくてたまらない菅野です。
aws-cliを駆使して取得する必要がでてきたのでスクリプトを作成しました。
今回の目標
- 全てのS3バケットのバケット毎の使用量を取得する
では早速スクリプト作成開始です。
バケットの一覧を取得
不採用になったスクリプト
最初はこのようにしてみました。
# バケット一覧を取得 bucket_list=`aws cloudwatch list-metrics --namespace AWS/S3` # バケット名だけを取り出し bucket_list_json=`echo "${bucket_list}" | jq -r '.Metrics[] | select(.MetricName == "BucketSizeBytes") | .Dimensions[] | select(.Name == "BucketName") | .Value'`
- select(.MetricName == "BucketSizeBytes")
これが無いと同じバケット名が2個ずつ表示されます - select(.Name == "BucketName") | .Value
他にもキーがValueの要素があるのでselectを使って絞り込んでいます
うん、取れた・・・と思ったら実際のバケット数より少ないので調べたところ
デフォルトリージョン以外のバケットが取得できてませんでした。
これでは全バケット名を取得するために全リージョンを配列にして回さないといけないので不採用とします。
採用したスクリプト
以下の方法でバケット一覧を取得しました。
(こんなに簡単なら最初からこっちにしておけばよかったと後悔)
bucket_name_list=(`aws s3 ls | sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} //g'`)
- sedコマンドを使って結果の文字列から日時を消しています
バケットのリージョンを取得
バケットのリージョンを取得するには「s3api」を使いました。
for bucket_name in ${bucket_name_list[@]} do # バケットのリージョン情報を取得 region_info=`aws s3api get-bucket-location --bucket ${bucket_name}` # バケットのリージョン名を取得 region_name=`echo ${region_info} | jq -r '.LocationConstraint'` # 表示 echo ${region_name} done
簡単ですね。結果は以下となります。
ap-northeast-1 ap-northeast-2 ap-southeast-1 ap-southeast-2 eu-central-1 EU sa-east-1 null us-west-1 us-west-2 ap-northeast-1 ap-northeast-1 ap-northeast-1 ap-northeast-1 ap-northeast-1 ap-northeast-1 ap-northeast-1
「EU」とか「null」とか混ざってます・・・
「EU」は以下のページを拝見させていただき、「eu-west-1」に置換すればいいとわかりました。
S3 の Regions(リージョン)一覧
「null」はなんだろうと、該当バケットの情報をコンソールで見ると「US Standard」となっています。
こちらも先ほどのページを拝見させていただくと、「us-east-1」に置換すればいいようです。
置換するスクリプトも追加するとこんな感じになりました。
for bucket_name in ${bucket_name_list[@]} do # バケットのリージョン情報を取得 region_info=`aws s3api get-bucket-location --bucket ${bucket_name}` # バケットのリージョン名を取得 region_name=`echo ${region_info} | jq -r '.LocationConstraint'` # us-east-1の場合、nullが返ってくるので上書き if [ ${region_name} == null ] then region_name="us-east-1" fi # eu-west-1の場合、EUが返ってくるので上書き if [ ${region_name} == "EU" ] then region_name="eu-west-1" fi # 表示 echo ${region_name} done
バケットの使用量を取得
不採用になったスクリプト
最初は以下のスクリプトで試しました。
aws s3 ls s3://${bucket_name} --recursive --human-readable --summarize --region ${region_name}
- --summarize
このオプションを付けると合計サイズが取得できます
一見問題なさそうなのですが、以下のようなエラーが発生するバケットがたまにあったので不採用になりました
encode() argument 1 must be string, not None
詳しくは追ってませんが、日本語のファイル名を使ったオブジェクトがあった時に発生するようです。
採用したスクリプト
以下の方法でバケットの使用量を取得しました。
# バケット指定で容量を取得 bucket_size_info=`aws cloudwatch get-metric-statistics --region ${region_name} --namespace AWS/S3 --metric-name BucketSizeBytes --dimensions Name=BucketName,Value=${bucket_name} Name=StorageType,Value=StandardStorage --statistics Sum --start-time ${start_time} --end-time ${end_time} --period ${period}` # バケットの容量を取得 bucket_size=`echo ${bucket_size_info} | jq -r '.Datapoints[].Sum'`
このスクリプトではCloudWatchから情報を取得しています。
- --region
リージョンを指定 - --dimensions
バケット名を指定 - --metric-name
取得するメトリクスを指定。今回は「BucketSizeBytes」 - --statistics
取得する値を指定。今回は「Sum」 - --start-time、--end-time、--period
取得する期間とデータの間隔を指定
この方法で取得できるバケットサイズの単位はバイトとなります。
「MB」もしくは「GB」にしないと見栄えが悪いのでそこを修正するスクリプトも追加しておきます。
# 単位をMBに unit="MB" bucket_size=`echo "scale=2; ${bucket_size} / 1024 / 1024" | bc` # 小数点以下の場合は0を付ける bucket_size=`echo ${bucket_size} | sed -E 's/^[.]/0./'` # 1024MB以上だったら単位をGBに if [ `echo "${bucket_size} >= 1000" | bc` == 1 ] then unit="GB" bucket_size=`echo "scale=2; ${bucket_size} / 1024" | bc` fi
完成したスクリプト
スクリプトのソースは以下となります。 ※ Macのターミナルで実行する前提ですので、一部コマンドのオプションを修正する必要があるかもしれません
#!/bin/sh # デフォルトリージョンを指定 REGION="ap-northeast-1" # 集計開始日時 start_time="2016-03-31T00:00:00Z" # 集計終了日時 end_time="2016-03-31T23:59:59Z" # 集計単位 period=86400 #1日 # アクセスキー等をexport export AWS_ACCESS_KEY_ID=【アクセスキー】 export AWS_SECRET_ACCESS_KEY=【シークレットアクセスキー】 export AWS_DEFAULT_REGION=${REGION} echo " ●バケット別のデータ保存量" # バケット一覧を取得 bucket_name_list=(`aws s3 ls | sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} //g'`) # バケット名の配列でループ for bucket_name in ${bucket_name_list[@]} do # バケットのリージョン情報を取得 region_info=`aws s3api get-bucket-location --bucket ${bucket_name}` # バケットのリージョン名を取得 region_name=`echo ${region_info} | jq -r '.LocationConstraint'` # us-east-1の場合、nullが返ってくるので上書き if [ ${region_name} == null ] then region_name="us-east-1" fi # eu-west-1の場合、EUが返ってくるので上書き if [ ${region_name} == "EU" ] then region_name="eu-west-1" fi # バケット指定で容量を取得 bucket_size_info=`aws cloudwatch get-metric-statistics --region ${region_name} --namespace AWS/S3 --metric-name BucketSizeBytes --dimensions Name=BucketName,Value=${bucket_name} Name=StorageType,Value=StandardStorage --statistics Sum --start-time ${start_time} --end-time ${end_time} --period ${period}` # バケットの容量を取得 bucket_size=`echo ${bucket_size_info} | jq -r '.Datapoints[].Sum'` # 単位をMBに unit="MB" bucket_size=`echo "scale=2; ${bucket_size} / 1024 / 1024" | bc` # 小数点以下の場合は0を付ける bucket_size=`echo ${bucket_size} | sed -E 's/^[.]/0./'` # 1024MB以上だったら単位をGBに if [ `echo "${bucket_size} >= 1000" | bc` == 1 ] then unit="GB" bucket_size=`echo "scale=2; ${bucket_size} / 1024" | bc` fi # バケット名と使用量を表示 echo " ${bucket_name}:${bucket_size}${unit}" done
今回もなんとかできました
結果は以下のようになります。
●バケット別のデータ保存量 cloudtrail-ap-northeast-1-xxxxxxxxxxxx:13.64MB cloudtrail-ap-northeast-2-xxxxxxxxxxxx:0.01MB cloudtrail-ap-southeast-1-xxxxxxxxxxxx:0.39MB cloudtrail-ap-southeast-2-xxxxxxxxxxxx:0.39MB cloudtrail-eu-central-1-xxxxxxxxxxxx:0.38MB cloudtrail-eu-west-1-xxxxxxxxxxxx:0.38MB cloudtrail-sa-east-1-xxxxxxxxxxxx:0.38MB cloudtrail-us-east-1-xxxxxxxxxxxx:3.56MB cloudtrail-us-west-1-xxxxxxxxxxxx:0.38MB cloudtrail-us-west-2-xxxxxxxxxxxx:0.39MB backet-01:130.69MB backet-02:10.41MB backet-03:68.05GB backet-04:8.23GB backet-05:0MB backet-06:2.27GB backet-07:836.56MB
今回作成したことで、以下の事がわかりました。
- バケット名の一覧が欲しければ素直に「aws s3 ls」を使おう
- 「aws s3 ls」コマンドに「--summarize」オプションを付けるとバケット使用量が取得できる
- 「aws s3 ls --summarize」コマンドでは日本語のファイル名を使っているとエラーになる場合がある(修正される可能性大)
- CloudWatchのメトリクスにS3バケットの使用量があった
【新機能】S3のファイル数とバケットサイズがCloudWatchに追加されました - jqはやっぱり便利
今回バケット毎の使用量取得をスクリプト化したので自動で監視させるといった用途にも使えますし、
CloudWatchの他のメトリクスをスクリプトから取得する時の参考にもなると思います。
是非ご利用ください。
参考ページ
これらのページを参考にさせていただきました。
ありがとうございました。
S3 の Regions(リージョン)一覧
【新機能】S3のファイル数とバケットサイズがCloudWatchに追加されました
Amazon CloudWatch の概念
get-metric-statistics
CloudWatchからメトリクスを取得する
配列の全要素をループで取得する
s3api
bashで小数点比較