AWS API GateWay (Labmda)に負荷テスト(ラッシュテスト)を実施したときのTips

概要

サーバレスアーキテクチャ(今回でいうとサーバレスAPI)を構築した際、負荷テスト(ラッシュテスト)を実施した際にいろいろ試行錯誤した時のTipsです。

アーキテクチャ構成

よくある構成。APIGW->Lambda->DynamoDBと処理しているAPIがほとんどです。

arch.png
 

実施内容

どうやってラッシュテストしようか。

下記のパターンがさっと思いつきます。
1. Device Farmを使ってテストケース投入してやってみる。
2. JMeterとかを使ってシナリオテストっぽくしてみる。
3. APIエンドポイントに対して負荷をかけてみる。

JMeterを使おうとも考えましたが、シンプルに想定RPSを耐え切るかを見たかったので、3を選択しました。

ラッシュテスト 前準備

結論から述べると、ApacheBenchもvegetaもうまくいかなかったので、wrk使います。
wrkでEC2を大量に立ち上げ、小さい時間間隔でリクエストを投げ続け、求めるRPSが出るまでチューニングを繰り返しました。

シンプルにApacheBench(ab)テストをしてみる

負荷テストといえばApacheBench、ABテストが一番に思い浮かぶのでEC2をさくっと立てて実施して見ます。構成的には下記のような感じですね。

ab.png

インストール

ApacheBenchインストールは、【初心者向け】ApacheBench入門を参考にしてください。

実行

API Gatewayのエンドポイント(下記図のURL)に対してabコマンドを実行します。
apiurl.jpg

$  [ec2-user@test ~]$ ab -n 100 -c 10 https://XXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/YYYYYYYYYYY

結果

ABコマンド実行結果、大量のSSLハンドシェイクエラーが発生しました。。。
ab_error.png

なお、同じ事象に見舞われている記事がHITしました。どうやらAPIGatewayはSSL/TLSハンドシェイクがTLSv1を強要するようで、sslv3ではハンドシェイクできないのが原因の様子です。風の噂でjavaのバージョンを8にあげたら通るとかいう話もあったので試してみましたが、一度だけなぜか通り、それ以降は同様のSSLエラーに見舞われました。

vegetaというツールを使ってみる

Amazon API Gateway 経由でちょっとしたアクセスを流してみたで紹介されていた、
Go言語製ツールであるvegetaを使ってみました。

結果

vegetaは、あのべジータですww最強のサイヤ人の王子です!
これならばAPIエンドポイントに猛攻をかけてくれるに違いない!!とおもいながら試しましたが、同様にSSLハンドシェイクエラーで死にました。。。

wrkというツールを使ってみる

wrkという、Modern HTTP benchmarking toolを試してみました。

インストール

C言語で書かれているのでgithubにあがっているMakefileをつかってmakeします。make -j4ぐらいでやるとすぐ終わります。

$ sudo yum -y git
$ git clone https://github.com/wg/wrk.git
$ cd wrk
$ make -j4

実行

wrkコマンドをたたくとヘルプが表示されるので、必要なオプションを設定して対象のAPIエンドポイントに対してwrkコマンドを実行します。

./wrk -c 10 -t 2 -d 5s --latency "https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/YYYYYYYY"

上記コマンドでは、2スレッドで10コネクションを確立し、5秒間リクエストを送り続けると意味になります。–latencyオプションをつけることで50-90パーセンタイルごとのレイテンシーを結果に表示することが出来ます。これはよくシステム開発の性能テストでは80パーセンタイルが性能目標を満たしているかを問われるシチュエーションでは非常に有効です。

結果

下記の通り、結果を取得することが出来ます。
wrk.png

なお、注意点としては持続時間を長くしたり、大きなコネクション数、スレッド数を指定するとタイムアウトエラーであったり、Non 2xx or 3xx レスポンスが返ってきたりします(下記参照)。短い時間で繰り返しコマンドを実行させることで、つどつどスレッドやコネクションを解放してあげる必要がありそうです。

wrk_error1.png

wrk_error2.png

ラッシュテスト

今回はとりあえず200RPSを目標にパラメータチューニングをしつつ、ラッシュテストを実施しました。

EC2起動時にwrkコマンドを自動実行

EC2で起動時やterminate時にシェルを実行するを参考にし、EC2インスタンスが起動するときに自動でwrkコマンドがうごくような設定をしました。

これにより、AWS CLIなどからEC2インスタンスを大量起動させたときに自動でwrkが走り、ラッシュが開始されるという仕組みになっています。

API Gatewayの負荷テスト時の注意点

これはAPI Gatewayというより、CloudFront利用時の注意点になるのですが、API Gatewayは内部的にCloudFrontを使っているのでCloudFront利用時の注意点と同様の注意が必要です。

AWS公式ページでCloudFront の負荷テストについては記載されています。

今回は、下記観点より、AllRegionからのリクエスト発行はしていません。
* API Gatewayのキャッシュは無効に設定
* キャッシュを利用せずラッシュをかける
* 日本からしかアクセスしない

CloudWatch で実行状況をモニタリング

APIGateway, DynamoDBの様子をモニタリングします。

試行1

下記パラメータで試行してみます。最初、Lambdaのデフォルト上限数で挑みましたが、HTTP429エラーが多発(ようはスロットリング)が発生したので上限緩和申請をしています。

  • APIGWの同時実行数(デフォルト:1000rps、バースト時:2000rps)
  • Lambdaの同時実行数(デフォルト100.下記試験では600まで上限緩和)、
  • DynamoDBのRead Provisioned Capacity(下記試験では読み込みAPIコールのため、Read:200を割り当て)

