Serverless FrameworkでLINE BOTが簡単にできちゃった

  • 41
    Like
  • 0
    Comment

Serverless Framework

Serverless Frameworkは簡単に言うと、yamlで記述した設定ファイルを元に、CloudFormation経由でAWS上のサーバレスアーキテクチャを構築管理してくれるAWS Lambdaを中心としたインフラまわりのフレームワークです。

フレームワークと聞くとRuby on RailsやCakePHPなどを思い浮かべてしまいますが、そういったアプリケーション的な機能は薄く、少し意味合いが違った印象です。

image
10月にv1.0になり、すでに現在v1.4.0になってます。
それ以前のバージョンとはかなり変わっているので注意

お天気チャンネル for LINE

LINEで「天気教えて」ってメッセージを送ると、
現在の渋谷の天気情報とスクランブル交差点のウェブカメラの画像を返してくれるChatBotをつくりました。
https://line.me/R/ti/p/%40wra7063k

地味に便利

LINE@

まだアカウントを持っていなければLINE Business Centerからアカウントを作成し、
LINE DevelopersChannel Access Tokenを準備してください。

LINE Messaging API

Messaging APIはLINEでメッセージが届くとWebhook経由でリクエストが届きます。

Webhookなので必要なときだけコードを実行するAWS Lambdaのようなイベント駆動のシステムを使用したアーキテクチャは、このようなBOTに適しているといえます。
また、LINE APIはhttpsが必須ですが、Serverlessで構築するAPI Gatewayがカバーしてくれます。

下準備

ドキュメントを見ながら実装していきます。
https://serverless.com/framework/docs/providers/aws/guide/intro/

node.jsのバージョン

実際にAWS Lambda上で動作するnode.jsv4.3.2なので、nodebrewなどでバージョンを合わせておいた方が良いでしょう。

$ nodebrew install-binary v4.3.2
$ nodebrew use v4.3.2
$ node -v
v4.3.2

installよりinstall-binaryを使うと速い

AWS準備

aws-cliインストール

$ pip install awscli
$ aws --version
aws-cli/1.11.28 Python/2.7.12 Darwin/16.1.0 botocore/1.4.85

かなり頻繁アップデートされるので、気が向いたときにupgradeかけると良いです。

$ pip install --upgrade awscli

アクセスキー設定

指示に従い、Access Key IDSecret Access Keyとリージョンを設定しておきます。

$ aws configure

IAMポリシー設定

ドキュメントではAdministratorAccessの権限をセットしろと書かれているのですが、流石に強権すぎるので、インラインでセットします。
とりあえず、今回はこの辺があればOKです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:*",
                "s3:*",
                "iam:*",
                "apigateway:*",
                "lambda:*"
            ],
            "Resource": "*"
        }
    ]
}

Serverlessインストール

コマンド実行できるようにnpmでグローバルにインストールしてしまいます。

$ npm install -g serverless
$ serverless -v
1.3.0

Serverlessサービスの雛形作成

Serverlessでは1つ1つをサービスという単位で作成していきます。
pythonとかjavaとか色々選べますが、今回はaws-nodejsを選択

$ serverless create --template aws-nodejs --path tenkibot
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/xxxx/xxxx/xxxx/xxxx/tenkibot"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.3.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

実行するとtenkibotの中にhandler.jsserverless.ymlが作成されています。

さらに、package.jsonがないのでnpm initする

$ cd ./tenkibot
$ npm init

ディレクトリー構成はこんな感じ

$ tree
.
├── handler.js
├── package.json
└── serverless.yml

ローカル実行環境

Serverlessには実行環境がなく、nodeコマンドとかで頑張ることもできますが、面倒なので
serverless-offlineをインストールしてAPI Gatewayをローカルでシミュレートしてもらいます。

$ npm install --save-dev serverless-offline

そしてserverless.ymlに2つ書き加えます

serverless.yml
plugins:
  - serverless-offline

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get

そしてローカル実行

$ serverless offline start
Serverless: Starting Offline: dev/us-east-1.

