dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

AWS未経験だけどJAWS DAYS 2016のIoTハンズオンに参加してきた

JAWS DAYS に初参戦してきました。

これまで、AWS は業務で必要になるまでとりあえずいいか...と避けてたんですが
やはりこれだけ周囲が AWS を使っている中、「いやー仕事で使ったことなくて全然知らないんですよ」という訳にもいかないなあと思っていた矢先にこちらのハンズオンイベントを見つけ、思わず申し込みました。

ハンズオンは実際のセンサデバイスからデータを取得して AWS に送信するというのを経験できただけでなく、使用した AWS のサービスも AWS IoT や Lambda という比較的新しめのサービスを使用したもので大変面白かったです。

ただ、ハンズオンの最中はとりあえずひたすら資料に従って手を動かしてただけだったので
AWS の各サービスが何をしているのかよくわかってなかったこともあり、復習も兼ねて内容の振り返りをしておこうと思います。

ちなみに、自分のクラウド経験は実務で少し GCP(特に GAE。GCE はチュートリアルレベル)を使っていたのと、最近趣味で Heroku を勉強している程度です。
AWS は本当に未経験で、アカウントもイベント前日に作成、サービスとしてどんなものか知っているのは S3 と EC2 ぐらいでした。


ハンズオン概要

今回のハンズオンでどんなことをやったのか、簡単に振り返ってみます。

ハンズオンの資料はこちらです。
https://s3-ap-northeast-1.amazonaws.com/ma2shita/jawsdays2016-hackday-beginner/index.html

全体構成図を資料から引用します。

f:id:dackdive:20160313223954p:plain

まず FWM8BLZ02 という温度・加速度センサーからのデータを OpenBlocks IoT BX1 という IoT ゲートウェイで受信します。

IoT ゲートウェイ、という言葉を初めて聞きましたがこちらの記事が参考になりました。
技術で理解するIoT - [Part3 インターネット接続]ゲートウエイか単体か、それが問題だ:IoT Next

また、BX1 の特徴や使用方法についてはこちらの記事が詳しいです。
OpenBlocks IoT BX1を触ってみた | Developers.IO

BX1 には SIM カードを挿すことができます。今回は SORACOM Air の SIM を挿入し、3G 回線でネットにつなげるようにします。

f:id:dackdive:20160314021133j:plain:w360

(この SORACOM Air の SIM カードは持ち帰り OK だった!)

センサーからのデータは一旦 BX1 が受信した後、AWS IoT に伝送されます。
そこからさらに AWS Lambda を通じて Amazon ES (Elasticsearch Service) に送られ、最終的に Amazon ES に標準で用意されている Kibana というデータ可視化ツールによってセンサーデータをグラフ化するという流れです。

最終的にこんな感じでセンサーの加速度データを可視化することができました。

f:id:dackdive:20160313233326p:plain


使った AWS サービス

AWS IoT

さまざまな IoT デバイスAWS の各種サービスや他のデバイスとつないでくれる。

AWS IoT についてはこちらの資料がわかりやすいです。
https://s3-ap-northeast-1.amazonaws.com/awsiot-handson-jp/AWS-IoT-Service-Salesdeck-handson-public.pdf

AWS IoT は設定しないといけない項目が多く、ハンズオン中はそれぞれが何の設定をしているのかよくわからなくなりました。改めて確認してみます。

  1. ポリシー(Policy)
  2. モノ(Thing)
  3. 証明書(Certificate)
  4. ルール(Rule)
1. ポリシー(Policy)

バイスに対し、AWS IoT の各種操作を許可するための設定です。
たとえば、ここ に書いてある

{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action":["iot:Publish"],
        "Resource": ["arn:aws:iot:us-east-1:123456789012:topic/foo/bar"]
    }]

は、/foo/bar という Topic に対して Publish のみ許可する、といった内容になるはず。

2. モノ(Thing)

実際の IoT デバイスに対応します。正直、なんでこれが必要なのか今もよく分かってないです。
シャドーと呼ばれる機能のために必要っぽい。。。?

参考:AWS IoTのThing Shadowsを図と実行例で理解する #reinvent | Developers.IO

3. 証明書(Certificate)

ちゃんと認証したデバイスとのみ通信するよう、証明書が必要になります。
証明書は、先ほどのポリシー・モノに対して割り当て(Attach)する必要があるのと、デバイス側にも設定する必要があります。

