ローカルでLambdaのテストをする環境を作ったメモ

何?

Lambdaをテストする際、いちいちUPしてCloudWatchを確認して・・・とテストするのは辛いのでローカルでテストする環境を作る。
作ったメモ

検証環境

Mac: macOS Sierra
awscli: aws-cli/1.14.32 Python/2.7.13 Darwin/16.7.0 botocore/1.8.36
nodejs: v9.4.0
npm: 5.6.0
docker: Version 17.06.2-ce-mac27

ディレクトリ構成

.
├── docker-compose.yml
├── event.json
├── index.js
├── package.json
└── template.yml

aws-sam-localのインストール

npm i aws-sam-local -g

私はこいつはグローバルインストールしている

手順

作業ディレクトリの作成と移動

コマンド
mkdir test
cd test

npm install

npm init -y
npm i aws-sam-local aws-sdk --save-dev

sam-localが使用するYAMLの作成

template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  lambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10

localstack用のYAMLファイル作成

docker-compose.yml
version: '2.1'
services:
  localstack:
    image: localstack/localstack
    ports:
      - 4567-4583:4567-4583
      - 8080:8080

スクリプトの用意

index.js
'use strict';

const AWS = require('aws-sdk');
const S3 = new AWS.S3({endpoint: 'http://<ローカル端末のIP>:4572', s3ForcePathStyle: true});


exports.handler = (event, context, callback) => {
    console.log(`EVENT is ${event}`);
    uploads3().then(() => {
        callback()
    });
};

const uploads3 = () => {
    return new Promise((resolve, reject) => {
        let param = {
            Bucket: "xxxxxxxxxxxxxbbb",
            Key: "test2.txt",
            Body: "fugafuga"
        };
        console.log(param);

        S3.putObject(param, (err, data) => {
            if (err) {
                console.log(err, err.stack);
            } else {
                console.log(data);
            }
            resolve();
        });
    });
};

ダミーイベント作成

コマンド
sam local generate-event dynamodb > event.json

local-stackの起動(バックグラウンド起動)

コマンド
docker-compose up -d

lambdaのローカル実行

コマンド
sam local invoke lambdaFunction -e event.json 
  • アップロード用のS3バケットのダミーは最初に作っておくこと。
  • samが呼んでくるlambda動かすdockerからlocalstackへのネットワーク疎通が通らなかったからEndpointは端末のIP指定している。

ローカルでCLI使ってlocalstackは疎通出来るのに、docker上で動いてるLambdaスクリプトから接続ができなくてすっごいハマった。

参考

[新ツール]AWS SAMをローカル環境で実行できるSAM Localがベータリリース

AWS SAM Local と LocalStack を使って ローカルでAWS Lambdaのコードを動かす

続きを読む

Serverless FrameworkでAPI Gatewayバイナリサポートを設定する

API Gatewayでバイナリを扱いたい場合、バイナリサポートを有効にする設定が必要になります。
その設定をServerless Frameworkで定義しました。

ServerlessFrameworkのデフォルトではバイナリサポートの設定パラメータが用意されていないためプラグインを使用します。

調べたところ現時点では以下の2つのプラグインが見つかりました。

一つ目のserverless-apigw-binaryは試してみたときに、デプロイは成功していてもAPI Gatewayに反映されていないということがあったため、二つ目のserverless-plugin-custom-binaryを使うことにしました。

環境

$ npm -v
5.5.1

$ serverless -v
1.22.0

設定方法

プラグインのインストール

$ npm install --save-dev serverless-plugin-custom-binary

設定を追加

serverless.yml
plugins:
  - serverless-plugin-custom-binary

custom:
  apigatewayBinary:
    types:
      - multipart/form-data

デプロイ! :beer:

$ serverless deploy

デプロイ完了後、API Gatewayのコンソールで確認するとちゃんと設定されています。
スクリーンショット 2018-02-03 22.20.23.png

以上です。

続きを読む

keystoneJSをnginxでデプロイしてaws上で動かす。

wordpressが使いたくなく、python大好きマンなのでmezzanineを使おうと思ったのですが、デプロイで頓挫したのでnodeJSでやろう。keystoneJSでやろうという次第です。

DDNSにはno-IPを利用しました。

keystoneJS official

前提

  • awsにインスタンスを作成済み
  • 上記インスタンスの3000番ポートを開けておく
  • 上記のインスタンスにssh接続出来る

諸々のインストール

sudo yum update -y

nodeJS


curl -L git.io/nodebrew | perl - setup
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
ebisennet$ source ~/.bash_profile

nodebrew install-binary v9.4.0

mongoDB