Serverless: Routes for hello:
Serverless: GET /hello

Serverless: Offline listening on http://localhost:3000

これで http://localhost:3000/hello にアクセスし

{
  "message": "Go Serverless v1.0! Your function executed successfully!",
  ...
}

と返ってくればOKです。

LINE WebHook作成

superagentをインストール

API通信用にsuperagentを使用します。

$ npm install --save-dev superagent

Function作成

新しくline.jsというファイルを作成し、その中にリクエストの処理を記述していきます。
ひとまずオウム返しするBOT
accessTokenにはLINE Developersで取得したChannel Access Tokenを使用してください。

./line.js
const request = require('superagent');
const endpoint = 'https://api.line.me/v2/bot/message/reply';
const accessToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

module.exports.webhook = (event, context, callback) => {
  var body = JSON.parse(event.body);
  body.events.forEach(function(data) {
    var replyToken = data.replyToken;
    var message = data.message.text

    request.post(endpoint)
            .set('Content-type', 'application/json; charset=UTF-8')
            .set('Authorization',  'Bearer ' + accessToken)
            .send({
              replyToken: replyToken,
              messages: [
                {
                  type: 'text',
                  text: message,
                },
              ],
            })
            .end(function(error){
              if (error) {
                console.log(error);
              }
            });
  });

  callback(null, {statusCode: 200, body: JSON.stringify({})});
};

URLを作成

serverless.ymlに新しく作ったFunctionを追記します。
この記述がAPI Gatewayに反映されます、routing的なものだと考えてください。

handlerにはファイル名.ファンクション名の形式で指定します。
handler: src/facebook.webhookみたいにを作ることもできます。

serverless.yml
functions:
  lineWebhook:
    handler: line.webhook
    events:
      - http:
          path: line/webhook
          method: post

これで http://localhost:3000/line/webhook というURLにPOSTすると動作するようになりました。
実際にlocalでこのままためそうとすると、LINEに送っちゃうのでお気をつけて

デプロイ

region設定

serverless.ymlにデプロイのための追記を行います。
regionがデフォルトでus-east-1なので、東京リージョン(ap-northeast-1)に変更します。

serverless.yml
provider:
  name: aws
  runtime: nodejs4.3
  stage: dev
  region: ap-northeast-1

デプロイ実行

ここまでできたら後はAWSにデプロイするだけ

$ serverless deploy
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
.....
.....
Serverless: Stack update finished...

Service Information
service: tenkibot
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  POST - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/line.webhook
  GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello
functions:
  tenkibot-dev-lineWebhook: arn:aws:lambda:us-east-1:000000000000:function:tenkibot-dev-lineWebhook
  tenkibot-dev-hello: arn:aws:lambda:us-east-1:000000000000:function:tenkibot-dev-hello

endpointsの
GET - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/hello
ここにアクセスすると、ローカルで実行したときと同じようにGo Serverless v1.0! Your function executed successfully!が表示されます。

Webhook URLを設定する

先程のendpointsから
POST - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/line.webhook
このURLをLINE DevelopersのWebhook URLを設定します。

完成

LINEで友達追加して、メッセージ送るとオウム返しされれば完成です。
IMG_1100.PNG
うまくいかない場合はCloudWatchのログにからデバッグできます。

おわり

最初に説明したお天気チャンネルは、更にYahoo! 気象情報APIやウェブカメラの秘密のAPIを組み合わせて作っています。

AWSと聞くと若干高いイメージですが、
AWS Lambdaは月1,000,000件が無料なので、普通の使い方ではまず課金されない。
その後は0.20 USD/1,000,000 件のリクエスト(0.0000002 USD/リクエスト)と書かれているので、CloudFormationやAPI Gateway含め、値が小さ過ぎむしろコスト計算が大変。

Amazonもかなり力を入れてるみたいなので、もうAPIのサーバーとか必要のない時代が迫ってるのかもしれない
サーバー管理いらないし、リリースに気を使わなくて良いってのはかなりメリット