aws-sam-localだって!?これは試さざるを得ない!

2017-08-11にaws-sam-localのベータ版がリリースされました。
単に「早速試したで!」と言う記事を書いても良かったのですが、少し趣向を変えてサーバレス界隈の開発環境のこれまでの推移を語った上で、aws-sam-localの使ってみた感想もお話しようかと思います。

サーバレス開発環境の今昔

サーバレス自体がかなり最近になって生まれた風潮なので昔とか言うのも問題はあるかと思いますが、とにかくサーバレスなるものの開発環境について私にわかる範囲でお話しようと思います。誤りや不正確な点については編集リクエストやコメントを頂けると幸いです。

なお、サーバレスという言葉は一般的な名詞ですが、私がAWS上でしかサーバレスに触れていないため、AzureやGCPなどには触れず、もっぱらLambdaの話になってしまうことをあらかじめご了承ください。

Lambdaのデプロイは辛かった

Lambdaの基本的なデプロイ方法はZIPで固めてアップロードです。
直接ZIPをLambdaに送るか、あらかじめS3に置いておいてLambdaにはそのURLを教えるかといった選択肢はありましたが、手動でZIPに固めてAWSに送るという手順は不可避でした。なんかもうすでに辛い。

さらに言うとLambdaに送りつけられるのはLambdaで実行するコードだけ。性質上Lambdaは単体で使われることはほとんどなく、他のサービスと連携することがほとんどなのにその辺は自分で管理するしかありませんでした。辛い。

CloudFormationで管理することは可能でしたが、CloudFormationテンプレートを書くのがかなりダルいことと、CloudFormationの更新とZIPのアップロードを別途行う必要があって手順が煩雑化しやすいため、「もうええわ」と手動管理してることが多かったと思われます。

また、ローカル環境で実行するには一工夫必要でした。

颯爽登場!Serverlessフレームワーク

そんな時に颯爽と現れたのがServerlessフレームワークでした。
ServerlessフレームワークにおいてはLambdaファンクション及び関連するリソースを独自のyamlファイルで管理します。結局は一度CloudFormationテンプレートに変換されるのですが、CloudFormationテンプレートよりも単純な形式で記述できたのが流行った一因かと思います。また、sls deployコマンドでLambdaのコードのアップロードおCloudFormationスタックの更新を一括で行ってくれたため、デプロイの手順は従来よりもはるかに簡略化されたかと思われます。

Lambdaテストしづらい問題

デプロイに関する問題はServerlessフレームワークや、ほぼ同時期に現れたSAMによって改善されましたが、開発プロセスにおいて大きな課題がありました。

テストし辛ぇ…

上記の通りLambdaは性質上他のサービスと連携することが多いため、その辺をローカル環境でどうテストするかに多くの開発者が頭を抱えました。対策として

  1. モッククラスを作って、実際のサービスのような振る舞いをさせる
  2. プロダクションとは別のリージョンに環境を再現して、そこで実行する

といった方法がありましたが、それぞれ

  1. モッククラスの実装がすこぶるダルい 下手したらロジック本体より時間かかる
  2. クラウドにデプロイしないとテストできないため、時間がかかる

といったデメリットがありました。

LocalStackとaws-sam-local

サーバレス開発者の嘆きを聞いたAtlassianがローカル環境でAWSのサービスのエンドポイントを再現するなんとも素敵なツールを作り上げました。それがLocalStackです。
再現されているサービスの数が物足りなく感じられたり、サードパーティ製であることに一抹の不安を覚えたりする人もいるかと思いますが、これ以上を求めるなら自分で作るぐらいしかないのが現状かと思います。

そしてaws-sam-local。こちらはLocalStackと少し趣が異なります。LocalStackが連携するサービスのエンドポイントを再現して提供するのに対して、aws-sam-localは実行環境の提供という意味合いが強いです。そして重要なことはAWSの公式がサポートしているということです。公式がサポートしているということです。大事なことなので(ry
「実行するのはローカルでNode.jsなりPythonなりで動かせばええやん」と思いがちですが、ランタイムのバージョンなどを本番環境と確実に揃えられるのは大きな利点です。
まだベータ版が出たばっかなので今後に期待といったところでしょう

aws-sam-local触ってみた

それでは実際に触ってみましょう。
ちなみに当方環境は

  • OS: macOS Sierra 10.12.6
  • Docker for Mac: 17.06.0-ce-mac19

です。

事前準備とインストール

公式のInstallationの項目を読み進めますが、事前にDockerを使えるようにしておく必要があります。

Macだったら普通にDocker For Macをインストールしておけば問題ありません。
一方Windowsだと

スクリーンショット 2017-08-16 14.48.18.png

まさかのDocker Toolbox推奨。 Docker For Windowsェ…
そしてaws-sam-localのインストールですが、私は-gオプション排斥論者なのでローカルインストールします

npm install aws-sam-local

実装

今回はこちらを参考にAPIゲートウェイから呼び出すLambdaを実装します。
ほぼ丸パクリですが一部アレンジしてますのでソースものっけます。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Local test
Resources:
  HelloWorld:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10
      Events:
        GetResource:
          Type: Api
          Properties:
            Path: /resource/{resourceId}
            Method: put

ランタイムをnodejs6.10に変更してます。
新しく作る場合にわざわざ古いバージョンを使う必要もありませんので。

余談ですが、WebStormのCloudFormation用のプラグインは今の所SAMには対応してないのか、Type: AWS::Serverless::Functionのところにめっちゃ赤線を引かれます。

index.js
/**
 * Created by yuhomiki on 2017/08/16.
 */

"use strict";

const os = require("os");
console.log("Loading function");


const handler = (event, context, callback) => {
  return callback(null, {
    statusCode: 200,
    headers: { "x-custom-header" : "my custom header value" },
    body: "Hello " + event.body + os.EOL
  });
};

exports.handler = handler;

完全に書き方の趣味の問題です。
内容は参考ページのものと全く同じです。

package.json
{
  "name": "sam_test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "invoke-local": "sam local invoke HelloWorld -e event.json",
    "validate": "sam validate",
    "api-local": "sam local start-api"
  },
  "author": "Mic-U",
  "license": "MIT",
  "dependencies": {
    "aws-sam-local": "^0.1.0"
  }
}

aws-sam-localをローカルインストールしているので、package.jsonのscriptsに追記しています。

