ようへいの日々精進XP

よかろうもん

(ショロカレ 15 日目)Amazon ECS の個人的な疑問を紐解いていくメモ(1)~ ECS container agent を ECS-Optimized Amazon Linux 以外の Linux にインストールする

やっと on time な「初老丸の独り Advent calendar 2015」の十五日目の記事です。

tl;dr

Amazon ECS で個人的な疑問を紐解いていきたい。


今日の疑問

疑問

  • ECS-Optimized Amazon Linux 以外の Linux に ECS container agent をインストール出来るのか?
  • 出来れば最新の Docker で ECS container agent を利用したいです

答え

  • 安心してください、インストールできますよ

ECS container agent 自体が Docker コンテナということもあり Docker が動いていればインストールできそうです。以下のようにドキュメントにも Amazon Linux 以外の Linux 環境にインストールする手順も記載されています。

また、以下のように Ubuntu 環境にインストールされている方もいらっしゃいます。

stormcat.hatenablog.com

今回は上記の記事などを参考に ECS container agent を ECS-Optimized Amazon Linux 以外の Linux にインストールしてみる。


試す

教材

github.com

今後の疑問解決か出来るだけこちらのリポジトリを利用する。

ざっくり手順

  1. EC2 を構築する
  2. ECS クラスタを作成する
  3. EC2 に Docker Engine をインストールする
  4. ECS Container agent をインストールする
  5. ひとまずクラスタの状態を確認するところまで

EC2 を構築する、ECS のクラスタを作成する

EC2 の OS は terraform を利用して Ubuntu Server 14.04 LTS を利用する。

尚、教材で利用する各種コマンドは make コマンドにまとめている。

$ cd oreno-ecs/terraform
$ make

Makefile for ECS

Usage: make [task]

Tasks:
tf-plan                         ....... Execute terraform plan
tf-apply                        ....... Execute terraform apply
tf-destroy                      ....... Execute terraform destroy

実行前に Makefile を修正する必要があるので注意。

$ vim Makefile
TF_PLAN := terraform plan \
             -var 'access_key=AKxxxxxxxxxxxxxxxxxx' \
             -var 'secret_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
             -var 'ssh_key_name=your-key-name' \
             -var 'subnet=subnet-xxxxxxxx' \
             -var 'securiy_group=sg-xxxxxxxx'

TF_APPLY := terraform apply \
             -var 'access_key=AKxxxxxxxxxxxxxxxxxx' \
             -var 'secret_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
             -var 'ssh_key_name=your-key-name' \
             -var 'subnet=subnet-xxxxxxxx' \
             -var 'securiy_group=sg-xxxxxxxx'

自分の環境に合わせて上記の情報を修正する。修正したら以下のように terraform planterraform apply を実行する。

$ make tf-plan
Refreshing Terraform state prior to plan...


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

(snip)

$ make tf-apply

(snip)

aws_iam_role.ecs_iam_role: Refreshing state... (ID: ecs_iam_role)
aws_iam_role_policy.ecs_iam_role: Refreshing state... (ID: ecs_iam_role:ecs_iam_role)
aws_iam_instance_profile.ecs_iam_role: Refreshing state... (ID: ecs_iam_role)
aws_instance.oreno_tf_test: Refreshing state... (ID: i-xxxxxxxx)

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

  EC2 IP address  = xxx.xxx.xxx.xxx
  EC2 Instance ID = i-xxxxxxxx
  ECS Cluster Name = oreno-cluster

EC2 が起動したら ssh でログイン出来るか確認しておく。

Docker をインストールする

以下のドキュメントに従って Docker をインストールする。

docs.docker.com

2015 年 12 月 15 日時点の Docker バージョンは 1.9.1 となる。

#
# apt-key の追加
#
$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

#
# source リストを作成
#
$ sudo vim /etc/apt/sources.list.d/docker.list
# 以下を追加する
deb https://apt.dockerproject.org/repo ubuntu-trusty main

#
# apt-get update
#
$ sudo apt-get update

#
# Docker をインストール
#
$ sudo apt-get install docker-engine

#
# ubuntu ユーザーでも docker コマンドをたたけるように ubuntu ユーザーを docker グループに所属させる
#
$ sudo usermod -aG docker ubuntu
# いったん、ログアウト

ubuntu ユーザーを docker グループに所属させた後に、一旦、ログアウトすることをお忘れなく...。

ECS container agent をインストールする

こちらのドキュメントを参考にして ECS container agent をインストールする。

#
# ECS container agent がコンテナ内からマウントするためのマウントポイントを作成する
#
$ sudo mkdir -p /var/log/ecs
$ sudo mkdir -p /var/lib/ecs/data

#
# ECS container agent をインストールする(docker run する)
#
$ docker run --name ecs-agent \
--detach=true \
--restart=on-failure:10 \
--volume=/var/run/docker.sock:/var/run/docker.sock \
--volume=/var/log/ecs/:/log \
--volume=/var/lib/ecs/data:/data \
--volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \
--volume=/var/run/docker/execdriver/native:/var/lib/docker/execdriver/native:ro \
--publish=127.0.0.1:51678:51678 \
--env=ECS_LOGFILE=/log/ecs-agent.log \
--env=ECS_LOGLEVEL=info \
--env=ECS_DATADIR=/data \
--env=ECS_CLUSTER=oreno-cluster \
amazon/amazon-ecs-agent:latest

#
# インストールされたことを確認
#
$ docker  ps

よし、よし。

諸々確認

例のごとく make コマンドにまとめてある。

$ cd oreno-ecs/ecs-cli
$ make

Makefile for ECS

Usage: make [task]

Tasks:
ecs-up                          ....... ECS Cluster up
ecs-list                        ....... list up ECS Clusters
ecs-list-container-instances    ....... list up ECS Container instances. Require environment variable 'ECS_CLUSTER'
ecs-describe-container-instances....... describe ECS Container instances. Require environment variable 'ECS_CLUSTER' and 'ECS_ARN'
$ make ecs-list
CLUSTERARNS     arn:aws:ecs:ap-northeast-1:251150836600:cluster/oreno-cluster
$ make ECS_CLUSTER=oreno-cluster ecs-list-container-instances
CONTAINERINSTANCEARNS   arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxxx:container-instance/55bcab9a-1983-4b5c-bfba-3b5668e29034
$ make OUTPUT=text ECS_CLUSTER=oreno-cluster ECS_ARN=55bcab9a-1983-4b5c-bfba-
3b5668e29034 ecs-describe-container-instances
CONTAINERINSTANCES      True    arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxxx:container-instance/55bcab9a-1983-4b5c-bfba-3b5668e29034 i-xxxxxxx   0       0       ACTIVE
ATTRIBUTES      com.amazonaws.ecs.capability.privileged-container
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.17
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.18
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.19
ATTRIBUTES      com.amazonaws.ecs.capability.docker-remote-api.1.20
ATTRIBUTES      com.amazonaws.ecs.capability.logging-driver.json-file
ATTRIBUTES      com.amazonaws.ecs.capability.ecr-auth
REGISTEREDRESOURCES     0.0     1024    0       CPU     INTEGER
REGISTEREDRESOURCES     0.0     992     0       MEMORY  INTEGER
REGISTEREDRESOURCES     0.0     0       0       PORTS   STRINGSET
STRINGSETVALUE  22
STRINGSETVALUE  2376
STRINGSETVALUE  2375
STRINGSETVALUE  51678
REGISTEREDRESOURCES     0.0     0       0       PORTS_UDP       STRINGSET
REMAININGRESOURCES      0.0     1024    0       CPU     INTEGER
REMAININGRESOURCES      0.0     992     0       MEMORY  INTEGER
REMAININGRESOURCES      0.0     0       0       PORTS   STRINGSET
STRINGSETVALUE  22
STRINGSETVALUE  2376
STRINGSETVALUE  2375
STRINGSETVALUE  51678
REMAININGRESOURCES      0.0     0       0       PORTS_UDP       STRINGSET
VERSIONINFO     191dbd5 1.7.0   DockerVersion: 1.9.1

Docker のバージョンは 1.9.1 として認識されている。ちなみに、--output text は見にくいかも。

  • マネジメントコントロールから ECS クラスタを確認する

Docker のバージョンも認識されている。

f:id:inokara:20151216083848p:plain


以上

疑問は...

解けました。

余談

ECS-Optimized Amazon Linux で用意したクラスタで Docker バージョンなどを確認すると以下のように Docker バージョンは少し古い。そして、ECS Container agent のバージョンもちょっと古い。(古いというか Docker バージョンに合わせたバージョンとなるようだ)

f:id:inokara:20151216090908p:plain

やり残し

  • Docker と ECS container agent をインストールするまでを自動化(出来るはず)

(ショロカレ 14 日目)EC2 の詳細モニタリングが適用されていることを確認するメモ

遅延していますが...これは「初老丸の独り Advent calendar 2015」の十四日目の記事です。

tl;dr

EC2 で詳細モニタリングが適用されていることをマネジメントコンソール以外から確認する方法のメモ(ドキュメントをちゃんと読もう事案)。


ドキュメントをちゃんと読もう事案

ドキュメント

docs.aws.amazon.com

詳細モニタリングとは

CloudWatch の詳細モニタリングを有効にすると 1 分ごとの CloudWatch 収集データを確認することが出来るようになる。

