Fluentdから#SORACOM Funnel経由でAmazon Kinesis Firehoseにログを送信する

2016.02.01

ども、大瀧です。

SORACOMから発表された新サービスFunnelは、IoTデバイスの通信をバックエンドのクラウドサービスに転送します。今回は、IoTデバイスからの通信として、Fluentd(td-agent)からKinesis Firehoseへの転送を試してみます。

Fluentdとは

Fluentdは、ログなどのデータ収集ソフトウェアとして広く用いられているOSSです。手軽に導入するために、開発主体のTreasure Data社が提供するtd-agentディストリビューションを利用するのが一般的です。 *1

Kinesis Firehoseとは

Kinesis Firehoseは、AWSのマネージドなストリーミング基盤サービスの一つで、簡単にS3やRedshiftへのデータ格納を行うことができます。

SORACOM Funnelなしでも、FluentdにはKinesis Firehoseプラグイン *2があるのですが、IoTデバイス全台にAWSのAPIキーを配置するのは、運用コストと盗難のリスクから難しいケースもあると思います。

SORACOM FunnelのKinesis Firehose Adapterを利用することで、AWS APIキーをアダプタに設定し、IoTデバイスからFunnelへはAPIキーなしのTCP/UDP/HTTPのいずれかのリクエストでFirehoseへのPutRecordが可能になります。こうすることで、IoTデバイスにAPIキーを配置する必要がなくなるわけです。

fluentd-funnel01

では、設定していきます。

Fluentd(td-agent)の設定

動作確認環境

  • OS : Ubuntu Server Trusty 64bit
  • td-agent : バージョン2.3.0

今回は、fluent-plugin-out-httpプラグインを利用しHTTPでFunnelへのログ送信を構成します。まずはtd-agentとfluent-plugin-out-httpプラグインをインストールします。

$ curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh
  :(略)
$ sudo td-agent-gem install fluent-plugin-out-http
  :(略)
$

今回はApacheのアクセスログを転送するので、以下のようにtd-agent.confを設定しました。

<source>
  @type tail
  path /var/log/apache2/access.log
  pos_file /var/log/td-agent/httpd-access.log.pos
  tag apache.access
  format apache2
</source>
<match **>
  type http
  endpoint_url    http://funnel.soracom.io/
  http_method     post   # default: post
  serializer      json   # default: form
  rate_limit_msec 100    # default: 0 = no rate limiting
  raise_on_error  false  # default: true
</match>
  • 115行目 : ここからfluent-plugin-out-httpの設定
  • 117行目endpoint_url : Funnelのエンドポイント(funnel.soracom.io)を指定
  • 118行目http_method : Funnelが許容するHTTPメソッドの記述がドキュメントに見当たらないため、Getting Startedの例に従いPOSTにしておく
  • 119行目serializer : FunnelへのHTTPリクエストは現時点でJSONフォーマットのみとのことなので、jsonをセットしておく

これでOKです。/var/log/apache2/および/var/log/apache2/access.logのパーミッションに注意しつつ、td-agentを実行しましょう。

Firehoseの構成

清野のエントリーと同じ構成でオレゴンリージョンに作成しました。Firehoseのデリバリーストリーム名、AWSリージョン名とIAMユーザーのAPIキー、シークレットキーを控えておきましょう。

Funnelの構成

SORACOMユーザーコンソールには、Funnelの設定画面に加えてFunnelリリース当初は無かった認証情報ストアの画面が追加されたので、今回はこれらを利用してみます。

ユーザーコンソールのメニューから[セキュリティ] - [認証情報ストア]をクリックし、[+ 認証情報を登録]ボタンをクリックします。

fluentd-funnel02

適当な[認証情報ID]を入力しつつ、[種別]を「AWS認証情報」、[AWS Access Key ID]、[AWS Secret Access Key]にAPIキー、シークレットキーそれぞれをペーストし、[登録]をクリックします。

fluentd-funnel03

続いて、FunnelはSIMグループ単位で設定するため、[グループ]メニューからグループを選択、[SORACOM Funnel設定]のアコーディオンメニューを開きます。

fluentd-funnel04

[ON]に切り替え、[リソースタイプ]から「Amazon Kinesis Firehose」、[リソースURL]は「https://firehose.<リージョン名>.amazonaws.com/<デリバリーストリーム名>」の規則で入力、[認証情報]は先ほど登録した認証情報IDを選択し、[保存]をクリックします。

これで準備OKです。デバイス上でcurl localhostなどを実行しアクセスログを出すと、Funnel→Firehose→S3とログが転送されていきます。Firehoseは転送するデータがある程度溜まるまでバッファリングするので、アクセスログを貯めるかしばらく待ってからS3バケットを確認しましょう。以下のようにファイルが格納されていれば正常に動作しています。

fluentd-funnel05

ファイルの中身は以下のようになっていました。

{"operatorId": "OP0123456789", "timestamp": 1454034500854, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034501314, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034501726, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034502242, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034502694, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034503106, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034503846, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034507992, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}
{"operatorId": "OP0123456789", "timestamp": 1454034508734, "destination": {"resourceUrl": "https://firehose.us-west-2.amazonaws.com/takipone-test", "service": "firehose", "provider": "aws"}, "credentialsId": "otaki-funnel-firehose", "payloads": {"code": 200, "agent": "curl/7.35.0", "host": "127.0.0.1", "referer": null, "user": null, "path": "/", "method": "GET", "size": 11764}, "sourceProtocol": "http", "imsi": "XXXXXXXXXXXXXXXX"}

いい感じですね!payloads以下がApacheログのデータ、それ以外はFunnelが付与したSIMに関する情報です。

まとめ

Fluentdのログ出力をSORACOM Funnel経由でKinesis Firehoseに転送する様子をご紹介しました。FunnelとFirehoseの組み合わせで、デバイス側のログ出力がすごく楽になる様子を感じていただけたのではないでしょうか。SORACOMのデータ転送料金が気になるのであれば、Funnel経由ではありませんがWi-Fiの固定回線とSORACOM Endorseの認証連携を組み合わせるのも面白いかもしれません。

脚注

  1. IoTデバイスによってはリソース面からRubyベースのFluentdの利用が難しいこともあるので、軽量版のFluentBitにHTTP Output Pluginがサポートされると今回の構成が試せるので誰か作ってくれないかなぁと思っています。
  2. 近々AWSオフィシャルのKinesisプラグインに統合される見通し