bucket容量を監視してみた

S3関連でよく聞かれる質問に、bucketでquota設定ができるか、という物がある。
書き込み制限まではしないまでも、容量監視くらいはしたいというニーズもあると思うので、実装してみた。

実装方法

実際にS3にアクセスし、各bucket毎のobjectのサイズを合計して、CloudWatchのcustom metricとしてputします。
以下の仕様があります。

  • 大文字などドメイン名として成立しないbucketを無視します
  • アクセス権のないbucketを無視します
  • VersioningやMulti Part Uploadで使用している領域は考慮していません
  • bucket名を指定しない場合には、全てのbucketに対して監視を行い、合計バイト数も監視します
  • 月額メトリック数 × $0.5 の費用がかかりますので、本当に監視したいbucketだけを監視した方がよいと思います

コード

python(boto)を使います。テストはUbuntu 11.10のAMI上で行っています。
AWS_ACCESS_KEYとAWS_SECRE_KEY、監視対象のbucket名を設定します(省略した場合には全てのbucketが対象)。

#!/usr/bin/env python
import os
import sys
import datetime
import boto

# config
AWS_ACCESS_KEY = "ACCESSKEY"
AWS_SECRET_KEY = "SECRETKEY"
bucketnames = []

cw = boto.connect_cloudwatch(AWS_ACCESS_KEY, AWS_SECRET_KEY)
s3 = boto.connect_s3(AWS_ACCESS_KEY,AWS_SECRET_KEY)

if len(bucketnames) == 0:
    buckets=s3.get_all_buckets()
else:
    buckets=[];
    for bucketname in bucketnames:
        bucket=s3.get_bucket(bucketname)
        buckets.append(bucket)

total=0
for bucket in buckets:
    try:
        size=0
        for k in list(bucket):
            size+=k.size
        print bucket.name+" : "+str(size) +" Bytes"
        total+=size
        cw.put_metric_data("S3","BucketSize" , size, datetime.datetime.now(), "Bytes", {"bucket":bucket.name})
    except:
        print "bucket "+bucket.name+" may contains Upper case letter or inaccessible. skipping..."

if len(bucketnames)==0:
    print "(total) : "+str(total)+" Bytes"
    cw.put_metric_data("S3","BucketSize" , total, datetime.datetime.now(), "Bytes",{"bucket":"(total)"})

実行時にはTimezoneがUTCでないとMetricの登録に失敗する可能性がある(日本時間などで日付がUTCよりも未来の場合)ので、もしシステムのTimezoneがUTCでない場合は

$ TZ=UTC python bucketsize.py 

などとする必要があります。後は1時間毎などにcronで実行してください。

0 * * * * ~/bucketsize.py 2>&1 > ~/bucketsize.log

実行結果

AWS Management ConsoleのCloudWatchのタブで確認すると(リージョンをUS Eastにしてください)、S3:bucketsというカテゴリでMetricが存在していますので、bucketを選択してグラフにしてみると

のようにプロットされます。後は必要に応じてAlarmを設定するなどして見てください。

おまけ

IAMで権限を絞りたい場合には、下記のようなpolicyをご使用下さい。

{
  "Statement": [
    {
      "Sid": "S3",
      "Action": [
        "s3:ListAllMyBuckets",
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::*"
    },
    {
      "Sid": "CW",
      "Action": [
        "cloudwatch:PutMetricData"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}