詳細は以下のドキュメントを。

docs.aws.amazon.com

(この記事を書く前にやっていた)詳細モニタリング設定

マネジメントコンソールから。

f:id:inokara:20151215081525p:plain

ポチ。

f:id:inokara:20151215081536p:plain

ポチと。

f:id:inokara:20151215081550p:plain

簡単に出来た。

さて、マネジメントコンソール以外から適用を確認する

aws-cli を利用する。

$ aws --version
aws-cli/1.9.8 Python/2.7.6 Linux/3.13.0-55-generic botocore/1.3.8

以下のように monitor-instances を使えばよさそう。というか、monitor-instances を利用することで詳細モニタリングが有効に出来るとのこと。

$ aws ec2 monitor-instances --instance-ids i-xxxxxxx

以下のように出力される。

{
    "InstanceMonitorings": [
        {
            "InstanceId": "i-xxxxxxx",
            "Monitoring": {
                "State": "enabled"
            }
        }
    ]
}

なるほど、なるほど。すでに有効になっているので Stateenabled になっている。

ちなみに、無効にする場合には以下のように unmonitor-instances を利用する。

$ aws ec2 monitor-instances --instance-ids i-xxxxxxx

以下のように出力される。

{
    "InstanceMonitorings": [
        {
            "InstanceId": "i-xxxxxxx",
            "Monitoring": {
                "State": "disabling"
            }
        }
    ]
}

無効中という感じなのかな...disabling となっている。もう一度、たたくと...

{
    "InstanceMonitorings": [
        {
            "InstanceId": "i-xxxxxxx",
            "Monitoring": {
                "State": "disabled"
            }
        }
    ]
}

念のためにマネジメントコンソールから確認すると以下のように...。

f:id:inokara:20151215082222p:plain

改めて有効にしてみる。

$ aws ec2 monitor-instances --instance-ids i-xxxxxxx

以下のように出力される。

{
    "InstanceMonitorings": [
        {
            "InstanceId": "i-xxxxxxx",
            "Monitoring": {
                "State": "pending"
            }
        }
    ]
}

設定中ということなのかな...pending となっている。もう一度、たたくと...

$ aws ec2 monitor-instances --instance-ids i-xxxxxxx

以下のように出力される。

{
    "InstanceMonitorings": [
        {
            "InstanceId": "i-xxxxxxx",
            "Monitoring": {
                "State": "enabled"
            }
        }
    ]
}

有効(詳細)になっている。念のためにマネジメントコンソールでも...

f:id:inokara:20151215082757p:plain

ほうほう。


ということで

詳細モニタリングってなんぼ?

こちらが詳しい。

おまけに基本のモニタリングと詳細モニタリングについてこちらより抜粋。

モニタリング 特徴
基本モニタリング 事前に選択した 7 種類のメトリックス(5 分間隔)と、3 種類の状態チェックメトリックス(1 分間隔)。追加料金なし
詳細モニタリング 基本モニタリングで利用できるすべてのメトリックスが 1 分間隔で更新される。追加料金が必要。詳細モニタリングが有効にされているインスタンスでは、Amazon EC2 AMI ID とインスタンスタイプごとにデータを集計できる。

なるほど、なるほど。

ecs-cli で起動するコンテナインスタンスって

デフォルトで詳細メトリクスが有効になっていて驚いた。

以上

詳細モニタリングを始めて触ることになったし、ドキュメントをちゃんと読みましょう事案でした。

(ショロカレ 13 日目)Elasticsearch 及び Amazon ES で Bulk API を試すメモ

遅延していますが...これは「初老丸の独り Advent calendar 2015」の十三日目の記事です。

tl;dr

先日の勉強会で Amazon ES に Web 上から取得したデータを解析して Amazon ES に放り込むデモをやったら Amazon ES にデータを放り込む前にタイムオーバーしてしまって残念だったのでメモ。


原因と対策

原因

原因というか大量のデータを放り込む時には Bulk Insert を利用する方が良さそう。

対策

上記の通り、Bulk API を使うように修正する。今回は Ruby の elasticsearch-ruby を利用する。

github.com

elasticsearch-ruby で Bulk API を利用する場合には bulk メソッドを利用する。

def bulk_post(es_endpoint, data)
  c = Elasticsearch::Client.new log: true, url: es_endpoint
  c.bulk(body: data)
end

data は配列で指定する。

ということで、以下のような感じで soramame-es.rb を書き換えた。

github.com

def processing_soramame_content(uri, check_date_time, check_time)
  index_date = check_date_time.split(' ')
  html = NKF.nkf("--utf8", open(uri).read)
  # Parse content and post to Elasticsearch
  header = ['CHECK_DATE_TIME','CHECK_TIME','mon_st_code','town_name', 'mon_st_name', 'SO2','NO','NO2','NOX','CO','OX','NMHC','CH4','THC','SPM','PM2_5','SP','WD','WS','TEMP','HUM','mon_st_kind']
  doc = Nokogiri::HTML.parse(html, nil, nil)
  bulk = []
  num = 1
  doc.xpath('//tr[td]').each do |tr|
    row = tr.xpath('td').map { |td| td.content.gsub(/[\u00A0\n]|\-\-\-/,'NA') }
    row.unshift(check_time)
    row.unshift(check_date_time)
    ary = [header,row].transpose
    h = Hash[*ary.flatten]
    record_index = {
      'index' => {
        '_index' => "pm25_test_" + $d.strftime("%Y-%m-%d"),
        '_type' => 'kyushu',
      }
    }
    record_data = {
      'CHECK_DATE_TIME' => h['CHECK_DATE_TIME'],
      'CHECK_TIME' => h['CHECK_TIME'],
      'town_name' => h['town_name'],
      'mon_st_name' => h['mon_st_name'],
      'PM2_5' => h['PM2_5'].include?('NA') ? h['PM2_5'] = '' : h['PM2_5'],
      'TEMP' => h['TEMP'].include?('NA') ? h['TEMP'] = '' : h['TEMP']
    }
    bulk << record_index
    bulk << record_data
  end
  bulk_post($url, bulk)
end

上記のようにすることで bulk の中身は以下となり Bulk API で放り込まれる。

(snip)

{"index":{"_index":"pm25_test_2015-12-13","_type":"kyushu"}}
{"CHECK_DATE_TIME":"2015-12-13 01:00:00","CHECK_TIME":"01","town_name":"志布志市","mon_st_name":"志布志","PM2_5":"","TEMP":""}
{"index":{"_index":"pm25_test_2015-12-13","_type":"kyushu"}}
{"CHECK_DATE_TIME":"2015-12-13 01:00:00","CHECK_TIME":"01","town_name":"肝属郡東串良町","mon_st_name":"東串良","PM2_5":"","TEMP":""}

比較

Bulk API を利用した場合と通常のドキュメント追加を利用した場合の速度をザクっと比較。

  • レコード数は 205 レコード
  • ファイルに書き出すと 36KB 弱

以下のような結果となった。

  • Elasticsearch で比較
#
# Bulk API
#
$ time ruby soramame-es.rb hb201512130108.html

(snip)

real    0m0.349s
user    0m0.224s
sys     0m0.063s

#
# 通常のドキュメント追加
#
$ time ruby soramame-es.rb hb201512130108.html

(snip)

real    0m0.643s
user    0m0.309s
sys     0m0.085s
#
# Bulk API
#
$ time ruby soramame-es.rb hb201512130108.html

(snip)

real    0m0.981s
user    0m0.254s
sys     0m0.051s

#
# 通常のドキュメント追加
#
$ time ruby soramame-es.rb hb201512130108.html

(snip)

real    0m44.970s
user    0m0.416s
sys     0m0.635s

Bulk API を使う方が速い。Amazon ES の場合がその差が顕著。Bulk API は速い分だけトレードオフはきっとあるだろうから引き続き調べる。


ということで...

How big is Too big?

ドキュメントより抜粋して意訳。

The entire bulk request needs to be loaded into memory by the node that receives our request, so the bigger the request, the less memory available for other requests. There is an optimal size of bulk request. Above that size, performance no longer improves and may even drop off. The optimal size, however, is not a fixed number. It depends entirely on your hardware, your document size and complexity, and your indexing and search load.

  • Bulk リクエスト(Bulk API)は Elasticsearch ノードのメモリにロードして処理する
  • ということは Elasticsearch ノードのメモリサイズによって Bulk API の性能は変化する
  • Bulk API のリクエストサイズによってはパフォーマンスが劣化する可能性がある
  • Bulk API のリクエストの最適値は Elasticsearch ノードのハードウェア性能、リクエストのドキュメントサイズや内容等によって変わる

なるほど、なるほど。

Amazon ES に対する要望

  • マネジメントコンソールからインデックスを追加、削除出来るとちょっとうれしい(API からでもそれほど難しくないけど)

以上

取り急ぎ、メモでした。(後ほど Bulk API についてもう少し書く)

(ショロカレ 12 日目)JAWS-UG福岡「ちょっと濃い目にAWSの話をしてみよう」で AWS カルタが超絶面白かったのと Amazon ES の話をさせて頂いたのでメモ

これは「初老丸の独り Advent calendar 2015」の十二日目の記事です。

tl;dr

久し振りに勉強会に参加して話をさせて頂いた。

jaws-ug-kyushu.doorkeeper.jp


ハイライト

