一昨日(2018年11月29日)にAWS LambdaでRubyがサポートされることがアナウンスされました。
https://aws.amazon.com/jp/blogs/compute/announcing-ruby-support-for-aws-lambda/
今までお手軽にRuby実装のLINE Bot(Messaging API)を動かす環境としては、
Herokuが最有力候補だと思っていたのですが、
AWS Lambdaで動くとなると、Cold Start時のレスポンスタイムが改善されることや、
24時間実行されるような環境でも非常に低価格で実行できることなど嬉しいことがたくさんあります。
なので、今回はAWS LambdaのRubyでLINE Botのを動かす方法を解説していきたいと思います。
この記事の想定読者は、AWSを少し触ったこともあるし、LINE Botも1回は作ったこともあるという方です。
LINE Botのアカウントの作り方や、LINE Bot SDKの使い方などについてはこの記事では軽くしか触れません。
開発環境の構築
AWS CLIのインストール
今回はLambdaへのデプロイにNodejsのServerlessを使用したいと思います。
https://github.com/serverless/serverless
ServerlessでAWS Lambdaにデプロイするためには、
ローカルにAWS CLIがインストールされていて、ログインしていることが必要です。
まずはじめにAWS CLIをインストールしましょう。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/installing.html
pipを使っている方は以下のコマンドでインストール可能です。
$ pip install awscli --upgrade --user
次にログインが必要です。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-getting-started.html
$ aws configure
serverlessのインストール
次にserverlessのインストールを行います。
serverlessコマンドがAWS LambdaのRubyに対応したのは、今日(2018年12月1日)のことなので、
おそらく皆さんアップデートorインストールが必要です。
$ npm install -g serverless
Serverless初期設定
とりあえず動かしたいんや!という方はこちらにリポジトリを用意しておいたので、
これをCloneして、Channel Secretを取得するまで読み飛ばしてください。
https://github.com/toduq/line-bot-ruby-lambda-sample
この章には実装の注意点が書いてあるだけです。
まずはじめに雛形を作ります。 handler.rb
や、 serverless.yml
が作成されると思います。
$ serverless create --template aws-ruby
LINE Bot SDK RubyのReadmeに書いているサンプルコードを参考に書いていくんですが、
今回はsinatraを使わないのと、bodyやheaderの受け取り方が違うので、そのあたりを注意して実装します。
require 'json'
require 'line/bot'
def client
@client ||= Line::Bot::Client.new { |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
}
end
def webhook(event:, context:)
signature = event['headers']['X-Line-Signature']
body = event['body']
unless client.validate_signature(body, signature)
puts 'signature_error' # for debug
return {statusCode: 400, body: JSON.generate('signature_error')}
end
events = client.parse_events_from(body)
events.each do |event|
case event
when Line::Bot::Event::Message
case event.type
when Line::Bot::Event::MessageType::Text
client.reply_message(event['replyToken'], {
type: 'text',
text: "Your message is\n" + event.message['text']
})
end
end
end
{statusCode: 200, body: JSON.generate('done')}
end
serverless.yml
は、HTTPのwebhookが受け取れるようにeventを設定するのと、環境変数を渡すように修正します。
お好みでregionやmemorySizeも設定してください。
service: line-bot-lambda-ruby # NOTE: update this with your service name
provider:
name: aws
runtime: ruby2.5
memorySize: 256
region: ap-northeast-1
environment:
LINE_CHANNEL_SECRET: _replace_with_yours_
LINE_CHANNEL_TOKEN: _replace_with_yours_
functions:
webhook:
handler: handler.webhook
events:
- http:
path: /webhook
method: post
GemfileでLINE Bot SDK Rubyを指定します。
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "line-bot-api"
Channel Secretを取得する
Botを作っていない方は、LINE Developersから作りましょう。
https://developers.line.biz/ja/services/messaging-api/
LINE DevelopersからChannel SecretとChannel Tokenというのを取得します。
こんな感じの文字列です。
LINE_CHANNEL_SECRET: f733394bc6294020f3d0c27f5af8ba50
LINE_CHANNEL_TOKEN: yvw6MNPDi34Ha9d3g65wn420QWp//aR2RyCLyrrabEISo1Ziu以下略...
これを serverless.yml に書き込みます。
environment:
LINE_CHANNEL_SECRET: f733394bc6294020f3d0c27f5af8ba50
LINE_CHANNEL_TOKEN: yvw6MNPDi34Ha9d3g65wn420QWp//aR2RyCLyrrabEISo1Ziu以下略...
いざDeploy!
Serverlessコマンドはローカルのファイルをzipにして、S3経由でAWS Lambdaを更新するという仕様のため、
ローカルのディレクトリに bundle install
の結果が必要です。
ネイティブライブラリを使用するようなGemではMacやWindowsで bundle install
したものを
そのままAWS Lambdaで動かすのは無理かもしれませんが、
今回はLINE Bot SDK Rubyだけなので大丈夫でした。
$ bundle install --path vendor/bundle
そして、serverlessでデプロイ!
Lambdaと一緒に、API Gatewayのルーティングなども設定してくれるのでとっても便利です。
$ serverless deploy
...省略...
endpoints:
POST - https://di2fhs9dnds0.execute-api.ap-northeast-1.amazonaws.com/dev/webhook
...省略...
エンドポイントが作成されたと思うので、これを先程のLINE DevelopersのWebhook URLというのに登録します。
これで準備は完了なので、LINEからメッセージを送ってみましょう。
こんな感じにメッセージが帰ってきたらバッチリです
Cold Startしたときでも、Herokuみたいにタイムアウトすることなく2秒以内にレスポンスが帰ってくるので、
非常に快適なBot開発ライフが送れると思います
動かなかったときのよくある原因
まずは serverless logs -f webhook
してみましょう。ログが見れます。
Channel SecretやChannel Tokenを変更し忘れている
signature_error
という文字列が出ていると思います。
ちゃんと、変更できているか確認してみてください。
bundle installできていない
--path vendor/bundle
をつけて実行したかもう一度確認してみてください。