なお、注意点としては、パラメータチューニングしたとしても予期せぬ事態でAPIGWかLambdaがタイムアウトするとHTTP429エラーを返すため、クライアント側でリトライする機構が本来は必要ですが今回は無視します。
(APIGW->Lambda呼び出しは同期呼び出しとなるため、自動リトライやDeadLetterQueueは使えない)

試行1の結果

下記の結果となっています。サイズやスケールがあっておらずすいません。
RPS、DynamoのRead Provisioned Capacisy, throttle、API Gatewayの順です。

  • RPSを見ると、最初はどかーんと出ていますが、DynamoDBのスロットリングが発生し出したあたりからRPSが下がり、一定の値で進んでいます。
  • DynamoDBを見ると、なぜかProvisioned超えながらConsumed Capacityが走っています。このグラフを見ると完全にDynamoで詰まっていることが分かります。
  • API Gatewayの結果を見ても、APIGatewayは1000rpsまで許可しているのでスロットリングは発生していないがDynamo側で詰まり、Lambdaの実行時間が長くなり、LambdaでタイムアウトしているためAPI Gatewayでも一定のエラーが発生しています。

rps.png

dynamo.png

APIgateway.png

試行2

下記パラメータで試行してみます。最初、Lambdaのデフォルト上限数で挑みましたが、HTTP429エラーが多発(ようはスロットリング)が発生したので上限緩和申請をしています。
過剰な気もしますが、Lambdaの上限数とDynamoから読み込むレコードサイズをもとにキャパシティを600としています。

  • APIGWの同時実行数(デフォルト:1000rps、バースト時:2000rps)
  • Lambdaの同時実行数(デフォルト100.下記試験では600まで上限緩和)
  • DynamoDBのReadProvisioned Capacity 600

試行2の結果

下記の結果となっています。サイズやスケールがあっておらずすいません。
RPS、DynamoのRead Provisioned Capacisy, throttle、API Gatewayの順です。

rps.png

dynamo.png

apigateway.png

  • リクエストが一気になだれ込むがLambdaの上限設定値あたりでストップします。
  • rpsの目標値である200はとりあえずクリアしています。
  • Dynamoのキャパシティをあげたので十分さばききれています(Provisioned > Consumedとなっている)。スロットリングも発生していません。
  • APIGatewayをみると時々エラーが発生(1、2件)いますが、前回ほどタイムアウトは発生していません。

まとめ

  • サーバレスアーキテクチャ(今回でいうとサーバレスAPI)の負荷テスト(ラッシュテスト)を実施
  • オンプレの環境と違い、ツール実行までに時間がかかったがwrkで着地(余裕があればJMeterやガトリングも使いたい)
  • フルマネージドということもあり、LambdaやAPI Gatewayはオートスケーリングしてくれる
    • 注意点としてはDynamoのキャパシティであるがマネジメントコンソールからボタン1つでキャパシティ設定できる
    • サーバレスアーキテクチャ的にスロットリングが一定時間発生したらキャパシティを現在より増加させるなどのCloudWatchEventsを設定してオートスケーリングさせるとよい気がする。
  • サーバレス楽しいです!

続きを読む

awscli で入れ子の AWS CloudFormation を楽にデプロイする

結論

aws cli のコマンド package で出来るよ!!!
package — AWS CLI 1.11.91 Command Reference

発端

CloudFormation の仕組みとして入れ子、つまり CloudFormation から CloudFormation をデプロイするができますが、その子供のほうが S3 に上がっている必要があります。
この S3 に上げるツールが色々あったり、自作できるレベルと思いつついやしかし…と考えていました。

解決策

その解決策して、冒頭に上げたコマンドがあります。
CHANGELOG を見る限りバージョン 1.11.19、去年の11月に追加されたみたいです。

使い方です。
フォルダ構成が以下のようになっている、とします。

.
├── README.md
├── sub
│   └── child.template
└──root.yaml

root.yaml が纏める CloudFormation です。
その中に child.template の情報が書いてあります。
実際にはこんな感じ。

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  myStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./sub/child.template
      TimeoutInMinutes: '60'
Outputs:
  StackRef:
    Value: !Ref myStack

この状態で、以下のコマンドをたたきます。

aws cloudformation package --template-file root.yaml --s3-bucket hogehoge-cfn

すると、TemplateURL: ./sub/child.template でおいていた子供のテンプレートが S3 にアップされて、それを適用するためのテンプレートが標準出力されます。

AWSTemplateFormatVersion: '2010-09-09'
Outputs:
  StackRef:
    Value:
      Ref: myStack
Resources:
  myStack:
    Properties:
      TemplateURL: https://s3.amazonaws.com/hogehoge-cfn/265b570db3b28df28e47c3f8e5032e65.template
      TimeoutInMinutes: '60'
    Type: AWS::CloudFormation::Stack

これでデプロイができます。

続きを読む

Amazon Athena の API を使ってみた (2017/05)

http://docs.aws.amazon.com/athena/latest/ug/release-notes.html#may-18-2017

2017年5月18日に Amazon Athena にて API が公開されました。
managed presto としての魅力を感じつつも API が存在しないということで original の presto を使っている人にとっては魅力が薄かったサービスですが、 API が公開されることでできることも増えました。

この記事では、 Amazon Athena の API の使い勝手について概観してみようと思います。

API で出来ること

公式ドキュメントにあるように、 API 経由で出来ることは以下になります。