AWS カルタ

その存在は聞いたことがあったが、初めて AWS カルタを体験した。

f:id:inokara:20151212234035p:plain

82 枚(SDK を含む各種 AWS サービスの数になる)の取り札から 16 枚獲得することが出来た。

人材サービス Amazon Mechanical Turk

カルタの取り札で AWS は人材もサービスとして提供していることを知った。

aws.amazon.com

主なサービスとして...

  • オンデマンドの労働力
  • 伸縮自在な労働力
  • 品質管理ツール

等...これには言葉が出なかった。

(ほぼ)マークダウンで書いたテキストをいい感じでスライドに仕上げてくれるアプリ

有償のアプリらしいけど、以下のアプリを教えて頂いた。

www.decksetapp.com

せっかく Keynote Remote を知った身としては悩みどころではあるが使ってみたい(これを利用することで良い資料が書けるとは限らないけど)。

濃い話

それぞれの登壇者が以下のようなネタを持ち寄って気が済むまで話をする感じであっと言う間に時間が過ぎた。

それぞれの発表資料は公開され次第、リンクを貼り付けたいと思う。

で、自分は Amazon Elasticsearch Service を使ってみた系の話をデモを含めて一時間程喋ってしまっていた。(以下は資料)

他の方のお話に比べるとちょっと薄っぺらい感じは否めなかったが、久し振りに人前で話する機会を頂けたり、上記のような濃い話が聞けてとても良い機会になった。企画して下さった藤崎さん、AWS カルタを作って下さった森田さん、会場の予約をして下さった安土さん、参加者の皆さん、お疲れ様でした。有難うございました。


次は...

何を話そうかな。

(ショロカレ 10 日目)S3 Event notification → Lamda → Amazon ES に挫折したので SQS → Amazon ES にしたメモ

ということで、これは「初老丸の独り Advent calendar 2015」の十日目の記事です。


tl;dr

S3 で動かしている静的サイトの access_log を S3 Event notification → SQS → Amazon ES という流れで可視化してみようと思ったのでメモ。本当は SQS ではなくて Lambda で挑戦したかったんだけど Lambda から IAM role で制御されている Amazon ES にポストするのに挫折してしまって SQS に頼ることにした。(何に挫折したかにも触れる)


メモ

構成

f:id:inokara:20151210214909p:plain

作ったもの

github.com

  • ログを正規表現で解析するのがつらかった(最終的にググったら同じことをされている方がいらっしゃったので拝借させていただいた)
  • Elasticsearch の Date Format の調整に苦労した(結局は ISO Format で放り込めた)

デモ

すでに上記のリポジトリを取得している前提で...

  • Mapping Template を放り込む
$ cd oreno-s3-access_log/es

#
# Amazon ES の Endpoint を修正する
#
$ vim regist-mapping-template.rb

#
# Amazon ES に Mapping Template を放り込む
#
$ ruby regist-mapping-template.rb
code: 200
msg: OK
body: {"acknowledged":true}
  • アプリケーションを Docker build する
$ cd oreno-s3-access_log/sqs

#
# Amazon ES のエンドポイント等を修正
#
$ vim Makefile
(snip)
DOCKER_RUN := docker run -d --name s3-access-log \
              --env ES_ENDPOINT="http://YOUR-ES-ENDPOINT:9200" \
              --env ES_PREFIX="YOUR_INDEX_PREFIX" \
              --env SQS_QUEUE_NAME="YOUR_QUEUE_NAME" \
              --env AWS_ACCESS_KEY_ID="AKxxxxxxxxxxxxxxxxxxxxxxxx" \
              --env AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
              --env AWS_REGION="YOUR_REGION" \
              -v /etc/localtime:/etc/localtime:ro s3-access-log
(snip)

#
# アプリケーションのデプロイ
#
$ make build

今回は ES_ENDPOINT には Amazon ES のエンドポイントを設定することになる。

  • アプリケーションを起動する
#
# docker run をラップしている
#
$ make run

#
# コンテナの軌道を確認
#
$ docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                    NAMES
5915f8932f0f        s3-access-log        "/usr/local/bin/super"   About an hour ago   Up About an hour                             s3-access-log
  • しばらく待つ
#
# Supervisord でアプリケーションを起動しているのでログを以下のように確認できる(キューを定期的にポーリングしている図)
#
$ docker exec s3-access-log /usr/local/bin/supervisorctl -c /app/supervisord.conf tail -f app
==> Press Ctrl-C to exit <==
21:56:34,261 INFO Calling sqs:receive_message with {u'QueueUrl': 'https://ap-northeast-1.queue.amazonaws.com/xxxxxxxxxxxx/s3-notification', 'MessageAttributeNames': ['*']}
2015-12-10 21:56:34,345 INFO Event does not exists...
2015-12-10 21:56:34,346 INFO Start polling...
2015-12-10 21:57:34,402 INFO Calling sqs:get_queue_url with {'QueueName': 's3-notification'}
2015-12-10 21:57:34,444 INFO Calling sqs:receive_message with {u'QueueUrl': 'https://ap-northeast-1.queue.amazonaws.com/xxxxxxxxxxxx/s3-notification', 'MessageAttributeNames': ['*']}
2015-12-10 21:57:34,525 INFO Event does not exists...
2015-12-10 21:57:34,526 INFO Start polling...
2015-12-10 21:58:34,585 INFO Calling sqs:get_queue_url with {'QueueName': 's3-notification'}
2015-12-10 21:58:34,626 INFO Calling sqs:receive_message with {u'QueueUrl': 'https://ap-northeast-1.queue.amazonaws.com/xxxxxxxxxxxx/s3-notification', 'MessageAttributeNames': ['*']}
2015-12-10 21:58:34,707 INFO Event does not exists...
2015-12-10 21:58:34,708 INFO Start polling...
  • Kibana を見てみる

f:id:inokara:20151210221603p:plain

ひとまず、Kibana 3 で見てみる。

Lambda → Amazon ES について何に挫折したのか

Lambda から Amazon ES にデータをポストしようとしたら以下のようなログが出た。

AuthorizationException: TransportError(403, u'{"Message":"User: anonymous is not authorized to perform: es:ESHttpPost on resource: arn:aws:es:ap-northeast-1:xxxxxxxxxxx:domain/oreno-es/s3_log-2015-12-08/s3_log"}')

なんや、権限が不足しとーとや、ほんじゃ、Lambda Function につけている IAM role に Amazon ES へのアクセスポリシーを付与すればよかろーもんって以下のようなポリシーを付与。

(snip)
    {
      "Effect": "Allow",
      "Action": "es:ESHttpPost",
      "Resource": "arn:aws:es:*:*:*"
    }
(snip)

付与しても状況は変わらず...。悩んで CloudWatch Logs の Amazon ES へのストリーム処理に利用する Node.js のコードを見てみると何やら Amazon ES のデータをポストする際に以下のような処理を行っていることが判明。

(snip)

function buildRequest(endpoint, body) {
    var endpointParts = endpoint.match(/^([^\.]+)\.?([^\.]*)\.?([^\.]*)\.amazonaws\.com$/);
    var region = endpointParts[2];
    var service = endpointParts[3];
    var datetime = (new Date()).toISOString().replace(/[:\-]|\.\d{3}/g, '');
    var date = datetime.substr(0, 8);
    var kDate = hmac('AWS4' + process.env.AWS_SECRET_ACCESS_KEY, date);
    var kRegion = hmac(kDate, region);
    var kService = hmac(kRegion, service);
    var kSigning = hmac(kService, 'aws4_request');
    
    var request = {
        host: endpoint,
        method: 'POST',
        path: '/_bulk',
        body: body,
        headers: { 
            'Content-Type': 'application/json',
            'Host': endpoint,
            'Content-Length': Buffer.byteLength(body),
            'X-Amz-Security-Token': process.env.AWS_SESSION_TOKEN,
            'X-Amz-Date': datetime
        }
    };

    var canonicalHeaders = Object.keys(request.headers)
        .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1; })
        .map(function(k) { return k.toLowerCase() + ':' + request.headers[k]; })
        .join('\n');

    var signedHeaders = Object.keys(request.headers)
        .map(function(k) { return k.toLowerCase(); })
        .sort()
        .join(';');

    var canonicalString = [
        request.method,
        request.path, '',
        canonicalHeaders, '',
        signedHeaders,
        hash(request.body, 'hex'),
    ].join('\n');

    var credentialString = [ date, region, service, 'aws4_request' ].join('/');

    var stringToSign = [
        'AWS4-HMAC-SHA256',
        datetime,
        credentialString,
        hash(canonicalString, 'hex')
    ] .join('\n');

    request.headers.Authorization = [
        'AWS4-HMAC-SHA256 Credential=' + process.env.AWS_ACCESS_KEY_ID + '/' + credentialString,
        'SignedHeaders=' + signedHeaders,
        'Signature=' + hmac(kSigning, stringToSign, 'hex')
    ].join(', ');

    return request;
}

(snip)

うう、これは...よく解らないということで挫折。

なお、Python から同じことを行う際には以下の記事が参考になることが判明。(有難うございます!)

qiita.com

どうやら、API リクエストを投げるのに Credential な情報を利用して署名を行ったリクエストヘッダが必要となるようで、以下ののドキュメントについて詳細に書かれている。

docs.aws.amazon.com

