2012年12月17日月曜日

CloudWatchのコマンドラインツールでDynamoDBの統計情報作成

前回のブログでDynamoDBの話をしたけど、インフラエンジニアの私は実際のテーブル設計
よりは、運用後のリソース管理が気になるところ。DynamoDBの良いところはスループットが
保障される事。とは言えこれは設定した値が保障されると言う事で、その値が適切でない
場合は結局「なんかレスポンス悪くね?」と言う残念な結果になってしまう事に。。。
それを恐れるがあまり、値を大きくしてしまうと請求の時に「高っ!」とびっくりする事に。
スループットの値は変更が聞くので、今回はDynamoDBの稼動統計を行うために情報取得を
してみましょ!


・情報取得方法
AWSでは稼動情報をみる事ができるCloudWatchという機能があります。こちらはEC2や
RDSなどAWSで扱っているサービスの情報が全て取得できます。何か動きがおかしいと
思った時には、ManagementConsoleからグラフ化されたものを見る事ができます。
ですが稼動統計を行う場合は、定期的に情報を取得しておく必要があります。
そこでコマンドラインツールを使用する事でデータを取得する事とします。

・準備
AWSの下記リンクから「Amazon CloudWatch Command Line Tool」をDownloadします。
http://aws.amazon.com/developertools/2534
今回はLinux(CentOS)を使用するため、DownloadしたzipファイルをEC2に格納します。
格納先は/usr/localとします。

/usr/local以下でzipファイルを解凍します。
# cd /usr/local
# unzip CloudWatch-2010-08-01.zip
# rm -f CloudWatch-2010-08-01.zip
使いやすいようにバージョン情報が入ったディレクトリ名を変更します。
# mv CloudWatch-1.0.13.4 CloudWatch
AWSにアクセスするためのアクセスキー用ファイルをコピーします。
# cp -p CloudWatch/credential-file-path.template ~/credential.txt
→コピー後にファイルを編集します。アクセスキー及びシークレットアクセスキーは事前に
 ManagementConsoleなどで確認しておきましょう。ファイルの中身は下記の通りです。

AWSAccessKeyId=<Write your AWS access ID>
AWSSecretKey=<Write your AWS secret key>


中身を他人に見られないようにパーミッションを変更します。
# chmod 600 ~/credential.txt
環境変数の設定です。(これらは.bashrcに記載しておくと良いでしょう)

export AWS_CLOUDWATCH_HOME=/usr/local/CloudWatch
export PATH=$PATH:$AWS_CLOUDWATCH_HOME/bin
export AWS_CREDENTIAL_FILE=~/credential.txt
export AWS_CLOUDWATCH_URL=https://monitoring.ap-northeast-1.amazonaws.com


これで準備は完了です。

・情報取得
今回用意したツールでは情報取得以外にもアラームの設定なども出来ます。今回は
統計情報を取得する事が目的のため、二種類のコマンドの紹介です。

○mon-get-stats
実際に情報を取得するコマンドです。
○mon-list-metrics
どのようなMetricがあるのかを確認(一覧表示)するコマンドです。

では実際に情報取得です。まずはmon-list-metricsで一覧を取得します。
# mon-list-metrics
結果は長いので省略ですが、今回はDynamoDBのRequestLatencyを取得するため一覧
から下記のものを対象とする事とします。

SuccessfulRequestLatency               AWS/DynamoDB     {Operation=GetItem,TableName=test_table}
SuccessfulRequestLatency               AWS/DynamoDB     {Operation=PutItem,TableName=test_table}
SuccessfulRequestLatency               AWS/DynamoDB     {Operation=UpdateItem,TableName=test_table}

mon-get-statsを使用して情報取得です。取り込み易いようにカンマ区切りにします。
# mon-get-stats SuccessfulRequestLatency \
   --statistics "Average,Sum,Minimum,Maximum" \
   --namespace "AWS/DynamoDB" \
   --dimensions "Operation=PutItem,TableName=test_table" \
   awk '{print $1 "," $2 "," $3 "," $4 "," $5 "," $6}' \
   >> ~/PutItem_test_table.cvs

ファイルの中身は下記のようになります。(時間はUTCのため注意)

2012-12-16,14:55:00,5.25654654646,196.23000000000002,3.265,6.013
2012-12-16,15:00:00,4.95656856565636,188.082,3.258,6.189
2012-12-16,15:05:00,3.565959565332,121.566,3.315,6.396
2012-12-16,15:10:00,4.4421333333333335,133.264,3.345,6.261
2012-12-16,15:15:00,4.2650526315795,165.88600000000002,3.279,6.124
2012-12-16,15:20:00,4.507655172413792,130.761999999998,3.392,6.659
2012-12-16,15:25:00,4.53334375,145.067,3.309,6.538
2012-12-16,15:30:00,4.254555555555555,123.87299999999,3.286,7.649
2012-12-16,15:35:00,4.309178571428572,120.65700000000001,3.251,6.151
2012-12-16,15:40:00,4.5852150000000001,93.043,3.343,5.876
2012-12-16,15:45:00,4.04362,101.138,3.284,5.2546