http://docs.aws.amazon.com/athena/latest/APIReference/API_Operations.html

  • BatchGetNamedQuery
  • BatchGetQueryExecution
  • CreateNamedQuery
  • DeleteNamedQuery
  • GetNamedQuery
  • GetQueryExecution
  • GetQueryResults
  • ListNamedQueries
  • ListQueryExecutions
  • StartQueryExecution
  • StopQueryExecution

いくつか API がありますが、出来ることは大別して以下の3つです。

  • Query の実行に関する操作

    • ***QueryExecution
  • Query の実行結果に関する操作
    • GetQueryResults
  • NamedQuery (SavedQuery) に関する操作
    • ***NamedQuery

AWS CLI のセットアップ

この記事では Amazon Athena の API の呼び出しはすべて cli 経由で例示します。
Amazon Athena の API 呼び出しを行うために、あらかじめ awscli を最新版にアップデートしておきます。

$ pip install -U awscli --ignore-installed six
(snip.)
$ aws --version
aws-cli/1.11.90 Python/2.7.10 Darwin/16.5.0 botocore/1.5.53

また、現時点(2017年5月23日)では Amazon Athena は Tokyo Region に来ていないため、region の設定を Athena が動作する region に設定しておく必要があります。

$ cat ~/.aws/config
[default]
region = us-east-1

サポートしていない region を指定して Amazon Athena の cli を実行すると、処理がフリーズし応答がなくなります。(これは、エラーメッセージが表示された方が親切だと思います。)

QueryExecution

StartQueryExecution

http://docs.aws.amazon.com/athena/latest/APIReference/API_StartQueryExecution.html

任意の Presto Query を実行します。
以下からの例では、再現性を考慮しあらかじめ最初から用意されているサンプルデータベースのテーブルを対象にします。
(sampledb.elb_logs)

$ aws athena start-query-execution 
  --query-string 'select * from sampledb.elb_logs limit 1;' 
  --result-configuration OutputLocation=s3://hogehoge/athena-execution-result/
{
    "QueryExecutionId": ".........."
}

--query-string に実行する Presto Query を指定します。
--result-configuration OutputLocation=..... で指定した S3 Bucket に実行結果を保存します。

API の結果として返却される QueryExecxutionId という値を使用して、当該 Query については以後操作することになります。

GetQueryExecution

http://docs.aws.amazon.com/athena/latest/APIReference/API_GetQueryExecution.html

実行した Query の状態などの情報を取得します。

$ aws athena get-query-execution 
  --query-execution-id ()
$ aws athena get-query-execution 
>   --query-execution-id ..........
{
    "QueryExecution": {
        "Status": {
            "SubmissionDateTime": 1495539953.596, 
            "State": "SUCCEEDED", 
            "CompletionDateTime": 1495539955.596
        }, 
        "Query": "select * from sampledb.elb_logs limit 10", 
        "Statistics": {
            "DataScannedInBytes": 850058, 
            "EngineExecutionTimeInMillis": 1651
        }, 
        "ResultConfiguration": {
            "OutputLocation": "s3://hogehoge/athena-execution-result/...........csv"
        }, 
        "QueryExecutionId": ".........."
    }
}

この API の結果からは、Query の現在の状況(実行中か、完了しているか)、開始 / 終了時間などが取得できます。
状態の種類については以下公式ドキュメントに記載されています。
http://docs.aws.amazon.com/athena/latest/APIReference/API_QueryExecutionStatus.html

QUEUED | RUNNING | SUCCEEDED | FAILED | CANCELLED

個人的に、当該 API を cli から使用するときは、 StartQueryExecutionGetQueryExecutionjq コマンドを用いて pipe で繋いで、正しく実行されているかどうかをひと目で確認できるようにしています。
(毎回手で実行するのは手間なので、 warpper shell を用意しています)