また、以下の記事も参考になった。(有難うございます!)

qiita.com

今まで CLISDK を何も考えずに使っていたのを反省するとともに次回の宿題にしたい。


以上

Amazon ES を触るというか、データを放り込んだりする方に時間を取られてしまっている...という位に Amazon ES は簡単に Elasticsearch を扱えるのは良いと思う。(ただし、ちゃんと運用しようとすると気を付けなければいけない点があると思う)

ということで、やっと、十日目に追いついた。

以上。

(ショロカレ 7 日目)2015 年のうちにやっておきたい Amazon Elasticsearch Service 入門(3)~CloudWatch Logs との連携~

これは「初老丸の独り Advent calendar 2015」の七日目の記事です。

tl;dr

引き続き、Amazon ES を使う。

CloudWatch Logs との連携を試してみる。


CloudWatch Logs との連携

連携の概要

  • CloudWatch Logs のログを直接というわけにはいかない
  • Subscription Filter を指定する
  • Lambda を介して Amazon ES に転送される

ざっくり手順

ざっくりとした手順は以下の通り。

  1. CloudWatch Logs の Log Group の作成
  2. Log Group に Log Stream を作成
  3. Log Stream にログが入ってくる...
  4. Log Group を選択して [Start Streaming to Amazon Elasticsearch Service] を選択
  5. Amazon ES のドメインを選択、Lambda Function 用の IAM role を作成(既存の role を選択するか新規作成する)
  6. Log Format を選択(今回は JSON を選ぶ)
  7. 確認して Start Streaming
  8. Amazon ES にインデックスが作成されていることを確認する

CloudWatch Logs にログを突っ込むまで

今回は fluentd を利用して Apacheアクセスログを CloudWatch Logs に放り込むことにする。

$ fluent-gem install fluent-plugin-cloudwatch-logs --no-ri --no-rdoc -V
$ cat fluentd.conf
<source>
  type tail
  path /tmp/log/apache2/access.log
  format apache2
  pos_file /tmp/apache.access.log.pos
  tag apache.access
</source>

<match apache.access>
  type copy
  <store>
    type stdout
  </store>
  <store>
    type cloudwatch_logs
    log_group_name apache-log
    log_stream_name apache-access-log
    auto_create_stream true
  </store>
</match>
$ export AWS_REGION="ap-northeast-1"
$ export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
$ export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_ACCESS_KEY"
$ fluentd -c fluentd.conf -l debug.log &

しばらくすると apache-access-log-demo にログが放り込まれてきている(はず)。

f:id:inokara:20151206191601p:plain

Amazon ES への転送設定開始

ロググループを指定してアクションから [Start Streaming to Amazon Elasticsearch Service] を選択する。

f:id:inokara:20151206185506p:plain

Amazon ES のドメインと Lambda Function 用の IAM role を作成

f:id:inokara:20151206185716p:plain

[Create new IAM role] を選択すると以下のような IAM role が作成される。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": [
        "arn:aws:logs:*:*:*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "es:ESHttpPost",
      "Resource": "arn:aws:es:*:*:*"
    }
  ]
}

Lambda function も以下のように自動的に作成されている。

f:id:inokara:20151206192137p:plain

ログフォーマットを指定

今回は Fluentd でシリアライズされたログが CloudWatch Logs に入っているのでそのまま JSON を選択。

f:id:inokara:20151206191634p:plain

確認して Start Streaming

f:id:inokara:20151206190715p:plain

念のために Subscription filter を AWS CLI で確認する。

$ aws logs describe-subscription-filters --log-group-name apache-log
{
    "subscriptionFilters": [
        {
            "filterName": "ElasticsearchStream_oreno-es",
            "destinationArn": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxxxxxx:function:LogsToElasticsearch_oreno-es",
            "creationTime": 1449390986860,
            "filterPattern": "",
            "logGroupName": "apache-log"
        }
    ]
}

Amazon ES でインデックスを確認

Streaming が開始するとインデックスが作成されている。

f:id:inokara:20151206191848p:plain

そして Kibana3 で

Amazon ES には Kibana4 と Kibana3 が同梱されているので、今回は Kibana3 でポチポチ。

f:id:inokara:20151206192346p:plain

久しぶりの Kibana3 は個人的には敷居が高かった...


以上

とりあえず 7 日目までキタけど、CloudWatch Logs との連携は思った以上に簡単だった。

(ショロカレ 5 日目)2015 年のうちにやっておきたい Amazon Elasticsearch Service 入門(2)~スナップショットとレストア~

これは「初老丸の独り Advent calendar 2015」の五日目の記事です。

tl;dr

昨日の続き。Amazon Elasticsearch Service では自動でスナップショットを作成してくれるが、手動でスナップショットを取ったり、レストアしたりしてみる。


手動でスナップショットを取得する

参考

docs.aws.amazon.com

ざっくり手順

  1. S3 Bucket 作る
  2. IAM role 作る
  3. IAM role にポリシーアタッチ
  4. スナップショットレジストリの登録
  5. スナップショット作成

以下の教材を利用して進める。

github.com

terraform で作る S3 Bucket と IAM role

  • 準備
$ git clone https://github.com/inokappa/oreno-soramame-amazon_es.git
$ cd oreno-soramame-amazon_es/snapshot/terraform
$ mv Makefile.sample Makefile
$ vim Makefile

# アクセスキーとシークレットアクセスキー、S3 バケットを環境に応じて設定する
PLAN         := terraform plan -var 'access_key=AKxxxxxxxxxxxxxxxxxxx' -var 'secret_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' -var 's3_bucket_name=your-bucket-name'
APPLY        := terraform apply -var 'access_key=AKxxxxxxxxxxxxxxxxxx' -var 'secret_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' -var 's3_bucket_name=your-bucket-name'
  • 作成
$ make tf-plan
$ make tf-apply

以下のように出力される。

aws_s3_bucket.oreno_bucket: Refreshing state... (ID: oreno-es-index-backup)
aws_iam_role.oreno_es_role: Refreshing state... (ID: oreno_es_role)
aws_iam_role_policy.oreno_es_policy: Refreshing state... (ID: oreno_es_role:oreno_es_policy)
aws_iam_instance_profile.oreno_es_profile: Refreshing state... (ID: oreno_es_profile)

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

  IAM Role  = arn:aws:iam::xxxxxxxxxxxx:role/oreno_es_role
  S3 bucket = your-bucket-name

スナップショット用のレジストリを登録する

  • コマンドを Docker build する
$ cd oreno-soramame-amazon_es/snapshot/
$ mv Makefile.sample Makefile
$ vim Makefile

#
# ES_HOST には Amazon ES のエンドポイント
# ES_SNAPSHOT にはスナップショットのレジストリ名
# ES_SNAPSHOT_NAME_PREFIX にはスナップショット名
#
DOCKER_BUILD        := docker build --no-cache=true -t oreno-es-index-snapshot .
DOCKER_RUN_REGIST   := docker run --rm --name oreno-es-index-snapshot --env "ES_HOST=search-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com" --env "ES_SNAPSHOT=your-snapshot" -v `pwd`:/tmp -v /etc/localtime:/etc/localtime:ro oreno-es-index-snapshot regist
DOCKER_RUN_CREATE   := docker run --rm --name oreno-es-index-snapshot --env "ES_HOST=search-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com" --env "ES_SNAPSHOT=your-snapshot" --env "ES_SNAPSHOT_NAME_PREFIX=your-snapshot" -v `pwd`:/tmp -v /etc/localtime:/etc/localtime:ro oreno-es-index-snapshot create
DOCKER_RUN_LIST     := docker run --rm --name oreno-es-index-snapshot --env "ES_HOST=search-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com" --env "ES_SNAPSHOT=your-snapshot" -v `pwd`:/tmp -v /etc/localtime:/etc/localtime:ro oreno-es-index-snapshot list

# Makefile を修正後に build を実行する
$ make build
$ make snapshot-regist

正常に作成されれば以下のように出力される。

code => 200
msg  => OK
body => {"acknowledged":true}

スナップショット作成

$ make snapshot-create

正常に作成されると以下のように出力される。

code => 200
msg  => OK
body => {"accepted":true}

スナップショット名は oreno-es-snapshot_${UNIX_TIME} となる。

スナップショット一覧を確認

$ make snapshot-list
code => 200
msg  => OK
body => {
  "snapshots" : [ {
    "snapshot" : "oreno-snapshot",
    "indices" : [ "pm25_2015-12-04", ".kibana-4", "pm25_2015-12-03" ],
    "state" : "SUCCESS",
    "start_time" : "2015-12-05T01:05:14.218Z",
    "start_time_in_millis" : 1449277514218,
    "end_time" : "2015-12-05T01:05:26.567Z",
    "end_time_in_millis" : 1449277526567,
    "duration_in_millis" : 12349,
    "failures" : [ ],
    "shards" : {
      "total" : 11,
      "failed" : 0,
      "successful" : 11
    }

(snip)

    "snapshot" : "oreno-es-snapshot_1449300324",
    "indices" : [ "pm25_2015-12-04", ".kibana-4", "pm25_2015-12-03" ],
    "state" : "SUCCESS",
    "start_time" : "2015-12-05T07:25:24.341Z",
    "start_time_in_millis" : 1449300324341,
    "end_time" : "2015-12-05T07:25:28.326Z",
    "end_time_in_millis" : 1449300328326,
    "duration_in_millis" : 3985,
    "failures" : [ ],
    "shards" : {
      "total" : 11,
      "failed" : 0,
      "successful" : 11
    }
  } ]
}