実行

それでは実行してみましょう

上記のpackage.jsonに記載した

  • invoke-local
  • validate
  • api-local

を実行していきます。

invoke-local

Lambdaファンクションをローカル環境で実行します。
Lambdaファンクションに渡すevent変数はワンライナーで定義することも可能ですが、あらかじめJSONファイルを作っといた方が取り回しがいいです。

json.event.json
{
  "body": "MIC"
}

実行結果はこんな感じ

スクリーンショット 2017-08-16 15.25.42.png

まず最初にdocker pullしてランタイムに応じたDockerイメージをダウンロードします。
その後はコンテナ内でLambdaファンクションを実行し、最後にcallbackに与えた引数を出力といった流れです。
ログの形式がすごくLambdaですね。あとタイムゾーンもUTCになっていますね。
メモリの使用量をローカルで確認できるのは嬉しいですね。

-dオプションをつけることでデバッグもできるようです。
公式のgithubにはご丁寧にVSCodeでデバッグしてる様子がgifで上げられてます。

validate

テンプレートファイルのチェックをします。
デフォルトではカレントディレクトリのtemplate.yamlファイルをチェックしますが、-tオプションで変更することが可能です。

失敗するとこんな感じに怒られます。

スクリーンショット 2017-08-16 15.33.47.png

成功した時は「Valid!」とだけ言ってきます。きっと必要以上に他人に関わりたくないタイプなのでしょう。

api-local

sam local start-apiコマンドはローカル環境にAPIサーバを立ち上げます。
ホットリロード機能がついてるので、立ち上げっぱなしでもソースを修正したら自動で反映されます。いい感じですね。

スクリーンショット 2017-08-16 15.40.58.png

立ち上がるとこんなメッセージが出るので、あとはCURLなりPostManなりで煮るなり焼くなり好きにしましょう。

CURLの結果はこんな感じ
スクリーンショット 2017-08-16 15.51.39.png

所感

Lambdaのローカル実行環境を公式が用意したことに大きな意義があるかと思います。
Dockerさえあればすぐに使えることと、SAMテンプレートを書かざるをえないのでInfrastructure as Codeが自然と根付いていくのも個人的には好感を持てます。

ただし、まだベータ版なこともあって機能的にもの足りない部分があるのも事実です。
具体的にはやはりDynamoDBとかもテンプレートから読み取ってDockerコンテナで用意してくれたらなーと思います。LocalStackやDynamoDB Localでできないこともないでしょうが、DynamoDB Localに関してはテンプレートからテーブル作ったりするの多分無理なのでマイグレーション用のコードを書くことになりますし、LocalStackに関しては実はあまり真面目に使ったことないのでわかりませんが環境構築に一手間かかりそう。ていうかできれば一つのツールで完結させたい。

SAMしかりaws-sam-localしかり、AWS側としてもより開発がしやすくなるような環境づくりをしていくような姿勢を見せているので、今後のアップデートに期待したいところですね。

続きを読む

DynamoDB Local Viewerに機能追加(スキーマ情報取得、ソート・フィルタ、データ削除)

以前作成したDynamoDBのLocal Viewerですが、現状の機能だと色々と不足してきたため更新をかけました。以前の記事はこちら。

DynamoDB Local用のViewerをSpring Bootベースで作ってみた

当時はScanメソッドでとりあえずデータを取ってましたが、今回は以下に対応させました。

  • テーブルの詳細情報確認
  • 指定したテーブルの中身の削除(制限あり)
  • 指定したテーブルの削除
  • テーブルデータのソートと絞り込み

結果はこちらに登録してあります。

https://github.com/kojiisd/dynamodb-local-view

テーブルの詳細情報確認

テーブル名をクリックした際にスキーマ情報を取得できるようにしました。

スクリーンショット 2017-04-21 7.10.54.png

こんな感じのダイアログを出すようにしています。

スクリーンショット 2017-04-21 7.11.21.png

指定したテーブルの中身の削除(制限あり)

個人的には一番欲しかった機能です。ローカルでDynamoDBを使った動作確認をしている際に、いちいちテーブルをドロップしてから作り直すのをスクリプトを組んで実施するのが面倒でした。なので「Clear」をクリックすれば中身をからにしてくれる機能を作りました。

スクリーンショット 2017-04-21 7.12.01.png

以下は削除後のスキーマ情報です。tableSizeBytesやitemCountが0になっているのがわかります。
ただいくつか制限があり、以下の実装のようにいくつかテーブル情報を引き継いでいません。この辺りうまい方法を知っている人がいればぜひ知りたいです。

CreateTableRequest createRequest = new CreateTableRequest().withTableName(tableName)
        .withAttributeDefinitions(describeResult.getTable().getAttributeDefinitions())
        .withKeySchema(describeResult.getTable().getKeySchema())
        .withProvisionedThroughput(new ProvisionedThroughput()
                .withReadCapacityUnits(describeResult.getTable().getProvisionedThroughput().getReadCapacityUnits())
                .withWriteCapacityUnits(describeResult.getTable().getProvisionedThroughput().getWriteCapacityUnits()));

スクリーンショット 2017-04-21 7.11.49.png

どんな仕組みにしたかはこちらに書きました。

Local DynamoDBのテーブルデータを削除したいときの実装(テーブル削除→作成)

指定したテーブルの削除

スクリーンショット 2017-04-21 7.13.16.png

スクリーンショット 2017-04-21 7.13.40.png

テーブルデータのソートと絞り込み

Scanのページには、各ヘッダで並び替えができるように、また検索結果にフィルタをかけられるように簡易のフィルタ機能をつけました。

スクリーンショット 2017-04-21 9.06.23.png

まとめ

そろそろQuery機能もつけて、実際のAWS ConsoleでのDynamoDBのユーザビリティを再現したいと思います。

続きを読む

DynamoDB Local用のViewerをSpring Bootベースで作ってみた

DynamoDB Localって便利ですよね。実際にAmazon DynamoDBにつなぎに行かなくてもCRUD操作をローカル環境で試せるので重宝しています。

java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb

このコマンドでDynamoDBがシミユレートできてしまうのだから、とても便利。

が、、、投入したデータの確認、となると一手間かかってしまいます。localhost:8000/shell(デフォルトの画面URL)で見れるこの画面、ありがたいのですが、今ひとつ物足りないですよね。

