チラシの裏の書き置き

技術的な話をするブログのタイトルじゃない気がする

GPSログを蓄積する仕組みをAPi Gateway+Lambda+DynamoDBで構築した

つい最近GPSロガー的なのを作りましたが、毎回毎回SFTPで接続するなどしてログを取り出すのも面倒なのでDynamoDBに蓄積するようにします。

blog.taiko19xx.net

単純な蓄積だけでも良かったのですが、それではあまり面白くないので、セッションID的なのを生成するAPIも一緒に作っています。
「クライアントで勝手に生成すればよくね?」という感じですが、AWSのサービス間連携における練習も兼ねているのでなるべくサーバサイドで完結するようにします。
今はやりのサーバレス!

使ったサービス

LambdaはセッションIDの生成に使っています。データの蓄積はAPI GatewayからDynamoDBに直で行います。
ちなみに後述しますが、一番はまったのはIAMの設定です。

準備

DynamoDB

今回は次の2テーブルを利用します。

  • データを蓄積するテーブル
  • セッションIDの一覧を蓄積するテーブル

データ蓄積はセッションIDをパーティションキーに、時間を入れるカラムをソートキーにしています。
セッションID一覧はセッションIDのパーティションキーのみ。全て文字列です。

IAM

IAMでロールの設定もします。

ポリシーはこんな感じです。

PutItemをデータ蓄積用のテーブルとセッションID保管用のテーブルに割り当てておきます。後で気づいたけど多分Scanはいらない。

もう1つ、ロールの信頼関係を編集して、API GatewayとLambda(のプリンシパル?)を信頼しておきます。デフォルトだとEC2(ec2.amazonaws.com)が信頼されているはず。

実は設定した時はこの辺があまりよく分かっておらず、2〜3時間ぐらいはまりました。こうしておかないとAPI GatewayとLambdaでアクセスする時に怒られましたね。
APIをテストした時に失敗していて、ログに「Execution failed due to configuration error: API Gateway does not have permission to assume the provided role」というエラーが返ってきた場合はこの辺を見直してみましょう。

Lambda

Lambdaの役割はセッションIDを生成して、DynamoDBに保管し、そのIDを返すという動きだけです。

lの数字を書き換えれば文字数を変える事ができます。

API Gateway

下準備は整ったので、API Gatewayも設定してしまいます。
作成するAPIは次の2つです。(カッコ内はメソッド)

  • /post(POST)
  • /start(GET)

/startでセッションIDを取得して、/postに投稿します。

/start

セットアップ時に統合タイプをLambda 関数にして、リージョンと関数名を適切に設定すれば終わりです。関数動かすだけなのでこんなもんです。

/post

こっちは少々大変です。

初期設定は次のような感じです。

f:id:taiko19xx:20170609164158p:plain

この場合、このリクエストではPutItemを実行したいのでアクションにはPutItemを設定します。
問題はHTTPメソッドでですが、APIドキュメントのSample RequestがPOSTで送っているようなのでPOSTにしてみたら成功しました。

お次はリクエスト本文と挿入パラメータを照らし合わせる必要がありますので、その辺を設定します。
作成したメソッドの統合リクエストを開いて、一番下の本文マッピングテンプレートから、次のような流れで設定します。

  • リクエスト本文のパススルーをなしに
  • JSONでリクエストを受ける前提なので、Content-Typeをapplication/jsonで追加
  • テンプレートを入力するフィールドが現れるので、先ほどのAPIドキュメントを参考にテンプレートを構築

f:id:taiko19xx:20170609164654p:plain

テンプレートは、今回は下記に設定しています。

$input.path('$.hogehoge')$.から下に送信したリクエストのJSONが含まれるため、それを利用して値を取得します。
今回は最小限なのでこんな感じですが、他にも色々設定できます。

APIテスト時は上記パラメータが含まれるJSONを構築して、それでテストします。
問題なくデータが蓄積されていれば、デプロイして終わりです。

クライアント側

クライアント側はシェルスクリプトで処理しています。

gpsdを利用しているので、gpspipe-wを使うことでJSONの出力が取れます。
そこから緯度経度と時間を抽出し、それにセッションIDを合わせてリクエストを飛ばします。

本当は毎秒飛ばしたいくらいなのですが、とりあえず10秒おきに送信するようにしています。

あとは一通り試してみて、どんどんDynamoDBに蓄積されていれば終わりです。

まとめ

  • API GatewayからDynamoDBに直で入れられるのは楽で良い
  • とはいえLambdaも難しくない
  • IAMは大変めんどくさい

ちなみに

200リクエストちょい送っていますが、今月は1円しかかかってません。やっす。
(Lambda/DynamoDB/Data Transferは毎月の無料枠内で収まっていて、API Gatewayの利用料しかかかってない)

参考