一応、S3 でも確認。

f:id:inokara:20151205180402p:plain


スナップショットからレストアする

新しいドメインクラスタを構築する

こちらを参考に新しいクラスタを構築してエンドポイント名を控えておく。

https://search-oreno-es-restore-xxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com

新しいドメインにもスナップショットレジストリを登録

$ docker run --rm \
>   --name oreno-es-index-snapshot \
>   --env "ES_HOST=search-oreno-es-restore-xxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com" \
>   --env "ES_SNAPSHOT=your-snapshot" \
>   -v `pwd`:/tmp -v /etc/localtime:/etc/localtime:ro \
>   oreno-es-index-snapshot regist
code => 200
msg  => OK
body => {"acknowledged":true}

ES_SNAPSHOT は先ほどスナップショットを作成した際に登録したスナップショット名に合わせておく。

レストア

元のインデックスを念のために確認。

$ curl -s -XGET https://search-oreno-es-xxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/_status | jq -r '.indices|keys[]'
.kibana-4
pm25_2015-12-03
pm25_2015-12-04

レストアする。

$ curl -XPOST 'https://search-oreno-es-restore-xxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/_snapshot/your-snapshot/oreno-es-snapshot_1449300324/_restore'
{"accepted":true}

レストアしたインデックスを確認する。

$ curl -s -XGET https://search-oreno-es-restore-xxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/_status | jq -r '.indices|keys[]'
.kibana-4
pm25_2015-12-03
pm25_2015-12-04

レストアできた。念のために Kibana でも確認してみる。

f:id:inokara:20151205180523p:plain


おまけ

ダメ元で試してみた elasticsarch-head が動かなかった

Elasticsearch を使う際には必ずと言っていいほどインストールしていた elasticsearch-headAmazon ES でも使いたいと思っていたら眠れなくなったのでダメ元で手元の環境にインストール済みの elasticsearch-headAmazon ES のエンドポイントを入れて試してみた。

f:id:inokara:20151205071440p:plain

やっぱり駄目だった。

たぶん、理由は以下の通り。

  • CORS になってしまう(No 'Access-Control-Allow-Origin' header is present on the requested resource. ってエラーが出る)
  • よく見ると Cluster APIStateAmazon ES ではサポートされていない

Cluster API を叩いて違いを見てみる。

  • 手元の Elasticsearch
$ curl -XGET 'http://localhost:9200/_cluster/state' | jq .
{
  "allocations": [],
  "cluster_name": "elasticsearch",
  "version": 34,
  "master_node": "iyzCUtV9R2yBr_0dniDSBg",
  "blocks": {},
  "nodes": {
    "iyzCUtV9R2yBr_0dniDSBg": {
      "attributes": {},

(snip)

        "unassigned_info": {
          "at": "2015-12-02T23:35:16.589Z",
          "reason": "CLUSTER_RECOVERED"
        },
        "index": "kibana-int",
        "shard": 2,
        "relocating_node": null,
        "node": null,
        "primary": false,
        "state": "UNASSIGNED"
      }
    ]
  }
}
$ curl -s -XGET 'https://search-oreno-es-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/_cluster/state' | jq .
{
  "Message": "Your request: '/_cluster/state' is not allowed."
}

はい、残念。

ちなみに、同じ Cluster API でも stats はサポートしている。

$ curl -s -XGET 'https://search-oreno-es-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/_cluster/stats' | jq .
{
  "nodes": {
    "plugins": [
      {
        "site": false,
        "jvm": true,
        "description": "Cloud AWS Plugin",
        "version": "${project.version}",
        "name": "cloud-aws"
      },

(snip)

  "status": "yellow",
  "cluster_name": "251150836600:oreno-es",
  "timestamp": 1449267842610
}

以上

引き続き、Amazon ES を触っていきたい。

(ショロカレ 4 日目)2015 年のうちにやっておきたい Amazon Elasticsearch Service 入門

これは「初老丸の独り Advent calendar 2015」の四日目の記事です。

tl;dr

ちゃんと Elasticsearch そのものをを使えていないこともあるが、Amazon Elasticsearch Service に入門したのでメモ。


うんちく

参考

aws.typepad.com

aws.amazon.com

Elasticsearch とは

speakerdeck.com

上記の資料の三ページ目に簡潔に纏まっているのが解りやすいが、抜粋させて頂く。

Amazon Elasticserch Service とは

上記の Elasticsearch が AWS 上にマネージドサービスとして提供されている、従来 Elasticsearch は AWS のサービスと間違えられることがあったか無かったは、今となっては分からないものの名実ともに AWS のサービスとなったことでより手軽に利用できるようになったのではと考えている。

で、Amazon Elasticsearch Service(以下、Amazon ES)の特徴としては...

  • 簡単デプロイ
  • 管理(可用性の確保、パッチ管理、障害検出、ノードの交換、バックアップ、モニタリング等)は AWS にある程度お任せ
  • CloudWatch と連携した高いスケーラビリティ
  • Kibana 入り(はじめから Kibana 入ってます)
  • IAM ポリシーによって安全にクラスタにアクセス出来る

Amazon ES のサポートされている API

サポートされている API に関しては以下に記載されている。

一般的に利用する API はサポートされているように見える。ただし、プラグイン系のエンドポイントについてはサポートされているプラグインに依存するので事前に確認しておく必要がありそう。

Amazon ES のサポートされているプラグイン

以下のプラグインが導入済みとのこと。

オープンソースプラグインをどのようにインストールするのかドキュメントをザクッとななめ読みしたところ読み取ることができなかった...もし、その方法があるなら教えて欲しい...。

Amazon ES のスナップショット

  • 自動的にスナップショットを取得(スナップショットは時間指定可能)
  • 14 日間保存される
  • Elasticsearch の Snapshot API を利用して S3 バケットに保存することが可能
  • S3 に保存されたスナップショットを利用して Amazon ES や自分で管理している Elasticsearch へレストアすることができる

で、なんぼ?

以下の要素で課金される。

詳細はこちらの料金表をご覧ください...。

お楽しみの無料枠は以下の通り。

AWS 無料利用枠をご利用のお客様は、Amazon Elasticsearch Service で単一アベイラビリティーゾーンの t2.micro.elasticsearch インスタンス最大 750 時間/月、およびオプションの Amazon EBS ストレージ (マグネティックまたは汎用) 10 GB/月を利用できます。

とのことなので、今回はこの無料枠の範囲で試してみたい。


Amazon ES クラスタ構築入門

まずはドメインを作るところから始める

Amazon Elasticsearch Service(以下、Amazon ES)はクラスタドメインという名前で管理する。1 クラスタ = 1 ドメインと覚えておくことにする。

f:id:inokara:20151203235252p:plain

Elasticsearch インスタンスタイプやドメインのノード数、ストレージを設定する

f:id:inokara:20151203235342p:plain

インスタンスタイプは以下の通り。(※こちらより抜粋。)

  • T2 開発およびテスト(dedicated masterノードにも適してる)
  • R3 Read-heavyもしくは複雑なクエリ(例えばnested aggregations)
  • I2 High-write、Large-scaleなデータの格納
  • M3 一般的なreadとwrite

また、Enable dedicated master と Enable zone awareness については以下の通り。

  • Enable dedicated masterクラスタ管理用のマスタノードを構築する(マスタノードにはデータは保持せずクラスタ管理のみを受け持つ、最低三つのマスタノードの指定を推奨、スプリットブレインを回避する為にマスタノードは常に奇数を設定すること)
  • Enable zone awareness はリージョン内の複数の AZ にノードを分散して構築する

f:id:inokara:20151203235404p:plain

  • T2 シリーズ以外は Instance Store を選択することができる
  • EBS は Magnetic / GP2 / PIOPS から選択することが出来る
  • EBS のサイズは最低 10GB から最大 35GB まで指定することが出来る
  • スナップショットの時間を指定する(今回は特に指定せずデフォルトのまま)

アクセスポリシーの設定

IAM ユーザーや IP アドレスを設定してアクセスのポリシーを設定する。

f:id:inokara:20151204000643p:plain

今回は接続元の IP を設定するので以下のように IP アドレスを入力する。

f:id:inokara:20151204093231p:plain

IP アドレスを入力すると以下のような JSON が自動生成される。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "es:*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "xxx.xxx.xx.xxx"
          ]
        }
      },
      "Resource": "arn:aws:es:ap-northeast-1:12345678901234567890:domain/oreno-es/*"
    }
  ]
}

設定を確認してクラスタを作成する

最後に設定を確認してクラスタの作成を開始する。

f:id:inokara:20151204000933p:plain

10 分程お待ちください...

f:id:inokara:20151204000954p:plain

クラスタ作成完了

10 分後....クラスタの出来上がり。

f:id:inokara:20151204002013p:plain

エンドポイントや Domain ARN や Kibana の URL も合わせて表示されている。

Kibana にアクセスする

Kibana にアクセスしてみる。

f:id:inokara:20151204002548p:plain

当然、インデックスが無いので何の面白みも無い。

エンドポイントにアクセスする

一応 curl を利用してエンドポイントにもアクセスする。