スクリーンショット 2017-01-04 19.54.49.png

やっぱり本家のこういう画面が欲しいなあ、、、と。こういうテーブル一覧とか、、、

スクリーンショット 2017-01-04 19.45.06.png

各テーブルの詳細画面とか。

スクリーンショット 2017-01-04 19.56.45.png

とりあえず目下自分が困っていたのは投入したデータの確認が容易にできないことだったので、DynamoDB Localにつなぎに行ってデータの中身を可視化してくれるViewerを作成しました。

結果

こちらに登録してあります。ご自由にお使いください。起動方法などはREADME.mdをご覧ください。

https://github.com/kojiisd/dynamodb-local-view

かなり力技で実装している部分があります。ソートやフィルタは実装していません。Pull Requestしてくれる方、大歓迎です。またデータ増えた時にパフォーマンス大丈夫かとかその辺は、知らんがな(´・ω・`)。今回の要件ではそんなにローカルでデータ保持しない想定だからダイジョーブ。

Mavenでのビルドから、Javaコマンドで実行できます。

$ mvn clean package
$ java -jar target/dynamodb-view-0.0.1-SNAPSHOT.jar

前提

  • 2016-05-17_1.0バージョンのDynamoDB Local jarファイルを利用しました。
  • Spring Boot + AngularJSで開発しました。

機能と画面

listTablesscanしかしていません。画面も2画面しか作っていません。

1. テーブル一覧画面

DynamoDB Localを起動した状態でアプリケーションから接続に行きます。 localhost:8080 でページが見れます。この画面は現在DynamoDB Localに保存されているテーブルの一覧になります。

スクリーンショット 2017-01-22 16.35.32.png

各テーブルにはリンクを付与しており、クリックするとそのテーブルのデータ一覧が見れます。

2. テーブル詳細画面

こんな感じになっています。DynamoDBは列指向ですので、動的に列が増えたとしても、対応していないレコードは空で表示するような仕組みにしています。

スクリーンショット 2017-01-22 16.35.22.png

この例ではsensor_idカラムとtimestampカラムをそれぞれ「HASH」、「RANGE」にしてテーブル作成しています。

テーブル作成のサンプルデータ

今回のテーブル(sample_table3)を表示するためのテーブル作成定義とデータサンプルは以下になります。

とりあえずこのままDynamoDB Localの管理画面(localhost:8000/shellでアクセスできるアレ)に投入すれば、テーブルの作成はできます。

CreateTable用データ定義
var params = {
    TableName: "sample_table3",
    KeySchema: [
        {
            AttributeName: "sensor_id",
            KeyType: "HASH"
        },
        {
            AttributeName: "timestamp",
            KeyType: "RANGE"
        }
    ],
    AttributeDefinitions: [
        {
            AttributeName: "sensor_id",
            AttributeType: "S"
        },
        {
            AttributeName: "timestamp",
            AttributeType: "S"
        }
    ],
    ProvisionedThroughput: {
        ReadCapacityUnits: 1, 
        WriteCapacityUnits: 1
    }
};

dynamodb.createTable(params, function(err, data) {
    if (err) ppJson(err); // an error occurred
    else ppJson(data); // successful response
});

データ作成はこんな感じでできます。

サンプルデータ用定義
var params = {
    TableName: "sample_table3",
    Item: { 
        sensor_id: "acceleration-sensor01",
        accelerationX: 1.254,
        accelerationY: 0.001,
        accelerationZ: 0.178,
        timestamp: "2017-01-22T10:01:24"
    },
    ReturnValues: "NONE",
    ReturnConsumedCapacity: "NONE",
    ReturnItemCollectionMetrics: "NONE"
};
docClient.put(params, function(err, data) {
    if (err) ppJson(err); // an error occurred
    else ppJson(data); // successful response
});

最後に

今回のツールのおかげで、個人的にDynamoDB Localに保持したデータの確認がかなり容易になりました。このツールを使ってバシバシデータの確認をしてもらえたら、と思います。

おまけ(少し困ったところ)

今回列指向のデータベースに対するアクセスでしたので、各レコードが持っている異なるカラムを、どのようにJava側でデータ保持して、画面側に渡し、表示するのがいいのか、については少し苦戦しました。

結果として以下のようにしました。

  1. [サーバ] 一旦値が空のキーのみのMapを作成する → カラムの過不足をなくす
  2. [サーバ] データが存在する部分だけ値を入れる → データが存在しない箇所は空文字になる
  3. [クライアント] ヘッダ作成部とデータ表示部でテーブルの作り方に一工夫

[サーバ] 一旦値が空のキーのみのMapを作成する

この辺りの実装ですね。少し力技です。画面側の表示を簡単にするためにサーバ側に処理を多めに入れています。

private Map<String, String> createEmptyColumnMap(ScanResult scanResult) {
    Map<String, String> columnMap = new LinkedHashMap<String, String>();
    for (Map<String, AttributeValue> valueMap : scanResult.getItems()) {
        for (Map.Entry<String, AttributeValue> valueMapEntry : valueMap.entrySet()) {
            columnMap.put(valueMapEntry.getKey(), StringUtils.EMPTY);
        }
    }
    return columnMap;
}

[サーバ] データが存在する部分だけ値を入れる

ここも力技。今回いくつかの型には(全部ではない)対応しましたが、これってDynamoDBのAPIを利用してもっとうまくできないですかね?

private String extractColumnValue(AttributeValue value) {
    String result = StringUtils.EMPTY;

    if (value == null) {
        return result;
    }

    if (value.getBOOL() != null) {
        result = value.getBOOL().toString();
    } else if (value.getB() != null) {
        result = value.getB().toString();
    } else if (value.getN() != null) {
        result = value.getN();
    } else if (value.getS() != null) {
        result = value.getS();
    } else if (value.getM() != null) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            result = mapper.writeValueAsString(value.getM());
        } catch (JsonProcessingException ex) {
            // TODO Exception handling
            ex.printStackTrace();
            result = StringUtils.EMPTY;
        }
    } else if (value.getSS() != null) {
        result = String.join(VALUE_SEPARATOR, value.getSS().toArray(new String[0]));
    } else if (value.getNS() != null) {
        result = String.join(VALUE_SEPARATOR, value.getNS().toArray(new String[0]));
    } else if (value.getBS() != null) {
        result = String.join(VALUE_SEPARATOR, value.getBS().toArray(new String[0]));
    }
    return result;
}

[クライアント] ヘッダ作成部とデータ表示部でテーブルの作り方に一工夫

ng-repeatを使ってAngularJS側でパッとテーブル表示したかったのですが、カラム名が動的に変わるのでこんな感じの実装になりました。limitTo:を使ってほぼ無理矢理です。これもよりスマートなやり方があればぜひ知りたいです。

<table class="table table-condensed table-bordered table-striped">
    <thead>
        <tr ng-repeat="data in datas | limitTo:1">
            <th>No</th>
            <th ng-repeat="(key, val) in data">{{ key }}</th>
        </tr>
    </thead>
    <tbody>
      <tr ng-repeat="data in datas">
          <td>{{ $index + 1 }}</td>
          <td ng-repeat="(key, val) in data">{{ val }}</td>
      </tr>
    </tbody>
</table>

続きを読む

Serverless アプリケーションをローカルで開発する

AWSに代表されるServerless Architectureはクラウド上での動作が前提ですが、Serverless Frameworkのプラグインを用いることにより、ローカル環境でも動作させることが可能になるのでご紹介します。AWSにデプロイすることなく開発が可能になるので、より素早く開発ができます。また、AWSのアカウントを持っていない方もServerlessの世界を体験できるかと思います。ここではじゃんけんを行うAPIの開発を通して、ローカルでの開発方法を説明します。完成版のソースコードは以下にあります

構成

API Gateway、Lambda、DynamoDBを用いたアーキテクチャをここでは想定します。ローカル開発環境ではそれぞれ serverless-offline、javascriptファイル、DynamoDB Local が対応します。

Screen Shot 2016-12-23 at 14.55.06.png

環境

  • macOS sierra
  • Node.js v4.6.2
  • Serverless Framework v1.4

プロジェクトの作成

Serverless Frameworkを用いて開発するのでインストールを行い、新しいサービスを作成します。

$ npm install -g serverless
$ mkdir serverless-janken
$ sls create -t aws-nodejs -n serverless-janken

関連するパッケージのインストール

API Gatewayの代用として利用する serverless-offline プラグイン、Serverless FrameworkからDynamoDB Localを操作できるようにする serverless-dynamodb-local プラグインをインストールします。

$ npm install aws-sdk
$ npm install --save-dev serverless-offline
$ npm install --save-dev serverless-dynamodb-local

インストール後、Serverless Frameworkからプラグインとして利用できるように設定に記入します。

$ vi serverless.yml
# service: serverless-janken の下に以下を追記
plugins: 
 - serverless-dynamodb-local
 - serverless-offline

DynamoDB Local のインストール

serverless-dynamodb-local プラグインを利用してDynamoDB Localをインストールします。

$ sls dynamodb install

DynamoDB Local テーブルの定義

DynamoDB Localで利用するテーブルを定義します。サンプルとして、プレイヤー名とUnixtimeをキーとするテーブルを作成しました。

$ mkdir migrations
$ vi migrations/jankens.json
# 下記内容で保存する
{
    "Table": {
        "TableName": "jankens",
        "KeySchema": [{
            "AttributeName": "player",
            "KeyType": "HASH"
        }, {
            "AttributeName": "unixtime",
            "KeyType": "RANGE"
        }],
        "AttributeDefinitions": [{
            "AttributeName": "player",
            "AttributeType": "S"
        }, {
            "AttributeName": "unixtime",
            "AttributeType": "N"
        }],
        "ProvisionedThroughput": {
            "ReadCapacityUnits": 1,
            "WriteCapacityUnits": 1
        }
    },
    "Seeds": [{
        "player": "user1",
        "unixtime": 1482418800,
        "player_hand": "rock",
        "computer_hand": "paper",
        "judge": "lose"
    }]
}

DynamoDB Local の起動

DynamoDB Local起動時にテーブルの作成とシードデータの挿入を行うため、 serverless.yml に設定を入れます。

serverless.yml
# service: serverless-janken の下に以下を追記
custom:
  dynamodb:
    start:
      port: 8000
      inMemory: true
      migration: true
    migration:
      dir: ./migrations

DynamoDB Localを起動します。

$ sls dynamodb start
Dynamodb Local Started, Visit: http://localhost:8000/shell

Table creation completed for table: jankens
Seed running complete for table: jankens

ブラウザで http://localhost:8000/shell にアクセスし、テーブルの中身を確認します。左側のエディタに下記を記入し、再生ボタンを押します。

var params = {
    TableName: 'jankens',
};
dynamodb.scan(params, function(err, data) {
    if (err) ppJson(err);
    else ppJson(data);
});

図のように右側にシードデータの内容が確認できれば、テーブルの作成&シードの挿入が完了しています。

Screen Shot 2016-12-23 at 15.08.59.png

Lambdaの開発

データベースの設定ができたので、ロジック部分を書いていきます。handler.js を開いて以下の内容で保存します。じゃんけんを行うAPI playJanken とじゃんけん結果を参照するAPI listJankens のためのロジックを書いています。このコードはAWSでもローカルでも動作が可能なように、 event.isOffline を見て接続するDynamoDBを切り替えています。

hander.js
"use strict";

var AWS = require("aws-sdk");

var judgeJanken = function (a, b) {
    var c = (a - b + 3) % 3;
    if (c === 0) return "draw";
    if (c === 2) return "win";
    return "lose";
}

var getDynamoClient = function (event) {
    var dynamodb = null;
    if ("isOffline" in event && event.isOffline) {
        dynamodb = new AWS.DynamoDB.DocumentClient({
            region: "localhost",
            endpoint: "http://localhost:8000"
        });
    } else { 
        dynamodb = new AWS.DynamoDB.DocumentClient();
    }
    return dynamodb;
}

module.exports.playJanken = function (event, context, callback) {
    console.log("Received event:", JSON.stringify(event, null, 2));
    console.log("Received context:", JSON.stringify(context, null, 2));

    var dynamodb    = getDynamoClient(event);
    var date        = new Date();
    var unixtime    = Math.floor(date.getTime() /1000);

    var hand        = ["rock", "scissors", "paper"];
    var player_name = event.queryStringParameters.name;
    var player_hand = event.queryStringParameters.hand;
    var player      = hand.indexOf(player_hand);
    var computer    = Math.floor( Math.random() * 3) ;
    var judge       = judgeJanken(player, computer);

    var params = {
        TableName: "jankens",
        Item: {
            player: player_name,
            unixtime: unixtime,
            player_hand: player_hand,
            computer_hand: hand[computer],
            judge: judge
        }
    };

    dynamodb.put(params, function(err) {
        var response = {statusCode: null, body: null};
        if (err) {
            console.log(err);
            response.statusCode = 500;
            response.body = {code: 500, message: "PutItem Error"};
        } else {
            response.statusCode = 200;
            response.body = JSON.stringify({
                player: player_hand,
                computer: hand[computer],
                unixtime: unixtime,
                judge: judge
            });
        }
        callback(null, response);
    });
};

module.exports.listJankens = function (event, context, callback) {
    console.log("Received event:", JSON.stringify(event, null, 2));
    console.log("Received context:", JSON.stringify(context, null, 2));

    var dynamodb = getDynamoClient(event);
    var params   = { TableName: "jankens" };

    dynamodb.scan(params, function(err, data) {
        var response = {statusCode: null, body: null};
        if (err) {
            console.log(err);
            response.statusCode = 500;
            response.body = {code: 500, message: "ScanItem Error"};
        } else if ("Items" in data) {
            response.statusCode = 200;
            response.body = JSON.stringify({jankens: data["Items"]});
        }
        callback(null, response);
    });
};

API Gatewayの設定

最後に前項で作成したロジックを呼ぶエンドポイントを作成するために serverless.yml に設定を入れます。

  • GET /jankens… じゃんけん結果の参照
  • POST /jankens… じゃんけんを行い結果をDynamoDB Localに保存
serverless.yml
service: serverless-janken

custom:
  dynamodb:
    start:
      port: 8000
      inMemory: true
      migration: true
    migration:
        dir: ./migrations

plugins:
  - serverless-dynamodb-local
  - serverless-offline

provider:
  name: aws
  runtime: nodejs4.3

functions:
  playJanken:
    handler: handler.playJanken
    events:
      - http:
          path: jankens
          method: post
  listJankens:
    handler: handler.listJankens
    events:
      - http:
          path: jankens
          method: get

テスト

以上で、データベース、ロジック、エンドポイントがそろったのでローカルで起動させて利用してみます。

$ sls offline

別のシェルでcurlでAPIを叩いて利用してみます。うまくいかない場合は sls dynamodb start でDynamoDB Localが起動していることを確認してください。

$ curl 'http://localhost:3000/jankens?hand=rock&name=test' -X POST
{"player":"rock","computer":"scissors","unixtime":1482469235,"judge":"win"}
$ curl 'http://localhost:3000/jankens'
{"jankens":[{"unixtime":1482469235,"player_hand":"rock","judge":"win","player":"test","computer_hand":"scissors"},{"unixtime":1482418800,"player_hand":"rock","judge":"lose","player":"user1","computer_hand":"paper"}]}

AWSにデプロイ

ローカルで開発ができたら、AWS上にデプロイします。AWSで動かすには、DynamoDBのテーブル定義と、IAMロールの設定が必要でしたので、serverless.yml に追記して下記のようにします。

serverless.yml
service: serverless-janken

custom:
  dynamodb:
    start:
      port: 8000
      inMemory: true
      migration: true
    migration:
        dir: ./migrations

plugins:
  - serverless-dynamodb-local
  - serverless-offline

package:
  exclude:
    - node_modules/**
    - migrations/**
    - .git/**

provider:
  name: aws
  runtime: nodejs4.3
  # DynamoDBの利用の許可
  iamRoleStatements:
    -  Effect: 'Allow'
       Action:
         - 'dynamodb:PutItem'
         - 'dynamodb:Scan'
       Resource: '*'

functions:
  playJanken:
    handler: handler.playJanken
    events:
      - http:
          path: jankens
          method: post
  listJankens:
    handler: handler.listJankens
    events:
      - http:
          path: jankens
          method: get

# DynamoDB Tableの作成
resources:
  Resources:
    JankensTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: jankens
        KeySchema:
          - AttributeName: player
            KeyType: HASH
          - AttributeName: unixtime
            KeyType: RANGE
        AttributeDefinitions:
          - AttributeName: player
            AttributeType: S
          - AttributeName: unixtime
            AttributeType: N
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1

最後にServerless Commandでデプロイします。

$ sls deploy
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3 (1.81 KB)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
......................
Serverless: Stack update finished...
Service Information
service: serverless-janken
stage: dev
region: ***
api keys:
  None
endpoints:
  POST - https://***.amazonaws.com/dev/jankens
  GET - https://***.amazonaws.com/dev/jankens
functions:
  serverless-janken-dev-playJanken: arn:aws:lambda:***:***:function:serverless-janken-dev-playJanken
  serverless-janken-dev-listJankens: arn:aws:lambda:***:***:function:serverless-janken-dev-listJankens

以上でローカルで開発したServerless アプリケーションをAWSにデプロイができました。

続きを読む

【メモ】AWSクラウドロードショウ大阪 # パネルセッション関西企業によるAWSで実現した「IoTビジネス」

事例紹介

  1. グッディ本部

    • ビーコンを使ってお客様や従業員の動線を可視化、バックヤード作業を効率化
  2. ダイドードリンコ
    • スマホを介してユーザーと自販機を繋ぐ新サービスを開発中

パネリスト各社のIoTビジネス

オプテックスのセンシングによるIoTビジネス

目的:センサの付加価値を高める -> 新たなビジネス価値やソリューションの創造

  1. 膨大なデータからセンサ側でデータを選別
  2. クラウドにデータをアップロード
  3. データを元に挙動を制御

オプテックスのセンサ

温度など特定の値を取得するのではなく、「侵入者検知」など、ある目的のためのセンサ

ビジネスモデル

  1. 端末機器販売型(従来)
  2. アライアンス型ソリューション(クラウドの発達によって可能)
  3. 完結型ソリューション(自らサービスを提供)

クラウド連携でサービス提供者と協業することがメイン

セーフメーターデータサービス

運転データの取得(加速度から運転の安全度を算出する独自アルゴリズム)
ドライブレコーダでは事故は減らない

ラトックシステム WiFi学習リモコン

PC・スマホの周辺機器メーカー

WiFi学習リモコンとは

スマホからWiFi経由で接続し、家電操作する機器
AWSを使うことで外出先からも家電の操作が可能

システム構成

  1. スマホアプリからCognitoの認証や、エンドポイントの作成、AWS IoTの証明書の作成など、IoTの下準備を行う
  2. 学習リモコンとAWSがMQTTで接続確立

スマホからの通信

  1. スマホアプリからコマンド発行DynamoDBに書き込み
  2. DynamoDBの書き込みイベントでLambdaをキック
  3. LambdaかたIoT MQTTをコール、学習リモコンへ指令を送る
  4. 学習リモコンからの応答をでLambdaをキック
  5. DynamoDBに応答を書き込むとともに、SNSでスマホにプッシュ通知

今後の展望

  • Alexaを使って音声認識で操作
  • ものづくりからサービスへ

ピクセラ 家庭向けIoT事業

ハードウェアからソフトウェアまで自社開発
IoT、翻訳、AR/VRにも参入

Conteホームサービス

スマートホームサービス
一人暮らし向け、高齢者見守り用など用途に向けたプランを選択可能

「ドアが開いたらLEDライトを点灯する」といったシナリオを組み立てることで、簡単に機器同士での連携ができる

AWS活用のメリット

求められる要素

  • セキュリティ

    • ユーザー認証
    • 秘匿性
  • 双方向通信
    • Websocket
  • スケーリング
    • 2016-08からELBもWebsocket対応
  • メンテナンス性

REST APIならAPIゲートウェイとLambdaを使える
双方向通信はAWS IoTのMQTT通信で実現

メリット

  • スモールスタートが可能
  • フルマネージド(保守運用の手間がへる)
  • カスタマイズ性

サーバレスアーキテクチャの開発フローの確立

Swaggerの活用

  • REST APIのモデリング
  • API ゲートウェイにインポート可能

Lambdaコードのテスト

  • DynamoDB localやdockerを利用した単体テスト環境

デプロイ

  • Cloud Formation, CLIを使って自動化

    • APIゲートウェイのステージ、Lambdaのaliasを使った環境切り替え、バージョン管理

今後の展開

  • 対応家電の追加
  • 対応ゲートウェイの追加

個人的所感

サーバレスアーキテクチャの開発フローが一番面白かったのにサクッと終わってしまった…
Lambdaはテストがデプロイ前のテストがやりづらいことに定評があるのでノウハウをしっかりと聞きたかったところ。
M-1グランプリの事例よりもピクセラの方がサーバーレス度高いやん!

続きを読む

Amazon Linuxコンテナイメージは AWS Lambda ネイティブライブラリ(.so)問題を解決するし財布にも優しい

全世界が泣いた!Amazon Linux Container Image!

New Amazon Linux Container Image for Cloud and On-Premises Workloads | AWS Blog
https://aws.amazon.com/jp/blogs/aws/new-amazon-linux-container-image-for-cloud-and-on-premises-workloads/

ついに手元に Amazon Linux が!!!

AWS Lambda でネイティブライブラリ(.so)を参照するpythonパッケージをベンダリングするのに使ってみる

Amazon Linux Container Imageを使えば
今までネイティブライブラリ(.so)を使うpythonパッケージを作るのに
EC2でAmazon Linuxを起動して作ってたところの手間が減る!
お財布にも優しい!

準備

コンテナイメージを pull しておく

Amazon Linux Container Image – Amazon ECR
http://docs.aws.amazon.com/AmazonECR/latest/userguide/amazon_linux_container_image.html

を参照。

確認してみる。

$ docker run -it 137112412989.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest cat  /etc/system-release
Amazon Linux AMI release 2016.09
$

確かにAmazon Linux! (感涙)

サンプルプログラム

lambdaの中で持っている画像をリサイズして
/tmp/ に出力して
lambdaの中に置きっぱなしで終了する
意味のないプログラムです。
Serverless Framework v1です。

https://github.com/imura81gt/lambda-and-amazon-linux-container/tree/qiita

各種ファイルについて補足すると

一覧

$ tree -FL 1 test/
test
├── Dockerfile  # Amazon Linuxコンテナ
├── event.json  # ServerlessFramework
├── handler.py  # ServerlessFramework
├── lena_std.tif # 画像ファイル
├── requirements.txt # pipでインストールするパッケージ(pip freeze >> requirements.txt)
├── serverless.yml  # ServerlessFramework
├── setup.cfg  # Amazon LinuxにPillowをインストールするのに必要だった
└── yum.list # Pillowをインストールするのに必要なyum repo管理のパッケージ

1 directory, 8 files

Dockerfile

FROM 137112412989.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest

RUN mkdir /app

WORKDIR /app

# lambdaは python2.7で動く
RUN yum install python27 python27-pip python27-devel python27-libs gcc  -y

ADD . .
# pipでインストールするパッケージが依存しているモノは yum.list に書いとく
# ONBUILD RUN とかにすればよかったかも
RUN yum install $(echo $(cat yum.list)) -y

CMD pip install --no-cache-dir -r /app/requirements.txt -t /app/vendor

NGパターン :bomb: ネイティブライブラリを使うpythonパッケージをOSX上でpipインストールしたら…

まちがって OSX 上で pip install したモノをそのまま Lambda にアップロードしたら…

$ cd test
$ # OSXやCentOS上で pip install した
$ # ネイティブライブラリを使うパッケージ
$ # (ex.Pillow)はLambda上では動かない。
$ pip install -r requirements.txt -t vendor/
$ $(npm bin)/sls deploy
$ $(npm bin)/sls invoke -f hello

エラーが出る

{
    "errorMessage": "Unable to import module 'handler'"

}

ログを見ると

$ $(npm bin)/sls logs -f hello

Unable to import module 'handler': /var/task/vendor/PIL/_imaging.so: invalid ELF header と出てます。

START RequestId: fea3d675-a59c-11e6-9977-9db5192e5233 Version: $LATEST
Unable to import module 'handler': /var/task/vendor/PIL/_imaging.so: invalid ELF header

END RequestId: fea3d675-a59c-11e6-9977-9db5192e5233
REPORT RequestId: fea3d675-a59c-11e6-9977-9db5192e5233  Duration: 0.24 ms   Billed Duration: 100 ms     Memory Size: 1024 MB    Max Memory Used: 32 MB

OKパターン:star: Amazon Linux Contaier Imageを使う

Amazon Linux Container Images をpullしておく
http://docs.aws.amazon.com/AmazonECR/latest/userguide/amazon_linux_container_image.html

$ cd test
$ rm -rf vendor/
$ docker build . -t amazon-py
$ docker run -it -v $(pwd)/vendor:/app/vendor:rw -t amazon-py
$ $(npm bin)/sls deploy
$ $(npm bin)/sls invoke -t hello

実行結果は

null

ログにもエラーなし

$ $(npm bin)/sls logs -f hello
START RequestId: e9003709-a59e-11e6-b541-0f7fe552a859 Version: $LATEST
END RequestId: e9003709-a59e-11e6-b541-0f7fe552a859
REPORT RequestId: e9003709-a59e-11e6-b541-0f7fe552a859  Duration: 169.37 ms Billed Duration: 200 ms     Memory Size: 1024 MB    Max Memory Used: 33 MB

期待

DynamoDB Local みたいな感じで、 Lambda Localが誕生するといいなぁ。

続きを読む

MacにAWS DynamoDB localを入れてRails runnerからアクセスしてみる

DynamoDBがローカルで実行できるらしいので開発用に試してみた。

ダウンロード・展開

wget http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest.zip #ダウンロード
unzip dynamodb_local_latest.zip #展開

起動

java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb #デフォルトだとPort8000で起動

接続

# aws cliがインストールされていれば、endpointを指定するだけで使える
local$ aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": [
        "test"
    ]
}

Railsから使う

runnerでやってみた。
※Rails 4.2.6

Gemfile
#SDKをGemで追加
gem 'aws-sdk'
lib/tasks/dynamo.rb
gem 'aws-sdk-core'

class Tasks::Dynamo
  def self.execute
    dynamo = Aws::DynamoDB::Client.new(
        endpoint: 'http://localhost:8000' #ローカルに対して
    )

    options = {
        table_name: "products",
        attribute_definitions: [
            {
                attribute_name: "product_code",
                attribute_type: "S"
            }
        ],
        key_schema: [
            {
                attribute_name: "product_code",
                key_type: "HASH"
            }
        ],
        provisioned_throughput: {
            read_capacity_units:  1,
            write_capacity_units:  1
        }
    }

    dynamo.create_table(options) #Table作成

    p dynamo.describe_table({table_name: "products"}) #テーブル情報取得
  end
end
local$ rails runner "Tasks::Dynamo.execute"
Running via Spring preloader in process 6438
#<struct Aws::DynamoDB::Types::DescribeTableOutput table=#<struct Aws::DynamoDB::Types::TableDescription attribute_definitions=[#<struct Aws::DynamoDB::Types::AttributeDefinition attribute_name="product_code", attribute_type="S">], table_name="products", key_schema=[#<struct Aws::DynamoDB::Types::KeySchemaElement attribute_name="product_code", key_type="HASH">], table_status="ACTIVE", creation_date_time=2016-10-31 08:20:37 +0000, provisioned_throughput=#<struct Aws::DynamoDB::Types::ProvisionedThroughputDescription last_increase_date_time=1970-01-01 00:00:00 +0000, last_decrease_date_time=1970-01-01 00:00:00 +0000, number_of_decreases_today=0, read_capacity_units=1, write_capacity_units=1>, table_size_bytes=0, item_count=0, table_arn="arn:aws:dynamodb:ddblocal:000000000000:table/products", local_secondary_indexes=nil, global_secondary_indexes=nil, stream_specification=nil, latest_stream_label=nil, latest_stream_arn=nil>>

無事表示された。

続きを読む

DynamoDBをlocal環境で動かしてみる

Dynamodbをlocal環境で動かすメモ

AWS上で使っているDynamodbに対して色々開発段階でデバッグなどしたい!
でも、アクセスしまくって課金されるのは困る。
みたいな時、Dynamodbには「DynamoDB Local」という、ローカルマシン内で稼働するdownloadable version of DynamoDBが公開されています。

公式のドキュメントに詳しく書かれています。
日本語版もあります。

環境

OSX 10.11.4
Java 1.8.0_101
IntelliJ IDEA 2016.1.4
Homebrew 1.0.8 もしくは pipとか(今回はHomebrewを使っています)

DynamodbLocalのセットアップ

[Step1]DynamodbLocalをダウンロード

ドキュメントにもある通りいずれかからダウンロード。

形式 URL
tar.gz 形式 http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest.tar.gz
zip 形式 http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest.zip

[Step2]任意のディレクトリ下で展開し、そのディレクトリ下に移動

こんな感じです
スクリーンショット 2016-10-27 8.33.10.png

[Step3]DynamodbLocalを起動

ここも、ドキュメントにあるようにまずはDynamodbLocalを起動してみます。

$ java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
Initializing DynamoDB Local with the following configuration:
Port:   8000
InMemory:   false
DbPath: null
SharedDb:   true
shouldDelayTransientStatuses:   false
CorsParams: *

これで起動は完了です。終了する場合はCtrl+Cです。

AWS コマンドラインインターフェイス (CLI)のインストール

[Step1]インストールします

公式ドキュメントではpipでaws-cliをインストールしていますが、homebrewで今回はインストールします。
これによって、コマンドラインで、Dynamodbのテーブルを作成したり、確認したりいろいろできるようになります。

$ sudo brew install awscli
Password:
~~~~省略~~~~
==> Renamed Formulae
stash-cli -> atlassian-cli
==> Deleted Formulae
dwarf                       jsdoc-toolkit               puddletag                   sonar-runner
homebrew/science/minc       libmarisa                   qbzr                        treeline

==> Downloading https://homebrew.bintray.com/bottles/awscli-1.11.10.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring awscli-1.11.10.el_capitan.bottle.tar.gz
==> Caveats
The "examples" directory has been installed to:
  /usr/local/share/awscli/examples

Before using aws-cli, you need to tell it about your AWS credentials.
The quickest way to do this is to run:
  aws configure

More information:
  https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
  https://pypi.python.org/pypi/awscli#getting-started

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completion has been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/awscli/1.11.10: 3,459 files, 28.4M

[Step2]aws configureの設定

http://www.task-notes.com/entry/20141026/1414322858
などを参考に。

$aws configure
AWS Access Key ID [None]: accesskey
AWS Secret Access Key [None]: secretkey
Default region name [None]: localhost:8000
Default output format [None]: 

[Step3]DynamoDB JavaScript consoleを立ち上げる

DynamodbLocalを起動している状態で、
http://localhost:8000/shell/
を開くと、以下のようなDynamoDB JavaScript consoleが開きます。

詳細な使い方についてはこちらがかなりわかりやすかったです。
http://dev.classmethod.jp/cloud/aws/dynamodb-local-shell-console/

[Step4]DynamodbLocalのtableをaws-cliで出力

$ aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": []
}

ここではまだ何もtableが登録されていないのでtableは空です

IntelliJ IDEAでDynamodbを触るプロジェクトを作ってみる(Java)

[Step1]IntelliJをダウンロード・インストールします

Comunity(無償)でも問題ないと思いますが(使ったことないですが)学生はUltimateも無料なのでそちらを使いましょう!
https://www.jetbrains.com/idea/
違いについてはこちらにまとまっています

[Step2]IntelliJを起動

[Step2]プロジェクトを作成(Create New Project)

Mavenを選択しProjectSDKはJava1.8にしました。


[Step3]テーブル作成のプロジェクトを作る

以下のStepではこのGettingStartedを参考にしています。というかコードはそのままです。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/gettingstartedguide/GettingStarted.Java.html

Javaファイルを作成します

作成先で以下のコードをコピペしてみましょう。

MoviesCreateTable.java
import java.util.Arrays;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;

public class MoviesCreateTable {

    public static void main(String[] args) throws Exception {

        AmazonDynamoDBClient client = new AmazonDynamoDBClient()
                .withEndpoint("http://localhost:8000");

        DynamoDB dynamoDB = new DynamoDB(client);

        String tableName = "Movies";

        try {
            System.out.println("Attempting to create table; please wait...");
            Table table = dynamoDB.createTable(tableName,
                    Arrays.asList(
                            new KeySchemaElement("year", KeyType.HASH),  //Partition key
                            new KeySchemaElement("title", KeyType.RANGE)), //Sort key
                    Arrays.asList(
                            new AttributeDefinition("year", ScalarAttributeType.N),
                            new AttributeDefinition("title", ScalarAttributeType.S)),
                    new ProvisionedThroughput(10L, 10L));
            table.waitForActive();
            System.out.println("Success.  Table status: " + table.getDescription().getTableStatus());

        } catch (Exception e) {
            System.err.println("Unable to create table: ");
            System.err.println(e.getMessage());
        }

    }
}

真っ赤になりました。

Add Maven Dependency… を行います

全て選択しAddします

右上にImport Changesとでてくるのでクリックすると

赤いのが消えます!

これはpom.xmlを確認してもらえれば分かりますが

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>hiroki11x</groupId>
    <artifactId>DynamodbSample</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-dynamodb</artifactId>
            <version>1.11.41</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-dynamodb</artifactId>
            <version>1.11.41</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-dynamodb</artifactId>
            <version>1.11.41</version>
        </dependency>
    </dependencies>
</project>

みたいにプロジェクトが依存するライブラリが指定されています。

現段階ではaws-cliでテーブルのリストを出力すると

$ aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": []
}

ですが、先ほどのMoviesCreateTable.javaを実行すると

$ aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": [
        "Movies"
    ]
}

Moviesが追加されました!
あとはGettingStartedに色々あるので引き続きこの記事に追加していこうと思います。

参考

続きを読む

AWS DynamoDB local の実行とアクセス方法(WindowsのGUIクライアントからも見れる!)

ダウンロードとインストール

AWS Documentation: コンピュータでの DynamoDB の実行

bash
wget http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest.tar.gz
tar xzvf dynamodb_local_latest.tar.gz

起動

java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb

  • -dbPathを指定すると、DBファイル格納フォルダを指定できるため、Vagrantでフォルダ共有とかする場合は便利。
  • -sharedDbをつけると指定されたリージョンごとのDBファイルではなく、単一のファイルにデータが格納される。

アクセス方法

CLIから

AWS Documentation:ローカルエンドポイントの設定

aws dynamodb list-tables --endpoint-url http://localhost:8000

JavaScript(node)SDKから

aws_sdk
var AWS = require("aws-sdk");
AWS.config.endpoint = new AWS.Endpoint('http://localhost:8000');

var db = new AWS.DynamoDB();
db.listTables(function(err, data) {
  console.log(data.TableNames);
});

dynamooseモジュールから

with_dynamoose
var dynamoose = require("dynamoose");
dynamoose.AWS.config.endpoint = new dynamoose.AWS.Endpoint('http://localhost:8000');

var Cat = dynamoose.model('Cat', { id: Number, name: String });
var garfield = new Cat({id: 666, name: 'Garfield'});
garfield.save();
Cat.get(666)
.then(function (badCat) {
  console.log('Never trust a smiling cat. - ' + badCat.name);
});

GUI(SQLite browser)から

stackoverflow:dynamodb-client-in-local-with-ui-like-phpmyadmin

DynamoDB LocalはSQLiteをバックグランドで使っているのでSQLite Database Browser上で中を見ることが出来るようです!!!!!!

  1. ローカルのDynamoDBをデータベースパスを指定して起動
    java -Djava.library.path=. -jar DynamoDBLocal.jar -dbPath /vagrant_data/dynamodb_data

  2. SQLite Database Browserをダウンロードしてインストール

  3. SQLite Database Browserを起動、Open DatabaseからDynamoDB起動時に指定したパスのXXX.dbファイルを開く

  • Windows上のVagrantで起動しているDynamoDB localでも、Vagrantの共有フォルダにDBファイルを出力するようにしておけば、GUIで見れるし、SQLが使えます。
  • DynamoDB localのデフォルトでは、起動したjarファイルと同じ場所にDBファイルが出力されます。

Javascript Shellから

チュートリアル: DynamoDB の基本的な運用

インタラクティブなチュートリアルが用意されています。優し~い!

  • ブラウザから以下にアクセスするとWebからJSのコードでDynamoDB localをいじれます
    http://localhost:8000/shell

  • Vagrantや、リモートの場合は動いているサーバーのURLに適宜変えてくださいませ~。


続きを読む