こちらの記事を参考にさせて頂きました。

sudo vim /etc/yum.repos.d/mongodb-org-3.2.repo

[mongodb-org-3.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.2.asc

sudo yum install -y mongodb-org

sudo service mongod start

sudo chkconfig mongod on

Yoeman

sudo npm install --global yo

keystoneJS

sudo npm install -g generator-keystone

no-IP

sudo yum-config-manager --enable epel
sudo yum install -y noip

nginx

sudo yum install nginx

forever

npm install -g forever

keystoneJSの実行

公式ページの通りに進めます。
htmlはpug,cssはsassがオススメです。

mkdir my-test-project
cd my-test-project
yo keystone

node keystone

この時点で[myIP]の3000ポートにアクセスするとページが見れるはずです。
example : http://x.x.x.x:3000

no-IPの設定

awsのドキュメントを参考に進めます。

sudo noip2 -C
sudo chkconfig noip on
sudo service noip start

nginxでデプロイ

sudo vi /etc/nginx/nginx.conf
nginx.conf
    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf; #この一行だけ加える
    ...
sudo vi /etc/nginx/conf.d/keystone.conf
keystone.conf
upstream node-sampleapp1 {
    server localhost:3000;
}

server {
    listen       80;
    server_name  http://DNSNAME/;
    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
    location / {
        proxy_pass http://node-sampleapp/;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
    root   /usr/share/nginx/html;
    }
}

foreverでデーモン化

forever start keystone.js

デバックモードを切る

vi my-test-project/.env

NODE_ENV=productionとする。

あとは、templatesやpublic,routesなどを編集して自分好みのスタイルに変更する。
また、記事の投稿はhttp://DNSNAME/keystone/signin より行う。

オチ

markdownのプラグインとか欲しいのでwordpressを始めようと思いました。

続きを読む

環境構築201801 slackbot

はじめに

環境構築時のメモです。
* Amazon Linux AMI release 2017.09
* nvm 0.33.8 (201712)
* node v9.3.0 (201712) 
* redis v2.4.10(201712)
* hubot-slack v4.4 (201712)
* nginx v1.10.3 (201708)
* pyton v3.6.0 (201712)

初期設定

command
$ cat /etc/system-release1
$ sudo yum update -y
$ sudo yum install -y git

タイムゾーンをJSTに変更する。

command
$ sudo ln -sf  /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ sudo vi /etc/sysconfig/clock
---
ZONE="Asiz/Tokyo"
UTC=false
---

OSユーザ(例:hoge)作成

command
$ useradd hoge
$ sudo su - hoge
$ cd /home/hoge
$ mkdir .ssh
$ cd .ssh
$ ssh-keygen -t rsa
$ mv id_rsa.pub authorized_keys
$ chmod 600 authorized_keys
$ cat id_rsa ※内容を接続元PCに保存 hoge.pem
※puttyの場合
・Run PuTTYgenを起動
・Load an existing private file を読み込む(load)
・Save public key hoge.ppk
・上記ファイルを"Private key file for authentication"に設定する。
・wheelユーザに追加およびパスワードなしでsudoを利用できるようにする。
$ vi /etc/group
----
wheel:x:10:ec2-user,hoge
----
$ sudo visudo
---
# %wheel        ALL=(ALL)       NOPASSWD: ALL
%hoge      ALL=(ALL)       NOPASSWD: ALL
---

Nginxインストール

$ sudo useradd www
$ sudo groupadd www
$ sudo yum install nginx
$ sudo cp /etc/nginx/nginx.conf.default /etc/nginx/nginx.conf
$ sudo vi /etc/nginx/nginx.conf
---
server{
   listen    80;
   server_name localhost;
   root ***設置場所***;
   charset utf-8;
   index index.html index.htm index.php;
   access_log /var/log/host.access.log main;
}
---
$ sudo service nginx start
$ sudo chkconfig nginx on

redisインストール

$ sudo yum --enablerepo=epel install redis
$ sudo service redis start
$ sudo chkconfig --level 35 redis on
$ sudo chkconfig --list | grep redis

nodeインストール

$ git clone git://github.com/creationix/nvm.git ~/.nvm
$ vi .bashrc
---
if [ -f ~/.nvm/nvm.sh ];then
        source ~/.nvm/nvm.sh > /dev/null 2>&1
fi
---
$ source ~/.bashrc
$ nvm ls-remote nodeバージョン一覧表示
$ nvm install v6.9.0
$ nvm alias default v6.9.0  #恒久的な切り替え
$ nvm ls-remote
$ node -v
nvm自身のバージョンアップ
text
$ cd ~/.nvm
$ git pull origin master
$ source ~/.bashrc

Python3インストール

text
$ yum install gcc gcc-c++ make git openssl-devel bzip2-devel zlib-devel readline-devel sqlite-devel
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
$ vi ~/.bashrc
---
export PYENV_ROOT="${HOME}/.pyenv"
if [ -d "${PYENV_ROOT}" ]; then
export PATH=${PYENV_ROOT}/bin:$PATH
eval "$(pyenv init -)"
fi
---
$ sudo yum install patch
$ pyenv install 3.6.0
$ pyenv global 3.6.0
$ pip install --upgrade pip
$ pip install bigquery-python
$ pip install beautifulsoup4
$ pip install jupyter
$ jupyter notebook --generate-config
$ python -c "from notebook.auth import passwd;print(passwd())" ※設定
$ vi ~/.jupyter/ 内に jupyter_notebook_config.py
---
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.password = 'sha1:*******' ※
---

Slackbot構築

Slackにhubotアプリを追加

Add apps| Slack

hubot01png.png

hubot2.png

Hubotインストール

$ cd ~/.nvm/versions/node/(バージョン)/lib/node_modules
$ npm install hubot yo generator-hubot coffee-script hubot-slack
$ cd ~
$ mkdir hello-hubot
$ cd hello-hubot
$ yo hubot
$ vi external-scripts.json
---
heroku packageを削除
---
動作確認
$ vi ./scripts/examples.coffee
---
module.exports = (robot) ->
#(コメントアウトを外す) robot.hear /badger/i, (res) ->
#(コメントアウトを外す) res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
---
$ export HUBOT_SLACK_TOKEN=<API Token>
$ ./bin/hubot -a slack 

Slackでbadgerを入力しリプライを確認
hubot3.png

SlackBot設置

slack からgoogle検索ができるか試す。
下記のアンプルコードを scriptsディレクトリに保存し、hubotを起動する。

./bin/hubot -a slack

サンプルコード|SlackBot

slackから作成したアプリに「search is ***」を送信するとreplyが届く。

hubot5.png

続きを読む

Amazon Translateを使ってみた&自動翻訳付きチャットを作ってみた

Amazon Translateのプレビュー申請が先日通ったので、使ってみました。us-east-1(バージニア北部)で利用しています。

Amazon Translateとは?

公式ページへどうぞ。

成果物

とにかく成果物が早く見たい方はこちらへ。

https://github.com/kojiisd/amazon-translate-chat-demo

コンソールから使ってみる

とりあえずAWSコンソールから使ってみます。100万文字で15ドルの料金のようです。

スクリーンショット 2018-01-13 16.05.42.png

選択できる言語は7つとまだ少なめですが、いずれすぐに日本語も追加されるでしょう。

image.png

入力した文字がリアルタイムに翻訳されます。(日本語が選択できないので、文章を入れても自然な文章になっているのかは判断できませんがw)

スクリーンショット 2018-01-13 16.08.49.png

APIを使ってみる

ただこれだけだとなんの面白みもないので、自動翻訳をつけたようなチャットを作ってみたいと思います。

画面の準備

以前作成したiot-demo-deviceをベースに開発します。

https://github.com/kojiisd/aws-iot-demo-device/

とりあえずこんな感じの画面を組みます。

スクリーンショット 2018-01-20 13.26.33.png

項目名 意味
Name 名前
Source Language 受信するメッセージの言語
Target Language 翻訳対象言語
Start Chat チャット開始のためのボタン
Message メッセージ
Send Message メッセージ送付用ボタン

最初は名前やメッセージ受信時の言語を選択しないとチャットを
スタートできないようにしています。
→メッセージをSubscribeする際に自身と同じ名前だったら翻訳しないようにするため。

画面下部の「Original」と「Translated」にメッセージのやりとりが記録されるように実装します。

WebSocketにAWS IoTを利用する

チャットのやりとりをするために今回WebSocketを利用しますが、一から環境を用意するのが面倒なので、AWS IoTで手を抜きます。カスタマイズなどは特に気にせずデフォルトで設定してしまってOKです。

今回はこちらの記事と同じ設定をしました。

Three.jsとAWSを連携させてIoTっぽいことしてみた

AWS IoTは受信後のアクションが必要だったので、DynamoDBに履歴として登録する体で設定をしています。

aws-sdkのフルビルド

この記事を書いている時の「v2.184.0」ではフルビルドをしないとAWS.Translateクラスが使えなかったため、公式ページを参考にビルドを実施します。

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/building-sdk-for-browsers.html

$ git clone git://github.com/aws/aws-sdk-js
$ cd aws-sdk-js
$ npm install
$ node dist-tools/browser-builder.js all > aws-sdk-full.js

翻訳部分を開発する

肝心の翻訳ですが、こんな感じのコードにします。事前にCredentialやEndpointなど必要な情報を設定しておく必要があります。なぜPromiseが必要かは後述します。

AWS.config.credentials = new AWS.Credentials(cred.awsAccessKeyId, cred.awsSecretAccessKey);
  :
  :
function translate(message) {

  var params = {
    Text: message,
    SourceLanguageCode: srcLang,
    TargetLanguageCode: targetLang
  };

  var syncProc = new Promise(
    function (resolve, reject) {
      window.translator.translateText(params, function onIncomingMessageTranslate(err, data) {
        if (err) {
          reject("Error calling Translate. " + err.message + err.stack);
      }
        if (data) {
          resolve(data.TranslatedText);
        }
      });
    }
  );

  return syncProc;
}

翻訳語の文章の追加部分の開発

上述のtranslateメソッドを呼び出す部分ですが、メッセージ受信後のコールバックメソッドとなります。

function onMessage(message) {
  var msgJson = JSON.parse(message.payloadString);
  var addingHtml = "<tr><td>" + msgJson.name + ": </td><td>" + msgJson.message + "</td>";
  if (msgJson.name == body.name) {
    addingHtml += "<td></td><td></td></tr>"
    $("#chatArea").prepend(addingHtml);
  }
  else {
    translate(msgJson.message).then(function (result) {
      addingHtml += "<td>" + msgJson.name + ": </td><td>" + result + "</td></tr>"
      $("#chatArea").prepend(addingHtml);
    }).catch(function(error){
      alert(error);
    });
  }

メッセージを受信した際、自身の名前と同じであれば翻訳は実施しないように処理をしています。

自分ではない人からのメッセージの場合translateメソッドを呼び出しますが、Translate APIにアクセスするタイミングで非同期処理となってしまうため、前述のPromiseでこの辺の処理の順番を制御しました。

実際の動き

画面を二つ用意して、それぞれ「kojiisd1」と「kojiisd2」でチャットを開始するようにします。設定はそれぞれ以下の通りとします。

kojiisd1 kojiisd2
Source Language French English
Target Language English French

kojiisd1からは英語で話すようにし、kojiisd2からはフランス語で話をしてみます。

こんな感じで操作できました(ちょっとGIFのサイズ大きい)。

amazon-translate-chat-demo3.gif

まとめ

Amazonが提供する翻訳サービスなので、Pollyなど他のサービスとの連携も容易にできるようになると期待が持てます。これは電話会議などもAmazonが提供する翻訳サービスを使いながらリアルタイムに全て自動翻訳できる日が来そうな感じがして、期待大のサービスですね。

続きを読む

AWS Cloud9でAngularアプリ開発(後編)

はじめに

前編ではCloud9の環境構築をおこなったので、今回は実際にAngularの環境構築~実行までを行おうと思います。

node, npmのバージョンを確認

Angular-CLIは現状、nodeが6.9.0以上、npmが3.0.0以上必要なので、まずはバージョンの確認をします。
Cloud9にはIDE上にコンソールがあるので、そこにコマンドを入力すれば確認できます。
image.png
Cloud9はデフォルトでnodeが6.12.3、npmが3.10.10がインストールされているので問題なさそうです。

ちなみに、Cloud9ではワークスペース毎にEC2インスタンスが違うので、ワークスペースを別に立てればインストールされたモジュールを共有しなくてもよくなります。
つまり、今まで一台のPCではNodeなどのバージョン管理が大変でしたが、Cloud9を利用すればバージョン毎にワークスペースを立てれば済むようになるわけです。

Angular-CLIのインストール

Angularの開発にはかかせないAngular-CLIをインストールします。
Cloud9のコンソールに公式に記載されている通りに入力します。

npm install -g @angular/cli

体感で1分ほどでインストールが完了しました。

Angularプロジェクトの作成

Angular-CLIを利用してプロジェクトを作成します。
sample-angular-appの部分には作成するアプリ名が入るので、適宜読み替えてください。

ng new sample-angular-app
cd sample-angular-app

image.png
今回は2分ほどで完了しました。

Angularアプリを実行

まずは公式の通り以下のコマンドで起動してみます。

ng serve

起動したら、上部にあるPreview -> Preview Runnig Applicationを選択して、起動した画面を見てみます。
image.png
すると、「Invalid Host header」と表示されて失敗します。
これは、ホスト名が指定されたものと違うことが原因のようなので、ホスト名を明示して起動してみます。
ng serveのオプションの–publicを利用することでホスト名を明示することができます。
指定するホスト名には、Preview用ブラウザに記載されているURLをそのまま利用します。

ng serve --public https://xxxxxxxx.vfs.cloud9.ap-southeast-1.amazonaws.com

image.png

今度は上手くアクセスすることができました。
理由はわかりませんが、初回アクセス時にはロードに時間がかかるので辛抱強く待ちましょう。

起動コマンドをpackage.jsonに記載する

毎回URLを記載するのは面倒なので、起動コマンドをpackage.jsonに記載して省略出来るようにします。
今回修正するscriptの部分は、プロジェクトを作成した直後では以下の内容です。

  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },

この、”ng serve”のコマンドに –public https://xxxxxxxx.vfs.cloud9.ap-southeast-1.amazonaws.comを追加します。
修正後は以下のようになります。

  "scripts": {
    "ng": "ng",
    "start": "ng serve --public https://xxxxxxxx.vfs.cloud9.ap-southeast-1.amazonaws.com",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },

修正を保存したら、実際に利用できるかを試してみましょう。
package.jsonで修正するのはnpmのコマンドなので、以下のコマンドで起動します。

npm run start

image.png

無事起動することが確認できました。

おわりに

前編から、AWS Cloud9を利用してAngularアプリの開発環境構築を行いました。
Cloud9を利用することで簡単に開発を始められるので、今後プロト等作成する時には積極的に利用していきたいです。

続きを読む

AWS Cloud9でAngularアプリ開発(前編)

AWS Cloud9とは

ブラウザ上で動作するIDEで、40以上の言語に必要なツールがあらかじめインストールされているため起動すればすぐに開発を始められる。
AWSが運営してるだけあって、AWSの他のサービスとの連携も簡単(らしい)。
複数人で同時に編集できたりハイライトした部分が相手からも見えるなど、ペアプロやコードレビューに向いた機能もある。

バージョン

ちなみにインストールされているバージョンは執筆当時で
Java : 1.7
node : 6.12.3
npm : 3.10.10
Python : 2.7.12
でした。
もちろんアップデートする方法はあるみたいです。

料金

Cloud9は基本的にEC2上で動作するようになっていて、課金はこの時に利用するEC2の料金のみ。
t2.microで構成すれば無料枠内で利用できる。
もちろんリッチな構成で作れば早くなる。
詳しくは公式を見てください。

AWS Cloud9環境の準備

では実際にCloud9の環境を準備してみます。
まずはCloud9のトップにアクセス。
すると、普段東京リージョンで利用している人はこんな画面に遷移したと思います。

キャプチャ.PNG

実はCloud9は現在東京リージョンには来ていないんです。
なので、おとなしく別のリージョンに移動しましょう。
するとこんな画面に遷移するので、右側にあるオレンジ色のCreate environmentをクリックしてCloud9の準備を始めましょう。
キャプチャ.PNG

Environment name and description

最初に環境の名前を設定します。
今回はcloud9-angular-sampleという名前にしました。
Descriptionの部分は環境の説明を書く部分なので今回は省略。

キャプチャ.PNG

Environment setting

次にCloud9を構築するサーバの設定をしていきます。

キャプチャ.PNG

Environment type

一番上のEnvironment typeは環境のタイプの設定です。
キャプチャ.PNG
上が新規にEC2インスタンスを作成してそこにCloud9環境を作る設定、
下が既存のEC2インスタンスもしくは自分で構築したサーバに環境を作る設定になります。
下の設定の場合には色々条件があるみたいなので公式の解説を参照するようにしてください。
今回は新規にインスタンスを作成するので上を選択します。

Instance type

新規インスタンスを選択すると、作成するインスタンスの構成を設定する必要があります。
image.png
今回は無料枠内で利用したいのでt2.microを選択します。
もちろんリッチな構成にすればそれだけ快適になるので、ここは好みで大丈夫です。

Cost-saving setting

この設定をすることで、Cloud9を使用していない時、自動的にインスタンスを閉じてくれるようになります。
キャプチャ.PNG
今回は30分に設定しておきました。

他の設定についてはデフォルトのままNextStepを押して先へ進みます。
キャプチャ.PNG

準備完了

確認画面のCreate environmentを押すと、グルグルしてる画面に遷移します。
image.png

初回はインスタンスの起動等々ありますが、だいたい1分ほどで準備が完了します。
キャプチャ.PNG

おわりに

前編はCloud9の環境構築までを行いました。
後編ではCloud9上でAngularの環境構築~実行までをやってみます。

続きを読む