$ curl https://search-oreno-es-xxxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/
{
  "status" : 200,
  "name" : "Steel Spider",
  "cluster_name" : "12345678901234567890:oreno-es",
  "version" : {
    "number" : "1.5.2",
    "build_hash" : "62ff9868b4c8a0c45860bebb259e21980778ab1c",
    "build_timestamp" : "2015-04-27T09:21:06Z",
    "build_snapshot" : false,
    "lucene_version" : "4.10.4"
  },
  "tagline" : "You Know, for Search"
}

Amazon ES をちょっと使ってみる

PM2.5 のデータを突っ込んでみる

以下を利用して Amazon ES に昨日の九州地方の各観測地点の PM2.5 データを突っ込んでみる。

github.com

詳しい使い方は README を。

突っ込んだら Kibana で可視化する

  • まずは Index の設定

f:id:inokara:20151204090648p:plain

  • 次に Search オブジェクトを作る

観測地点毎に見たいので 205 地点分の Search オブジェクトを一気に作成。

$ cd kibana
$ kibana_search.rb.sample kibana_search.rb
$ sed -i 's/YOUR_AMAZON_ES_ENDPOINT/search-xxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/g' kibana_search.rb
$ ruby kibana_search.rb
  • そして Visualize

Visualize オブジェクトも 205 地点分を一気に作成。

$ cd kibana
$ mv kibana_visualize.rb.sample kibana_visualize.rb
$ sed -i 's/YOUR_AMAZON_ES_ENDPOINT/search-xxxxxxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/g' kibana_visualize.rb
$ ruby kibana_visualize.rb
  • 最後に Dashiboard

ポチポチ...

f:id:inokara:20151204091823p:plain

一応、完成。

f:id:inokara:20151204091841p:plain

PM2.5 の観測データが無い観測地点もあるので歯抜けな状態になっているのはすいません。


ということで

Amazon ES は...

  • はじめから Kibana も付いてる、簡単セットアップ Elasticsearch
  • お手軽に運用出来るかもしれない Elasticsearch
  • AWS サービスともシームレスに連携出来そうな Elasticsearch

だと思うので引き続き触ってみたいと思う。

次回は...

以下をやってみる。

  • S3 へのスナップショット、レストア
  • CloudWatch Logs との連携
  • Fluentd との連携

ということで、2015 年のうちにやっておきたい Amazon Elasticsearch Service 入門の第一回目でした。

(超メモ)Elastic Beanstalk の Worker Tier について(cron っぽいことをやってみる)

tl;dr

Elastic Beanstalk の Worker Tier と Worker Tier で Cron っぽいことを試してみたメモ。


参考

www.slideshare.net


Worker Tier について

その前に Elastic Beanstalk について

  • 読み方的には「エラスティック・ビーン・ストーク」で「ビーンズ・トーク」では無い(重要)
  • PaaS(アプリケーション以下の環境は AWS がマネジメントしてくれる)
  • 各種言語に対応
  • ELB と AutoScaling や RDS だって利用可能
  • Web Tier(今回は触れない) と Worker Tier がある

Worker Tier

  • SQS キューに書き込むことができる AWS サービスのバックグラウンド処理タスクを実行する
  • aws-sqsd が SQS のキューを監視、キューにメッセージが届いたらローカルホストのアプリケーションにアクセスする(下図参照)

http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/images/aeb-messageflow-worker.png