$ aws athena get-query-execution 
  --query-execution-id  
  `aws athena start-query-execution --query-string 'select * from kuso_query;' --result-configuration OutputLocation=s3://hogehoge/athena-execution-result/ | jq -r '.QueryExecutionId'`
{
    "QueryExecution": {
        "Status": {
            "SubmissionDateTime": 1495540557.77, 
            "State": "FAILED", 
            "CompletionDateTime": 1495540557.914, 
            "StateChangeReason": "Database, table or column name not found. Please check your query."
        }, 
        "Query": "select * from kuso_query", 
        "Statistics": {
            "DataScannedInBytes": 0, 
            "EngineExecutionTimeInMillis": 67
        },
(snip.)
}

ListQueryExecutions

http://docs.aws.amazon.com/athena/latest/APIReference/API_ListQueryExecutions.html

過去に実行した Query の履歴が取得できます。
特に request parameter で検索条件が指摘できないため、基本的に登録された日時が新しいものから順に取得されます。

$ aws athena list-query-executions 
  --max-results 3
{
    "NextToken": "......", 
    "QueryExecutionIds": [
        "........", 
        "........", 
        "........"
    ]
}

こちらも結果として QueryExecutionId しか返却されず可読性が悪いので、以下のように jq で pipe してみます。
GetQueryExecution には複数の QueryExecutionId が渡せる BatchGetQueryExecution が存在するのでこちらを用います。

$ aws athena batch-get-query-execution  
  --query-execution-ids 
  `aws athena list-query-executions --max-results 3 | jq -r ".QueryExecutionIds[]" | tr 'n' ' '`
{
    "UnprocessedQueryExecutionIds": [], 
    "QueryExecutions": [
        {
            "Status": {
                "SubmissionDateTime": 1495540557.77, 
                "State": "FAILED", 
                "CompletionDateTime": 1495540557.914, 
                "StateChangeReason": "Database, table or column name not found. Please check your query."
            }, 
            "Query": "select * from kuso_query", 
(snip.)
    ]
}

このような形で、直近の Query の実行状況を 1 liner で確認することができます。

GetQueryResults

http://docs.aws.amazon.com/athena/latest/APIReference/API_GetQueryResults.html

実行した Query のデータを取得することができる API です。

$ aws athena get-query-results  
  --query-execution-id ........
{
  "ResultSet": {
    "Rows": [
      {
        "Data": [
          {
            "VarCharValue": "request_timestamp"
          },
          {
            "VarCharValue": "elb_name"
          },
          {
            "VarCharValue": "request_ip"
          },
(snip.)
        ]
      },
      {
        "Data": [
          {
            "VarCharValue": "2015-01-06T12:00:01.612598Z"
          },
          {
            "VarCharValue": "elb_demo_006"
          },
          {
            "VarCharValue": "243.72.152.87"
          },
(snip.)
    "ResultSetMetadata": {
      "ColumnInfo": [
        {
          "Scale": 0,
          "Name": "request_timestamp",
          "Nullable": "UNKNOWN",
          "TableName": "",
          "Precision": 1073741824,
          "Label": "request_timestamp",
          "CaseSensitive": true,
          "SchemaName": "",
          "Type": "varchar",
          "CatalogName": "hive"
        },
(snip.)
}

ただしこの結果内容は、プログラムで扱う分にはまだ良いですが、awscli から扱うには直感的な内容とはい言えないです。

awscli からは、StartQueryExecution 時に指定した OutputLocation から S3 経由で取得する、という方が楽かもしれません。

$ aws s3 cp  
  `aws athena get-query-execution --query-execution-id ........ | jq -r ".QueryExecution.ResultConfiguration.OutputLocation"` ./result.csv

download: s3://hogehoge/athena-execution-result/...........csv to ./result.csv

***NamedQuery

NamedQuery という用語が聞きなれなかったので何を指しているかよくわからなかったのですが、これは Amazon Athena の画面上では Saved Query と表現されているもののようです。

Athena ではよく使う Query などをあらかじめ登録しておくことができる機能がありますが、当該 API はその SavedQuery を操作する API になります。

CreateNamedQuery

http://docs.aws.amazon.com/athena/latest/APIReference/API_CreateNamedQuery.html

$ aws athena create-named-query 
  --name test --description 'for test'  
  --database sampledb  
  --query-string 'select * from sampledb.elb_logs limit 10;' 
{
    "NamedQueryId": "........"
}

QueryExecution と同じような形で NamedQueryId という ID が返却されます。

ListNamedQueries

http://docs.aws.amazon.com/athena/latest/APIReference/API_ListNamedQueries.html

登録されている SavedQuery (NamedQuery) の一覧を取得できます。
特に request parameter で検索条件が指摘できないため、基本的に登録された日時が新しいものから順に取得されます。namedescription などで絞込はできません。

$ aws athena list-named-queries 
  --max-results 3
{
    "NamedQueryIds": [
        "........", 
        "........", 
        "........"
    ], 
    "NextToken": "....."
}

GetNamedQuery

http://docs.aws.amazon.com/athena/latest/APIReference/API_GetNamedQuery.html

あらかじめ登録されている SavedQuery (NamedQuery) の情報を取得できます。
NamedQueryId のみを検索条件に指定可能で、 namedescription などで絞込はできません。

NamedQueryId があらかじめわかっている場合は、以下のような形で pipe で繋ぐことで Query を 1 liner で発行することは一応できます。

$ aws athena start-query-execution 
  --query-string "`aws athena get-named-query --named-query-id ........ | jq -r ".NamedQuery.QueryString"`"  
  --result-configuration OutputLocation=s3://hogehoge/athena-execution-result/
{
    "QueryExecutionId": "........"
}

個人的な感想

ここまで、だらだらと各 API について awscli の例をもとに書いてきました。

いままで JDBC 経由、もしくは Amazon Athena の web console 経由でしか使用ができなかった状況にくらべると格段と可能性は広がったように思えますが、個人的には以下の点で物足りなさを感じています。

  • 全体的に API のインターフェースが気がきいてない
  • ListQueryExecutions API で所定の条件で絞込、ならびに並び替えができない
    • たとえば、実行中の Query だけ取得する、実行時間が長い Query を取得する、ということが API 単体ではできない。
  • ListQueryExecutions の返却結果が QueryExecutionId だけで、情報量が少ない
  • GetQueryResults の使い勝手が悪い
  • 基本的に API の数が少ない
  • このタイミングで Amazon Athena 自身の機能拡張は特に無かった

などなど。

正直、今の機能では積極的にシステム・サービスに組み込んで行くには不足している点が多いと思いますが、期待されているサービスでもありますので今後の進化を期待したいと思います。

個人的に想像しているユースケース

Amazon Athena の API が出る、という話を聞いて、個人的に以下のようなユースケースで使いたいなと感がていました。蛇足になりますが、以下列挙します。

実行時間が長い Query を検知して stop する

現状の API では使い勝手が良くないですが、以下の API を組み合わせることで実現可能です。

  • ListQueryExecutions
  • BatchGetQueryExecution
  • StopQueryExecution

where 句に partition が指定されていない Query を検知して stop する

2017年5月22日現在、Amazon Athena は Tokyo Region に来ていないため、 Tokyo Region の S3 を Athena で使用する場合はどうしても転送量が発生します。

ものすごい巨大なデータ群が入っている S3 Bucket を data source にしている場合、partition を設定していなかったり、もしくは Query に partition 情報が含まれていない場合、膨大な転送量が発生してクラウド破産をしてしまう恐れがあります。
そのため、partition が指定されていない Query を検知し次第、stop をする、というようなユースケースが考えられます。

本来は、Amazon Athena 単体でこのような機能が備わっていてほしいですが、 API を用いることで実現することは可能です。

レポーティングバッチ

おそらくアプリケーション使用用途で一番うれしいのはこのケースだと思います。

レポーティングバッチから Amazon Athena を呼び出して何かしらのレポート処理を行いたい場合、JDBC 経由で対話的に Amazon Athena に繋ぐしか無い状況下では、 Query 実行結果に引きづられてずっとプロセスが待機する必要があったと思います(作りによりますが)

API が提供されたことで、 Query を submit する処理と結果を polling する処理を別に分けることもできますし、そもそも標準機能で実行結果を自動的に S3 にアップできるようにもなりました。

まとめにかえて

長々と書いてきましたが、Amazon Athena は期待の大きいサービスでもありますので、本体の機能も、API の機能についても、より使いやすいものに進化してもらえると、ユーザーとしては嬉しく感じます。

続きを読む

aws周りのメモ2

postgresqlを使う

RDSへpostgresqlをいれて立ち上げ

認証と接続

import-key-pair — AWS CLI 1.11.87 Command Reference
http://docs.aws.amazon.com/cli/latest/reference/ec2/import-key-pair.html

cd $HOGE
openssl genrsa -out my-key.pem 2048
openssl rsa -in my-key.pem -pubout > my-key.pub
# IAMのコンパネで*.pubを入力
# 多分、権限があれば以下でもいける
# aws iam upload-ssh-public-key

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

便利

無料枠

無料のクラウドサービス | AWS 無料利用枠
https://aws.amazon.com/jp/free/

AMI

AWS Marketplace: Search Results
https://aws.amazon.com/marketplace/search/results?x=14&y=18&searchTerms=&page=1&ref_=nav_search_box

CFテンプレート

サンプルコード & テンプレート – AWS CloudFormation | AWS
https://aws.amazon.com/jp/cloudformation/aws-cloudformation-templates/

ec2 ami tool & ec2 api tool

Mac で Amazon EC2 API Toolsを設定する – サーバーワークスエンジニアブログ
http://blog.serverworks.co.jp/tech/2013/01/31/mac-amazon-ec2-api-tools-setup/

ec2 api toolは若干心配。

VPCを使う

接続の際に、sshを経由したい。sslでもいいけどなんかsshがいいなと。
パスワードよりkeyのほうがセキュアだからかな。

0から始めるAWS入門①:VPC編 – Qiita
http://qiita.com/hiroshik1985/items/9de2dd02c9c2f6911f3b

導入

Amazon VPC とは? – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Introduction.html

公式のいろいろ

料金 – Amazon VPC | AWS
https://aws.amazon.com/jp/vpc/pricing/

基本は無料だけどNATとVPNは別課金。

【AWS 再入門】VPC 環境に踏み台サーバーを構築して SSH 接続してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-bastion-host-vpc/#i-3

ec2(Bastion)を配置する必要がありそう。

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

VPC に推奨されるネットワーク ACL ルール – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Appendix_NACLs.html

vpcでのネットワークのポリシーの例

Default VPC

AWSのDefault VPCを削除して困った話 – MikeTOKYO Developers
http://blog.miketokyo.com/post/49939300091/aws-default-vpc

デフォルトvpcは削除したらダメか。使い分けがわからん。

Amazon EC2 と Amazon Virtual Private Cloud – Amazon Elastic Compute Cloud
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-vpc.html

基本の機能はデフォルトとそうじゃないvpcは同じだけど、
デフォルトvpcがないとちゃんと機能しない。
デフォルトの属性によって、指定がないとipを紐付けたりする。

VPCネットワーク設計

これだけ押さえておけば大丈夫!Webサービス向けVPCネットワークの設計指針 | eureka tech blog
https://developers.eure.jp/tech/vpc_networking/

ネットワークは一度稼働させると移行が大変なので、初期設計が非常に重要になります。

わかりやすい。図が特に。

  • Bastion
  • NAT
  • Security Group

ENI

インフラエンジニアに贈るAmazon VPC入門 | シリーズ | Developers.IO
http://dev.classmethod.jp/series/vpcfor-infra-engineer/

サブネットで指定したIPアドレスのうち、先頭4つと末尾の1つはVPCで予約されるため使用できません。

VPCでは常にDHCP有効とするのがポイントです。

また、DHCPサービスで伝えられる情報(DHCPオプション)は、変更することもできます。

仮想マシンにひもづくENIにより、DHCPサーバーから毎回同じMACアドレス、IPアドレスが付与されます。これは、仮想マシンの状態に依存しないため、仮想マシンを再起動しようと、一旦シャットダウンしてしばらくしてから起動した場合でも必ず同じアドレスが付与されます。

ENI(Elastic Network Interface)か。。なるほど。でも、使うことはなさそうだな。

NAT

IPマスカレードが使えないVPC
NATは、Static(静的・サーバー用途)とElastic(仮想・クライアント用途)がある。
個人的には、このNATインスタンスの実装は、あまり好きではありません。動きがややこしいですし、ユーザーが自分でNATインスタンスの管理をしなければならないのも煩雑な印象を受けます。VPCのネットワークサービスの一つとして提供される機能であれば、ユーザーからはなるべく抽象化され仮想マシンとして意識されないようにするべきと考えます。
ただ、ユーザーから仮想マシンとして見える分、機能・実装が具体的に把握できる点やカスタマイズ性が高い点は良いとも思っています。

NAT インスタンスと NAT ゲートウェイの比較 – Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-nat-comparison.html

なるほど。。

Bastion

AWSで最低限セキュアな構成を組む – Qiita
http://qiita.com/ausuited/items/09b626fa5264f0c650fd

パブリックSubnetにEC2インスタンス(踏み台サーバーとして)
NATインスタンスを作成した要領で、パブリックSubnetにEC2インスタンスを作成する。Security groupは新規に作成してSSHをAnywhereに。Key pairは厳重に管理。尚、踏み台サーバーは、使用する時以外はStoppedにしておく事で、さらにセキュアな状態とする。このデザインパターンをOn Demand Bastionパターンと呼ぶらしい。

詳しい。「On Demand Bastionパターン」か。なるほど。

vpcへの踏み台サーバー
ポートフォワーディング、トンネルなどと同じ意味。

Network ACL

インスタンス単位じゃなくサブネット単位でより制限してセキュアにしたい場合に使うのかな。

安全なVPC設計 — Commerce Hack
http://tech.degica.com/ja/2016/01/07/designing-vpc-and-subnets/


結局どうするのか、、ひとまずNATはつかわずに、Bistionをつくってみる感じかな。

アベイラビリティーゾーン

リージョンごとでの、障害などで全部やられないように物理的にセグメントされた範囲の単位かな。
RDSではセグメントグループに2つ以上のゾーンを含める。でも、一つしか使わなくていい。ということか。s

RDSのVPC間の移動

サブネットグループの関連付けを変えればいいらしい。間違って設定したので移動した。

【小ネタ】知っていましたか?RDSを別のVPCに移動できることを | Developers.IO
http://dev.classmethod.jp/cloud/aws/rds_can_move_to_another_vpc/

Bastion作成作業をしてみる

主に下記を参考。

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう – NET BIZ DIV. TECH BLOG
https://tech.recruit-mp.co.jp/infrastructure/retry-aws-minimum-vpc-server-environment/

  • サブネットってなんだっけとか復習。
  • ストレージはどうするのか。
    • とりあえずssdにしたけどマグネティックでよかったかなあ。

      • ssd:$0.12 : 1 か月にプロビジョニングされたストレージ 1 GB あたり
      • マグネティック: 0.05 USD/GB-月
  • public IPは設定必要だよね
  • market placeからamiを取得した方がいいの?
    • とりあえず公式のウィザードを使ったけど。
  • 認証にIAMが追加されていたので使ってみた
    • これとは別にキーペアは必要ってことかな。
  • CFnテンプレート(CloudFormationテンプレート)というのがあるらしい。。
    • これでつくりなおそうかな。。
  • サブネットとかいろいろネットワーク系の設定
    • なんだかんだいっていろいろあった
  • セキュリティグループ
    • エイリアスみたいなセキュリティグループにできたらいいのに。タグや名前で明示化かな。
    • bastionは22をあけて、rdsは5432をbastionからのみあける
  • ログイン
  • DNS
    • あれ、パブリックDNSがうまく割り振ってないな。。
      AWSでPublic DNS(パブリックDNS)が割り当てられない時の解決法 – Qiita
      http://qiita.com/sunadoridotnet/items/4ea689ce9f206e78a523
    • RDSのDNS
      • nslookupしたら内部ipがかえってくるのね。接続できないけどなんか気持ち悪いな。これかな。。
        外部からdnsを引けることを気にしている人は見かけなくて便利だからって話なのかね。
        【AWS】VPC内でPrivate DNSによる名前解決 – Qiita
        http://qiita.com/y_takeshita/items/2eb5e6abb5eb5516d1de

やってるうちはいいけど、しばらくやらないと設定の方法とか忘れそう。。こういうのは学習コストだけじゃないな。

PlantUMLで図にしておく

Kobito.hQIwJs.png

VPC内のRDSへLambdaから接続。。

しまった!アンチパターンだそうだ。。

Lambda+RDSはアンチパターン – Qiita
http://qiita.com/teradonburi/items/86400ea82a65699672ad

Lambda + RDS benchmark – Qiita
http://qiita.com/taruhachi/items/3f95ae3e84f56edb3787

新し目の記事でIAM認証でクリアできそうな。。

【全世界待望】Public AccessのRDSへIAM認証(+ SSL)で安全にLambda Pythonから接続する – サーバーワークスエンジニアブログ
https://blog.serverworks.co.jp/tech/2017/04/27/rds-iam-auth-lambda-python/


セキュアに接続するのと速度のトレードオフになっていたのが
IAM認証のおかげで両方可能になったということっぽい。
でも、ネットのスループット、コネクション数(料金・負荷)、など、、ほかにも気にすることが出て来そうで若干不安。
非同期でよければキューイングして一回投げっぱなしすればどうだろう。
もしくは、似てるけど、Lambdaから一回値を返してもらってからRDSへ投げ直す。
これでいっかなあ。。Lambdaの意味がなくなる?うーん。

今後

  • 疑問としてrdsなど内部向けのdnsを外から見れなくできないものか。
  • というか、rdsのエンドポイントって再起動したら変わったりしないかね。ipは固定されるのか。
    • たぶん、サブネット内でdhcpになるのでipは変動するけどエンドポイントは固定。。じゃないかしら。

posgresqlをつかうための情報

Amazon RDS 上の PostgreSQL – Amazon Relational Database Service
http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.SSL

続きを読む

AWS CLIからAthenaのクエリを実行してみた

AWS CLIがAthena対応したので、試してみました。
(いや〜JDBC接続とかめんどかった・・・)

利用環境はMacです

AWS CLIをバージョンアップ

利用していたAWS CLIのバージョンは1.11.88でした

$ aws --version
aws-cli/1.11.88 Python/2.7.10 Darwin/15.6.0 botocore/1.5.51
$ aws help | grep athena

もちろんAthenaが入っていないのでバージョンアップします
–ignore-installed sixをつけないとバージョンアップできないのはなんとかならないかな・・・

$ sudo pip install --upgrade awscli --ignore-installed six

バージョンアップ完了

$ aws --version
aws-cli/1.11.89 Python/2.7.10 Darwin/15.6.0 botocore/1.5.52
$ aws help | grep athena
       o athena

ドキュメントを眺める

コマンド一覧

  • batch-get-named-query
  • batch-get-query-execution
  • create-named-query
  • delete-named-query
  • get-named-query
  • get-query-execution
  • get-query-results
  • list-named-queries
  • list-query-executions
  • start-query-execution
  • stop-query-execution

コマンド実行してみる

本日時点ではAthenaが東京リージョンに来てないので、コマンドに–region us-east-1(バージニアリージョン)を指定。(諸事情でprofileは使わない)
すでに、CloudFrontとCloudTrailのログをAthena上に配置
Athenaを使ってAWSのログを集計する

start-query-execution

クエリを実行するコマンド。
必須パラメータ
–query-string:Stringでクエリを記述。FROM句にDB名は必須。
–result-configuration:結果を出力するS3バケットを指定

$ aws --region us-east-1 athena start-query-execution 
    --query-string "SELECT * FROM aws_logs.cloudfront_log limit 10;" 
    --result-configuration OutputLocation=s3://athena-output
{
    "QueryExecutionId": "9d5f2f3a-e80f-4807-ab6c-35139924d374"
}

get-query-results

クエリの実行結果を見る

$ aws --region us-east-1 athena get-query-results 
    --query-execution-id 9d5f2f3a-e80f-4807-ab6c-35139924d374
{
    "ResultSet": {
        "Rows": [
            {
                "Data": [
                    {
                        "VarCharValue": "date"
                    }, 
                    {
                        "VarCharValue": "time"
                    }, 
                    {
                        "VarCharValue": "xedgelocation"
                    }, 
                    {
                        "VarCharValue": "scbytes"
                    }, 
                    {
                        "VarCharValue": "cip"
                    }, 
                    {
                        "VarCharValue": "csmethod"
                    }, 
                    {
                        "VarCharValue": "cshost"
                    }, 
                    {
                        "VarCharValue": "csuristem"
                    }, 
                    {
                        "VarCharValue": "scstatus"
                    }, 
                    {
                        "VarCharValue": "csreferer"
                    }, 
                    {
                        "VarCharValue": "csuseragent"
                    }, 
                    {
                        "VarCharValue": "csuriquery"
                    }, 
                    {
                        "VarCharValue": "cscookie"
                    }, 
                    {
                        "VarCharValue": "xedgeresulttype"
                    }, 
                    {
                        "VarCharValue": "xedgerequestid"
                    }, 
                    {
                        "VarCharValue": "xhostheader"
                    }, 
                    {
                        "VarCharValue": "csprotocol"
                    }, 
                    {
                        "VarCharValue": "csbytes"
                    }, 
                    {
                        "VarCharValue": "timetaken"
                    }, 
                    {
                        "VarCharValue": "xforwardedfor"
                    }, 
                    {
                        "VarCharValue": "sslprotocol"
                    }, 
                    {
                        "VarCharValue": "sslcipher"
                    }, 
                    {
                        "VarCharValue": "xedgeresponseresulttype"
                    }, 
                    {
                        "VarCharValue": "csprotocolversion"
                    }
                ]
            }, 
            {
                "Data": [
                    {
                        "VarCharValue": "2017-03-11"
                    }, 
                    {
                        "VarCharValue": "07:09:39"
                    }, 
                    {
                        "VarCharValue": "NRT20"
                    }, 
                    {
                        "VarCharValue": "485"
                    }, 
                    {
                        "VarCharValue": "182.251.62.172"
                    }, 
                    {
                        "VarCharValue": "GET"
                    }, 
                    {
                        "VarCharValue": "d296z2px268if9.cloudfront.net"
                    }, 
                    {
                        "VarCharValue": "/sample"
                    }, 
                    {
                        "VarCharValue": "200"
                    }, 
                    {
                        "VarCharValue": "-"
                    }, 
                    {
                        "VarCharValue": "curl/7.43.0"
                    }, 
                    {
                        "VarCharValue": "-"
                    }, 
                    {
                        "VarCharValue": "-"
                    }, 
                    {
                        "VarCharValue": "Miss"
                    }, 
                    {
                        "VarCharValue": "7_kRmqTCtndlAsdecditmwIL3kPgVKjsqBggBEFSu68_tsTGWAVK-g=="
                    }, 
                    {
                        "VarCharValue": "d296z2px268if9.cloudfront.net"
                    }, 
                    {
                        "VarCharValue": "https"
                    }, 
                    {
                        "VarCharValue": "99"
                    }, 
                    {}, 
                    {
                        "VarCharValue": "-"
                    }, 
                    {
                        "VarCharValue": "TLSv1.2"
                    }, 
                    {
                        "VarCharValue": "ECDHE-RSA-AES128-GCM-SHA256"
                    }, 
                    {
                        "VarCharValue": "Miss"
                    }, 
                    {
                        "VarCharValue": "HTTP/1.1"
                    }
                ]
            }, 
・・・

これ使いにくい・・・

get-query-execution

クエリ実行結果(成功/失敗)等の情報を取得する
start-query-executionで実行した結果を取得
必須パラメータ
–query-execution-id:実行時に表示されるQueryExecutionIdを指定

$ aws --region us-east-1 athena get-query-execution 
    --query-execution-id 9d5f2f3a-e80f-4807-ab6c-35139924d374
{
    "QueryExecution": {
        "Status": {
            "SubmissionDateTime": 1495269759.131, 
            "State": "SUCCEEDED", 
            "CompletionDateTime": 1495269762.711
        }, 
        "Query": "SELECT * FROM aws_logs.cloudfront_log limit 10", 
        "Statistics": {
            "DataScannedInBytes": 1454, 
            "EngineExecutionTimeInMillis": 3475
        }, 
        "ResultConfiguration": {
            "OutputLocation": "s3://athena-output/3fbf61dd-866e-4de6-9ba4-56cfdb671964.csv"
        }, 
        "QueryExecutionId": "3fbf61dd-866e-4de6-9ba4-56cfdb671964"
    }
}

StatusにSUCCEEDEDと表示されるので成功している
結果は実行時に指定したS3バケット内にCSVで保存される→OutputLocation

スクリプトを組むならこんな感じ?

athena-query.sh
#!/bin/bash

OutputBucket=athena-output # 出力バケット
# クエリ実行
queryId=$(aws --region us-east-1 athena start-query-execution 
    --query-string "SELECT * FROM aws_logs.cloudfront_log limit 10;" 
    --result-configuration OutputLocation=s3://$OutputBucket 
    | jq -r '.QueryExecutionId')
# 結果の確認
status=$(aws --region us-east-1 athena get-query-execution 
    --query-execution-id $queryId 
    | jq -r '.QueryExecution.Status.State')

if [ "$status" == "SUCCEEDED" ]; then
    aws s3 cp s3://${OutputBucket}/${queryId}.csv .
else
    echo "Query Error!"
fi

cat ${queryId}.csv

まとめ

  • 待望のAthenaがAWS CLIに対応しました。
  • BigQueryはbqコマンドで実行できたので、足並み揃い始めた感じでしょうか
  • もうすぐ東京リージョンに来そうな感じなので、期待大です(Comming Soonってなってるので、AWS Summit Tokyoで発表!?)
  • 出力結果がもっといい感じに見れるといいですね

続きを読む

AWS IoTの利用手順

AWS IoTに関する基本的な内容をまとめてみたものです。AWS IoTに関する、Web上にすでにある解説コンテンツをまとめたサイトの抜粋です。
AWS IoTの利用手順

AWS IoTを使うための手順

1) デバイスの作成
まずは、「Register -> Things」メニューの中の、 Register Thingsを選択して、デバイスを作成します。名称を指定して登録すると、AWS IoTの中にその名称のThingsおよびシャドウが作成されます。
その次に、そのデバイスのRuleを設定します。Ruleとは、どのデータに対してどういう条件のときにアクションを実行するかを決める情報です。

2) 証明書の作成
次にデバイスに登録する証明書を作成します。「Security -> Certificates」メニューの中の、Create a certificatesを選択して、証明書を作成します。

3) ポリシーの作成
次にデバイスに対して、AWS IoTの各種操作を許可するためのポリシーを作成します。全ての操作を許可するのか、一部の操作だけを許可するのか、許可する操作の定義です。「Security -> Policies」メニューの中の、Create a policyを選択して、ポリシーを作成します。

4) 証明書にデバイスとポリシーを割り当てる
作成した証明書とポリシーを関連づけします。証明書を作成した後に、「attach a policy」を選択して、関連付けしたいポリシーを設定、「attach a thing」を選択して割り当てしたいデバイスの設定をします。

マネジメントコンソールの設定は以上です。

デバイスの作成からデータを受信できるまで

AWS マネジメントコンソールは、Amazon IoT リソースのすべてにアクセスして管理するためのウェブベースのインターフェイスを提供しますが、プログラムから AWS IoT へのアクセスは、AWS CLI と AWS SDK を使用して有効にできます。

ハードウェアデバイス、センサー、モバイルアプリケーション、モノを接続するには、AWS IoT デバイス SDK を使用します。AWS IoT に接続が実装された AWS スターターキットから 1 つ選択します。それに加えて、AWS IoT は、幅広い種類のサードパーティ製のツールおよびゲートウェイでサポートされています。

AWS IoTデバイスSDK
AWS IoT デバイス SDK にはオープンソースライブラリ、サンプルの付属した開発者ガイドおよび移植ガイドが含まれているので、お客様の選択したハードウェアプラットフォームに革新的な IoT サービスを構築できます。

証明書と秘密鍵
マネジメントコンソールで作成した証明書と秘密鍵は、マネジメントコンソールからダウンロードしてデバイス側に設定します。

以上の作業で、デバイスからのデータのpublish/subscribeが可能となります。

AWS IoTへの各種アクセス方法

AWS IoT サービスには AWS マネジメントコンソール、AWS SDK、AWS CLI、AWS IoT API を使用してアクセスできます。接続されたデバイスからは AWS IoT デバイス SDK を使用して AWS IoT サービスと簡単に通信できます。
AWS IoT API およびコマンドは、コントロールプレーンオペレーションと、データプレーンオペレーションに大きく分かれています。コントロールプレーンオペレーションでは、セキュリティの設定、デバイスの登録、ルーティングデータのルールの設定、ログ記録の設定などのタスクを実行することができます。データプレーンオペレーションでは、接続されたデバイスから AWS IoT へ大規模に低レイテンシーかつ高スループットレートでのデータ取り込みを可能にします。

続きを読む