BX1 の場合は Web UI から証明書のアップロードもできてました。その他のデバイスだとどうするのかな。。。

f:id:dackdive:20160314014244p:plain

4. ルール(Rule)

一番重要っぽい。
バイスから送られてきたさまざまな Topic のさまざまなデータのうち、

  • どの Topic のデータを受信(Subscribe)するか
  • どういう条件にマッチした時だけアクションするか
  • どういうアクションをするか

みたいなことを決めます。

設定画面はこんな感じです。

f:id:dackdive:20160314014601p:plain

「Topic filter」が Subscribe する Topic になります。設定したルールは SQL っぽくなってますね(「Rule query statement」の部分)。

また、Subscribe したデータに対するアクションは以下のように、AWS の各種サービスにつなげることができます。

f:id:dackdive:20160314014719p:plain

今回はここから Lambda function を実行するよう設定しました。

Lambda に使える言語は今のところ Node.js、PythonJava の3つのようです。
Python をおさえてるの個人的にはポイント高い)

今回は言語に Python を使用し、以下のようなコードを書きました。

# 一部抜粋
def lambda_handler(event, context):
    logger.info('got event: {}'.format(event))
    body = []

    es_bulk_header = {"index": {}}
    body.append(es_bulk_header)

    payload = event["state"]["reported"] # When data of client pass through the AWS IoT, become {state: {reported: {PAYLOAD}}}
    es_bulk_row = {
        "deviceId"  : payload["deviceId"],
        "@timestamp": datetime.now(tz=JST()).strftime("%Y-%m-%dT%H:%M:%S%z"),
        "payload"   : payload
    }
    body.append(es_bulk_row)

    post_body = "\n".join(map(json.dumps, body)) + "\n"
    logger.debug('post_body: {}'.format(post_body))

    # REF: http://takuya-1st.hatenablog.jp/entry/2014/08/23/023707
    invoke_url = "http://" + "/".join([es_endpoint, es_index, es_type, "_bulk"])
    logger.debug('invoke url: {}'.format(invoke_url))
    req = urllib2.Request(invoke_url, post_body, http_req_headers)
    res = urllib2.urlopen(req)
    logger.info('res body   :{}'.format(res.read()))

    return "done"

受け取ったデータをそのまま Amazon ES のエンドポイントに POST しています。


AWS Lambda

他の AWS サービスのイベントをトリガとしてコードを実行することができます。コードを書くだけなので、コードを実行するためのサーバーの管理などは不要です。

AWS サービスのイベントから関数を呼び出すという使い方だけでなく、Amazon API Gateway と組み合わせれば REST API サーバーみたいなものが作れてしまうようです。

f:id:dackdive:20160314020047p:plain:w360

(↑ は https://aws.amazon.com/jp/lambda/ から)

参考:【新機能】Amazon API Gatewayを使ってAWS LambdaをSDKなしでHTTPS越しに操作する | Developers.IO


Amazon Elasticsearch Service (Amazon ES)

Elasticsearch というオープンソースの分析エンジンを AWS 上で簡単に扱えるようにしたもの。
Elasticsearch は Elastic 社というところが開発したものらしいんですが、同じく Elastic 社の Kibana というデータ可視化ツールも一緒になってるので、分析用に投入したデータを簡単にグラフ化して見ることができます。

Elasticsearch について調べると用語が色々でてきてイメージがしづらかったんですが、このあたりが参考になりました。

おわりに

振り返ってみると3時間のハンズオンがかなり濃い内容だったことがわかりました。
まだまだ各種サービスを完全に理解したわけでは決してありませんが、今回のイベントがきっかけで概要を知ることができたのは非常にいい経験になりました。

センサーがないと今日学んだことを試せないのかなと思ってたんですが、こちらの記事にあるようにそれっぽいデータを JS で作って SDK で送信することができるみたいです。
AWS IoTのデータをKibanaに表示する - Qiita

そう考えると、たしかにデバイスから AWS IoT への送信部分は BX1 がよしなにやってくれた部分があったので
そのあたり普通に(SDK 使って)やったらどういうことしないといけないのか、確認してみないとなあ。。。

それから、ハンズオンの内容もそうですがイベント全体的にもう話題は EC2 とかから Lambda などの新規サービス(Lambda しか知らないのでアレですが)に集中しており、世間でサーバーレスアーキテクチャと呼ばれている流れなのかなあと感じました。

聞けなかったこのあたりのセッションも勉強したい。