(出典:Worker Environments

  • Worker Tier を作成すると 2 つのキューが作成される(Worker Queue と DeadLetterr Queue)
  • DeadLetterr Queue を設けることで正常に処理出来なかったキューを後から確認することが出来る

トライ

IAM role を作る

Worker Tier を利用する場合には EC2 から SQS 等の各種 AWS リソースにアクセスする為の IAM role を作成する必要があるので、今回はマネジメントコンソールから Worker Tier を作成した際に自動で作成してくれる以下の IAM role を流用する。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "QueueAccess",
      "Action": [
        "sqs:ChangeMessageVisibility",
        "sqs:DeleteMessage",
        "sqs:ReceiveMessage",
        "sqs:SendMessage"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Sid": "MetricsAccess",
      "Action": [
        "cloudwatch:PutMetricData"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Sid": "BucketAccess",
      "Action": [
        "s3:Get*",
        "s3:List*",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::elasticbeanstalk-*-xxxxxxxxxxxx/*",
        "arn:aws:s3:::elasticbeanstalk-*-xxxxxxxxxxxx-*/*"
      ]
    },
    {
      "Sid": "DynamoPeriodicTasks",
      "Action": [
        "dynamodb:BatchGetItem",
        "dynamodb:BatchWriteItem",
        "dynamodb:DeleteItem",
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:dynamodb:*:xxxxxxxxxxxx:table/*-stack-AWSEBWorkerCronLeaderRegistry*"
      ]
    }
  ]
}

この IAM role を aws-elasticbeanstalk-ec2-worker-role という名前で保存しておく。必要に応じて他の AWS リソースへのアクセスポリシーも適宜追加する。

ebcli で新しいアプリケーション

ebcli を利用して作業を進める。ebcli についてはこちらのドキュメントを参考に進める。

% eb init

Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-southeast-1 : Asia Pacific (Singapore)
7) ap-southeast-2 : Asia Pacific (Sydney)
8) ap-northeast-1 : Asia Pacific (Tokyo)
9) sa-east-1 : South America (Sao Paulo)
10) cn-north-1 : China (Beijing)
(default is 3): 8

Select an application to use
1) oreno-worker
2) eb-sinatra
3) [ Create new Application ]
(default is 3): 3

Enter Application Name
(default is "oreno-eb-sinatra"): oreno-eb-sinatra-worker
Application oreno-eb-sinatra-worker has been created.

It appears you are using Ruby. Is this correct?
(y/n): y

Select a platform version.
1) Ruby 2.2 (Puma)
2) Ruby 2.1 (Puma)
3) Ruby 2.0 (Puma)
4) Ruby 2.2 (Passenger Standalone)
5) Ruby 2.1 (Passenger Standalone)
6) Ruby 2.0 (Passenger Standalone)
7) Ruby 1.9.3
(default is 1): 1
Do you want to set up SSH for your instances?
(y/n): y

Select a keypair.
1) key1
2) key2
3) key3
4) key4
5) [ Create new KeyPair ]
(default is 5): 3

雑な Worker アプリケーション

Sinatra を使って / に HTTP アクセスすると /tmp/sinatra.log に Hello World! とリクエストヘッダをダンプするだけの超簡単な Worker アプリケーションを作ってみる。

  • Gemfile
source 'http://rubygems.org'
gem 'sinatra'
  • config.ru
require './helloworld'
run Sinatra::Application
  • helloworld.rb
require 'sinatra'
require 'logger'

logger = Logger.new('/tmp/sinatra.log')

post '/' do
  logger.info "Hello World!"
  http_headers = request.env.select { |k, v| k.start_with?('HTTP_')}
  logger.info http_headers
end

ebcli で Worker Tier を起動する

ebcli で Worker Tier を起動するには --tier worker オプションを利用する。また、合わせて --instance_profile で IAM role を指定する。

% eb create --tier worker --instance_profile aws-elasticbeanstalk-ec2-worker-role
Enter Environment Name
(default is oreno-eb-sinatra-worke): oreno-eb-sinatra-worker
WARNING: You have uncommitted changes.
Creating application version archive "app-52ef-151129_122719".
Uploading oreno-eb-sinatra-worker/app-52ef-151129_122719.zip to S3. This may take a while.
Upload Complete.
Environment details for: oreno-eb-sinatra-worker
  Application name: oreno-eb-sinatra-worker
  Region: ap-northeast-1
  Deployed Version: app-52ef-151129_122719
  Environment ID: e-xxxxxxxxxx
  Platform: 64bit Amazon Linux 2015.09 v2.0.4 running Ruby 2.2 (Puma)
  Tier: Worker-SQS/HTTP
  CNAME: UNKNOWN
  Updated: 2015-11-29 03:27:23.689000+00:00
Printing Status:
INFO: createEnvironment is starting.
INFO: Using elasticbeanstalk-ap-northeast-1-xxxxxxxxxxxx as Amazon S3 storage bucket for environment data.
INFO: Environment health has transitioned to Pending. There are no instances.
INFO: Created security group named: awseb-e-xxxxxxxxxx-stack-AWSEBSecurityGroup-XXXXXXXXXXXXXX
INFO: Created Auto Scaling launch configuration named: awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingLaunchConfiguration-XXXXXXXXXXXXXX
INFO: Added instance [i-xxxxxxx] to your environment.
INFO: Created Auto Scaling group named: awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingGroup-XXXXXXXXXXXXXX
INFO: Waiting for EC2 instances to launch. This may take a few minutes.
INFO: Created Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:xxxxxxxxxxxx:scalingPolicy:65f129b5-91f6-4ef7-afc6-ca0cc21cbad2:autoScalingGroupName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingGroup-XXXXXXXXXXXXXX:policyName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingScaleUpPolicy-XXXXXXXXXXXXXX
INFO: Created Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:xxxxxxxxxxxx:scalingPolicy:118024ed-e434-45a3-9aa2-cdda3d60aa11:autoScalingGroupName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingGroup-XXXXXXXXXXXXXX:policyName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingScaleDownPolicy-XXXXXXXXXXXXXX
INFO: Created CloudWatch alarm named: awseb-e-xxxxxxxxxx-stack-AWSEBCloudwatchAlarmHigh-XXXXXXXXXXXXXX
INFO: Created CloudWatch alarm named: awseb-e-xxxxxxxxxx-stack-AWSEBCloudwatchAlarmLow-XXXXXXXXXXXXXX
INFO: Successfully loaded 1 scheduled tasks from cron.yaml.
INFO: Environment health has transitioned from Pending to Ok.
INFO: Successfully launched environment: oreno-eb-sinatra-worker

Ctrl + c でプロンプトに戻ることが出来る。その間もインスタンスの作成等の環境構築が進行している。その確認は eb statsu で確認することが出来る。(以下の状態はインスタンスの起動中の為 status: LaunchingHealth: Grey となっている。また、Tier: Worker-SQS/HTTP となっており Worker として環境が起動していることが判る。 )

% eb status
Environment details for: oreno-eb-sinatra-worker
  Application name: oreno-eb-sinatra-worker
  Region: ap-northeast-1
  Deployed Version: None
  Environment ID: e-wruk4dmtq8
  Platform: 64bit Amazon Linux 2015.09 v2.0.4 running Ruby 2.2 (Puma)
  Tier: Worker-SQS/HTTP
  CNAME: UNKNOWN
  Updated: 2015-11-29 13:54:04.618000+00:00
  Status: Launching
  Health: Grey

暫くすると...以下のように StatusHealth の状態が変わって必要な環境の構築が終了となる。

% eb status
Environment details for: oreno-eb-sinatra-worker
  Application name: oreno-eb-sinatra-worker
  Region: ap-northeast-1
  Deployed Version: app-52ef-151129_225352
  Environment ID: e-wruk4dmtq8
  Platform: 64bit Amazon Linux 2015.09 v2.0.4 running Ruby 2.2 (Puma)
  Tier: Worker-SQS/HTTP
  CNAME: UNKNOWN
  Updated: 2015-11-29 13:56:58.315000+00:00
  Status: Launching
  Health: Green

以下のように SQS のキューも作成されている。

f:id:inokara:20151129221251p:plain

おお。

eb sshインスタンスにログイン

% eb ssh
INFO: Attempting to open port 22.
INFO: SSH port 22 open.
Last login: Sun Nov 29 03:33:32 2015 from xxx.xxx.xxx.jp
 _____ _           _   _      ____                       _        _ _
| ____| | __ _ ___| |_(_) ___| __ )  ___  __ _ _ __  ___| |_ __ _| | | __
|  _| | |/ _` / __| __| |/ __|  _ \ / _ \/ _` | '_ \/ __| __/ _` | | |/ /
| |___| | (_| \__ \ |_| | (__| |_) |  __/ (_| | | | \__ \ || (_| | |   <
|_____|_|\__,_|___/\__|_|\___|____/ \___|\__,_|_| |_|___/\__\__,_|_|_|\_\
                                       Amazon Linux AMI

This EC2 instance is managed by AWS Elastic Beanstalk. Changes made via SSH 
WILL BE LOST if the instance is replaced by auto-scaling. For more information 
on customizing your Elastic Beanstalk environment, see our documentation here: 
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[ec2-user@ip-xx-xxx-xxx-xxx ~]$ 

手動でキューにメッセージを送る

f:id:inokara:20151129220325p:plain

以下のようにアプリケーションのログが出力されている。

$ cat /tmp/sinatra.log 
# Logfile created on 2015-11-29 03:31:05 +0000 by logger.rb/47272
I, [2015-11-29T03:34:25.483217 #2023]  INFO -- : Hello World!
I, [2015-11-29T03:34:25.483344 #2023]  INFO -- : {"HTTP_VERSION"=>"HTTP/1.0", "HTTP_HOST"=>"localhost", "HTTP_X_FORWARDED_FOR"=>"127.0.0.1", "HTTP_CONNECTION"=>"close", "HTTP_USER_AGENT"=>"aws-sqsd/2.0", "HTTP_X_AWS_SQSD_MSGID"=>"ff89eb93-b3cc-46e2-860f-2b6a500b32b3", "HTTP_X_AWS_SQSD_RECEIVE_COUNT"=>"1", "HTTP_X_AWS_SQSD_FIRST_RECEIVED_AT"=>"2015-11-29T03:34:25Z", "HTTP_X_AWS_SQSD_SENT_AT"=>"2015-11-29T03:34:25Z", "HTTP_X_AWS_SQSD_QUEUE"=>"awseb-e-xxxxxxxxxx-stack-AWSEBWorkerQueue-XXXXXXXXXXXXXX", "HTTP_X_AWS_SQSD_PATH"=>"", "HTTP_X_AWS_SQSD_SENDER_ID"=>"xxxxxxxxxxxx"}

cron っぽいことをする

こちらこちらを参考にして cron っぽいことをやってみたいので、アプリケーションのルートディレクトリに cron.yaml を以下のように作成する。

version: 1
cron:
 - name: "test"
   url: "/"
   schedule: "*/5 * * * *"

上記の設定で aws-sqsd が 5 分毎に / に HTTP アクセスする。

作成したらアプリケーションをデプロイする。

% ls -l
total 32
-rw-r--r--  1 kappa  staff   43 Nov 28 19:30 Gemfile
-rw-r--r--  1 kappa  staff   48 Nov 28 19:29 config.ru
-rw-r--r--  1 kappa  staff   72 Nov 29 11:42 cron.yaml
drwxr-xr-x  3 kappa  staff  102 Nov 29 11:43 elasticbeanstalk
-rw-r--r--  1 kappa  staff  218 Nov 29 01:13 helloworld.rb
% git add .
% git commit -m "add cron.yaml"
% eb deploy
WARNING: You have uncommitted changes.
Creating application version archive "app-52ef-151129_221803".
Uploading oreno-eb-sinatra-worker/app-52ef-151129_221803.zip to S3. This may take a while.
Upload Complete.
INFO: Environment update is starting.                               
INFO: Deploying new version to instance(s).                         
INFO: Successfully loaded 1 scheduled tasks from cron.yaml.         
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.

インスタンスにログインして確認する。

$ tail -f /tmp/sinatra.log
I, [2015-11-29T02:49:59.908826 #2708]  INFO -- : Hello World!
I, [2015-11-29T02:49:59.908955 #2708]  INFO -- : {"HTTP_VERSION"=>"HTTP/1.0", "HTTP_HOST"=>"localhost", "HTTP_X_FORWARDED_FOR"=>"127.0.0.1", "HTTP_CONNECTION"=>"close", "HTTP_USER_AGENT"=>"aws-sqsd/2.0", "HTTP_X_AWS_SQSD_MSGID"=>"3422e8f4-7023-4bf0-89e7-db882fdf9618", "HTTP_X_AWS_SQSD_RECEIVE_COUNT"=>"1", "HTTP_X_AWS_SQSD_FIRST_RECEIVED_AT"=>"2015-11-29T02:49:59Z", "HTTP_X_AWS_SQSD_SENT_AT"=>"2015-11-29T02:49:59Z", "HTTP_X_AWS_SQSD_QUEUE"=>"awseb-e-qmjp6upame-stack-AWSEBWorkerQueue-XXXXXXXXXXXXX", "HTTP_X_AWS_SQSD_PATH"=>"/", "HTTP_X_AWS_SQSD_SENDER_ID"=>"XXXXXXXXXXXXXXXXXXXXXX:i-xxxxxxxx", "HTTP_X_AWS_SQSD_SCHEDULED_AT"=>"2015-11-29T02:50:00Z", "HTTP_X_AWS_SQSD_TASKNAME"=>"test"}
I, [2015-11-29T02:54:59.878897 #2708]  INFO -- : Hello World!
I, [2015-11-29T02:54:59.879049 #2708]  INFO -- : {"HTTP_VERSION"=>"HTTP/1.0", "HTTP_HOST"=>"localhost", "HTTP_X_FORWARDED_FOR"=>"127.0.0.1", "HTTP_CONNECTION"=>"close", "HTTP_USER_AGENT"=>"aws-sqsd/2.0", "HTTP_X_AWS_SQSD_MSGID"=>"3fde7c59-7535-4ec0-9567-374a90a24eb7", "HTTP_X_AWS_SQSD_RECEIVE_COUNT"=>"1", "HTTP_X_AWS_SQSD_FIRST_RECEIVED_AT"=>"2015-11-29T02:54:59Z", "HTTP_X_AWS_SQSD_SENT_AT"=>"2015-11-29T02:54:59Z", "HTTP_X_AWS_SQSD_QUEUE"=>"awseb-e-qmjp6upame-stack-AWSEBWorkerQueue-XXXXXXXXXXXXX", "HTTP_X_AWS_SQSD_PATH"=>"/", "HTTP_X_AWS_SQSD_SENDER_ID"=>"XXXXXXXXXXXXXXXXXXXXXX:i-xxxxxxxx", "HTTP_X_AWS_SQSD_SCHEDULED_AT"=>"2015-11-29T02:55:00Z", "HTTP_X_AWS_SQSD_TASKNAME"=>"test"}

タイムスタンプを見ると 5 分ごとにアクセスが発生していることが判る。

あとかたづけ

EC2 や SQS もまとめてターミネート。

% eb terminate
The environment "oreno-eb-sinatra-worker" and all associated instances will be terminated.
To confirm, type the environment name: oreno-eb-sinatra-worker
INFO: terminateEnvironment is starting.
INFO: Deleted CloudWatch alarm named: awseb-e-xxxxxxxxxx-stack-AWSEBCloudwatchAlarmLow-XXXXXXXXXXXXX 
INFO: Deleted CloudWatch alarm named: awseb-e-xxxxxxxxxx-stack-AWSEBCloudwatchAlarmHigh-XXXXXXXXXXXXX 
INFO: Deleted Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:XXXXXXXXXXXX:scalingPolicy:65f129b5-91f6-4ef7-afc6-ca0cc21cbad2:autoScalingGroupName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingGroup-XXXXXXXXXXXXX:policyName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingScaleUpPolicy-XXXXXXXXXXXXX
INFO: Deleted Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:XXXXXXXXXXXX:scalingPolicy:118024ed-e434-45a3-9aa2-cdda3d60aa11:autoScalingGroupName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingGroup-XXXXXXXXXXXXX:policyName/awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingScaleDownPolicy-XXXXXXXXXXXXXINFO: Waiting for EC2 instances to terminate. This may take a few minutes.
INFO: Deleted Auto Scaling group named: awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingGroup-XXXXXXXXXXXXXINFO: Deleted Auto Scaling launch configuration named: awseb-e-xxxxxxxxxx-stack-AWSEBAutoScalingLaunchConfiguration-XXXXXXXXXXXXX
INFO: Deleted security group named: awseb-e-xxxxxxxxxx-stack-AWSEBSecurityGroup-XXXXXXXXXXXXX
INFO: Removed instance [i-xxxxxxxx] from your environment.
INFO: Deleting SNS topic for environment oreno-eb-sinatra-worker.
INFO: terminateEnvironment completed successfully.

以上

Elastic Beanstalk を使って Cron っぽい動作は cron.yaml を置くだけで簡単に実装出来ることが解った。Lambda と単純に比較出来るわけでもなく、サーバレスアーキテクチャでも無いが、既存のアプリケーションを手軽にバッチ処理として利用する面では Elastic Beanstalk の Worker Tier も選択肢の一つになると考えている。(※実際にプロダクション環境等で利用する場合にはアプリケーションのエラー処理、タイムアウト処理等を実装する必要がある)

以上。

(超メモ)AWS イオット革命...もとい、AWS IoT をちょっと触ってみる

おはげようございます。「IT 革命(アイティー革命)」を「イット革命」と呼ばれた方がいらっしゃったことをリスペクトします。

追記(2016/01/19)

AWS Iot は昨年の 12 月にベータが取れて正式リリースとなっております。

aws.typepad.com

tl;dr

2015 年の re:Invent で満を持して発表された AWS イヲット、もとい、AWS IoT をちょっと触ってみる。

aws.typepad.com


AWS IoT とは

詳しくは...

ドキュメントを。

AWS IoT はベータ版での提供となっており、今後も仕様の変更等が行われることが予想されるので実際の利用に際しては上記のドキュメントを参考にされたし

提供するサービスをざっくり三行 + α で

  • AWS が提供するマネージド MQTT ブローカー(但し、MQTT には提供されない Shadow が実装されている、又、HTTP 1.1 もサポート)
  • AWS IoT が提供する Rule にもとづいて AWS の各サービス(全てのサービスに対応しているわけではないが...)との連携
  • ポリシーによるクライアントの認可と X.509 証明書ベースの認証

その他、詳細については AWS IoT の仕組み と以下の資料を。

www.slideshare.net

自分なりの理解を手書き絵で

ドキュメント読みながら AWS IoT の構成要素を手書きで絵にしてみた。

f:id:inokara:20151121235521p:plain

構成要素としては...

  • Thing「モノ」、自分が知ってる名詞ではラズパイ、エヂソン、IoT 機器と呼ばれるモノ
  • AWS IoT のメッセージブローカー(MQTT 又はHTTP 1.1 で Thing からのメッセージを送受信可能)
  • 証明書とポリシー(Thing からメッセージブローカーに対する認可、認証)
  • ルール(メッセージブローカーから AWS 各サービスへのルーティング)
  • Shadow(デバイスがオフラインでもメッセージ受信可能)
  • Registry(デバイスの管理)

それぞれの機能や用途については引き続き調べたい。

で、なんぼ?

AWS IoT に掛かる費用の計算は以下を利用する。詳細はこちらを。

  • モノから AWS IoT に送信したメッセージ数
  • AWS IoT からモノに送信したメッセージ数

尚、AWS IoT と連携が可能な AWS サービスへの通信コストは発生しないとのこと。また、小遣い制の自分には嬉しい無料は以下の通り。

  • 毎月 25 万メッセージ
  • 12 ヶ月

ありがたや、ありがたや。


俺の手元にはラズパイがある

ラズパイ

f:id:inokara:20151122081024p:plain

今回は温度センサーとかは利用しない。

ということで

手元のラズパイを AWS IoT に登録してみる手順は以下の通り。

  1. ラズパイを登録
  2. ルールを定義
  3. ポリシーを定義
  4. 証明書を発行、ポリシーをアタッチ
  5. 証明書にラズパイをアタッチ
  6. 証明書をアクティベート
  7. 証明書をラズパイにダウンロード
  8. ルート証明書もラズパイにダウンロード
  9. ルールを定義

最終的には以下の記事を参考にさせて頂いて(有難うございます)俺のラズパイから Ruby を利用してメッセージを AWS IoT を経由して SNS に送信して最終的にはメールにメッセージを飛ばしたい。

qiita.com

以下、AWS CLI でサクッと試されている方が多い中、マネジメントコンソールをポチポチでやってみたいと思う。

ラズパイを登録

必須項目はモノの名前だけ。

f:id:inokara:20151122010254p:plain

ルールを定義

f:id:inokara:20151122010400p:plain

  • Name を入力し、AttributeTopic Filter を入力する。Topic Filter には MQTT のトピック名を指定する
  • Choose Action には対応している AWS 各サービスのアクションを選択する(今回は SNS を利用したが、SNS の Topic ARN やポリシー等を一緒に作成することが出来る)

ポリシーを定義

f:id:inokara:20151122010641p:plain

  • AWS IoT の IAM ポリシーを指定する(イメージ)
  • Action でブローカーに対する細かいアクションを定義することが出来る

証明書を発行してラズパイとポリシーにアタッチ、アクティベート

証明書を発行。発行時点では INACTIVE となっている。

f:id:inokara:20151122011040p:plain

証明書にポリシーをアタッチ。

f:id:inokara:20151122011121p:plain

証明書にラズパイをアタッチ。

f:id:inokara:20151122011135p:plain

証明書をアクティベート。

f:id:inokara:20151122011325p:plain

尚、ポリシーのアタッチ、アクティベートについては以下のように証明書にチェックを入れて Action プルダウンより選択する。

f:id:inokara:20151122011636p:plain

証明書をラズパイに設置

何らかの方法で証明書ファイルをダウンロードしてラズパイに設置する。

f:id:inokara:20151122012100p:plain

ラズパイに適当にディレクトリをこさえておく。

pi@raspberrypi ~ $ mkdir path/to/iot
pi@raspberrypi ~ $ cd path/to/iot
pi@raspberrypi ~/dev/iot $ ls -l
total 24
-rw-r----- 1 pi pi 1220 Nov 22 00:45 xxxxxxxxxxx-certificate.pem.crt
-rw-r----- 1 pi pi 1675 Nov 22 00:45 xxxxxxxxxxx-private.pem.key
-rw-r----- 1 pi pi  451 Nov 22 00:45 xxxxxxxxxxx-public.pem.key

ルート証明書もラズパイに設置

以下のようにルート証明書を取得する。

pi@raspberrypi ~ $ mkdir path/to/iot
pi@raspberrypi ~ $ cd path/to/iot
pi@raspberrypi ~ $ wget https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem -O rootCA.pem

メッセージを送信

以下のようなスクリプトを用意してメッセージを送信。

require "mqtt"

MQTT::Client.connect(
  host: "xxxxxxxxxxxxxxxxxxxxx.iot.ap-northeast-1.amazonaws.com",
  port: 8883,
  ssl: true,
  cert_file: "xxxxxxxxxx-certificate.pem.crt",
  key_file: "xxxxxxxxxx-private.pem.key",
  ca_file: "rootCA.pem"
) do |client|
  client.publish("oreno/iot", "Hello Oreno IoT!")
end

以下のように AWS IoT がメッセージを受信、ルールに基いて SNS に転送、SNS から Subscribe 先のメールアドレスに送信されて受信を確認できた。

f:id:inokara:20151122012652p:plain


以上

今回は Ruby を利用したが、AWS IoT の醍醐味の一つは AWS IoT SDK が提供されている点で AWS IoT を介して SDK で開発したアプリケーションを搭載したモノと AWS の各種サービスが手軽に連携出来るのが嬉しい点なのかなと考えている。現時点ではベータ版での提供ということもあるのか連携出来るサービスが限られている感があるが、今後、Amazon Elasticsearch Service 等との連携も出来るようになるのかしら...。

ということで、電源入れっぱなしでホコリを被っていたラズパイが利用出来て良かった、良かった。