コマンドの最初の引数はMetricNameです。後の引数は下記になります。
--statistics 集計方法の指定
--namespace サービス名(DynamoDB、EC2など)の指定
--dimensions 集計情報のうちのどの情報かの指定
*ここがポイントで前述のmon-list-metricsの3カラム目の値となります。

上記のコマンドをcronなどで自動的に取得すれば良いということになります。
少々分からないのが5分おきの直近1時間のデータが取得されるはずなのですが、
11個(55分)しか取得できませんでした。ですので、データの抜けが内容に取得する
間隔を調整して重複するデータはuniqなどで排除する必要がありそうです。
(何か方法があるのかも知れませんが。。。)


大事なのは情報を取得する事ではなく、ここからいかに適切なリソース状態を導き
出すかです。(今後の課題ですね。。。)

2012年12月8日土曜日

DynamoDBをIAMでアクセス制限

DynamoDBは便利。AWSのManagementConsoleのウィザードでちょちょいとテーブル
作成が簡単にできる。検証でさくっと作ってぱぱっとテストも出来てしまう。テーブル
削除もぽちっとすれば、はい消えた!となるのでお手軽。テーブルはあるだけでお金
がかかるので、不要となったら小まめに消さなきゃね。
と、調子にのっているとミスって肝心の本番用テーブルを消してしまいがちなものですね。

そこで、IAMアカウントで本番用と開発用と分けてアクセス制限してしまいましょう^^


・制御内容
ネーミングルール(少なくとも本番用)が必要となります。今回は下記のようにします。
■本番用はテーブル名の頭にprd_がついている
■開発用はそれ以外

・アカウント
アカウントは二つ作成します。
■本番用アカウント prd_dynamo
■開発用アカウント dev_dynamo

・グループ
DynamoDBではアラート設定が出来るため、cloudwatchの権限を付与します。
テーブル自体は個々のアカウントでアクセス制御しますので、cloudwatchの権限はgroupで
管理します。Policy Generatorで簡単に作れますが、一応JSON載せておきます。

{
  "Statement": [
    {
      "Sid": "Stmt1354899265648",
      "Action": [
      "cloudwatch:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "*"
      ]
    }
  ]
}


では実際にアカウントへのpolicy設定です。
まずはprd_dynamoです。
{
  "Statement": [
    {
      "Sid": "Stmt1330073911360",
      "Action": [
        "dynamodb:DescribeTable",
        "dynamodb:ListTables"
      ],
      "Effect": "Allow",
      "Resource": [
        "*"
      ]
    },
    {
      "Sid": "Stmt1330073911361",
      "Action": [
        "dynamodb:*"
      ],
      "Effect": "Allow",
      "Resource": [
      "arn:aws:dynamodb:ap-northeast-1:<アカウントID>:table/prd_*"
      ]
    }
  ]
}

キーとなるのは、次の二点です。
■最初のAllowでDescribeTableとListTablesを入れる事
→これで全体のテーブルリストを表示する事ができます。全体を表示できるように
 設定しておかないと、自身のテーブルも表示出来ません。この設定でテーブル
 リストの表示のみ出来るようになります。
■次のAllowのリソースでtable/prd_*と記載する事
→これでprd_*で始まるテーブルを全て制御できるようになります。

次にdev_dynamoです。
{
  "Statement": [
    {
      "Sid": "Stmt1330073911370",
      "Action": [
        "dynamodb:BatchGetItem",
        "dynamodb:CreateTable",
        "dynamodb:DeleteItem",
        "dynamodb:DeleteTable",
        "dynamodb:DescribeTable",
        "dynamodb:GetItem",
        "dynamodb:ListTables",
        "dynamodb:PutItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:UpdateTable"
      ],
      "Effect": "Allow",
      "Resource": [
        "*"
      ]
    },
    {
      "Sid": "Stmt1330073911371",
      "Action": [
        "dynamodb:BatchGetItem",
        "dynamodb:CreateTable",
        "dynamodb:DeleteItem",
        "dynamodb:DeleteTable",
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:UpdateTable" ],
      "Effect": "Deny",
      "Resource": [
      "arn:aws:dynamodb:ap-northeast-1:<アカウントID>:table/prd_*"
      ]
    }
  ]
}

キーとなるのは、次の二点です。
■最初のAllowでDynamoDBの全ての権限を記載する事
→これで全てのテーブルの制御ができるようになります。ほんとは*でも良いかと
 思うのですが、ちょっと上手く動かなかったので個別に記載しています。
■次のDneyでtable/prd_*を記載する事
→これでprd_*で始まるテーブルを全て制御出来なくなります。但し、ここの記載
 にListTablesとDescribeTableは記載してはいけません。テーブルリスト表示が
 出来なくなるため、全体のテーブルリストも表示できなくなります。

さて、アクセス制御出来ているか確認してみましょう。

まずはprd_dynamoです。

テーブルリストが確認できます。

prd_testにアクセスできます。

testにアクセスできません。


次にdev_dynamoです。
テーブルリストが確認できます。

prd_testにアクセスできません。
testにアクセスできます。


最初はActionは*でResourceをprd_*のAllowとDenyで逆にすれば簡単に制御できる
かと思いましたが、テーブルリスト表示などの細かい部分で*で制御出来ない感じ
でした。