こんにちはこんばんは!佐々木です!
プライベートでLINEBot開発に取り組んでみようとしたところ、「AWS SAM CLI」が便利だよ。ということで使ってみたところ、めちゃくちゃ捗どりました!
また、ローカル環境で「MessagingAPI」を検証する際に「localtunnel」を使うとURLが固定できたりともろもろ楽出来たので、今回は僕が使用したサービスの簡単なご紹介とオウム返しBotを作ってローカル環境で検証するところまで書いていこうと思います!
AWS SAM (AWS Serverless Application Model ) とAWS SAM CLI
AWS Serverless Application Model (AWS SAM) は、AWS でサーバーレスアプリケーションを構築するために使用できるオープンソースのフレームワークです。
https://docs.aws.amazon.com/serverless-application-model/index.html
AWS SAM CLI は、AWS SAM テンプレートおよびアプリケーションコードで動作するコマンドラインツールです。AWS SAM CLI では、ローカルでの Lambda 関数の呼び出し、サーバーレスアプリケーションのデプロイパッケージの作成、サーバーレスアプリケーションの AWS クラウドへのデプロイなどを行うことができます。
環境構築から開発、テスト、デプロイがガンガン進められるのでめちゃくちゃ楽です!(逐一アップロードなどやってられry、、)
Messaging API
国内利用者数8900万人超えのSNS、LINEが提供するAPIの一つです。
LINEからは様々なAPIを提供しており、ボット開発やLINEログイン・決済機能と用途は多岐にわたるため、興味があればぜひご利用してみてはいかがでしょうか!
localtunnel
開発用に利用するローカルサーバをHTTPSとして外部サービスから連携させたりする際に、
「ngrok」をよく耳にしますが、無料アカウントだと少し手間がかかる面がありました。
「ngrok」は無料アカウントだと、ドメイン指定ができないため、起動のたびにurlがランダムに変更されてしまいます。
それはちょっとなぁ、、ということで今回は「localtunnel」を利用しました!
こちらは、サブドメインが固定できるので起動のたびにWebHookのURLを変えずに済むので重宝しました。
インターネット上にローカルマシンのリソースが公開されますので、ご利用する際はよくご検討ください。
また、開発が終わったら確実にサーバを落として、不用意に公開し続けないようにご注意ください。
事前準備ツール
始める前に以下のツールをインストールしておきましょう!(けっこう多いです)また、Dockerはデバッグなどを実行する際に起動している必要があるので、忘れずに起動しておきましょう!
- Docker
- AWS CLI
- AWS SAM CLI
- npm ※5.2.0以降
事前登録
- AWS アカウント
- Messaging API 【以下を参照】※WebHookが利用できる状態・Botを友達追加していればOK
環境構築
最初に「sam init」を入力すると対話型で環境構築を進めていくことになります。今回はGoを選択して作成します。(理由は僕がGo好きだからです)
sum init
▶ sam init
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1 ## 1を選択
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1 <meta charset="utf-8">## 1を選択
Which runtime would you like to use?
1 - nodejs14.x
2 - python3.9
3 - ruby2.7
4 - go1.x
5 - java11
6 - dotnetcore3.1
7 - nodejs12.x
8 - nodejs10.x
9 - python3.8
10 - python3.7
11 - python3.6
12 - python2.7
13 - ruby2.5
14 - java8.al2
15 - java8
16 - dotnetcore2.1
Runtime: 4 <meta charset="utf-8">## 4を選択
Project name [sam-app]: sample<meta charset="utf-8">## 任意の名前を入力
Cloning from https://github.com/aws/aws-sam-cli-app-templates
AWS quick start application templates:
1 - Hello World Example
2 - Step Functions Sample App (Stock Trader)
Template selection: 1 <meta charset="utf-8">## 1を選択
-----------------------
Generating application:
-----------------------
Name: sample
Runtime: go1.x
Architectures: x86_64
Dependency Manager: mod
Application Template: hello-world
Output Directory: .
Next application steps can be found in the README file at ./sample/README.md
Commands you can use next
=========================
[*] Create pipeline: cd sample && sam pipeline init --bootstrap
<meta charset="utf-8">▶ tree .
.
└── sample
├── Makefile
├── README.md
├── hello-world
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── main_test.go
└── template.yaml
上記のようにプロジェクトが作成されました。続けてbuildします。
cd sample/ && make
makeファイルには「sam build」が記載されているため、上記のコマンドでビルドされます。
ビルド後は、デプロイ用のアーティファクトが作成されます(青字部)。
<meta charset="utf-8">▶ tree . -a
.
└── sample
<span class="bold-blue"> ├── .aws-sam
│ ├── build
│ │ ├── HelloWorldFunction
│ │ │ └── hello-world
│ │ └── template.yaml
│ └── build.toml</span>
├── Makefile
├── README.md
├── hello-world
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── main_test.go
└── template.yaml
build後は以下のコマンドでlambda関数を起動できます。
sam local invoke
または、以下のコマンドでAPI呼び出しを含めたアプリケーション全体のテストができます。
sam local start-api
この際に
http://127.0.0.1:3000/にアクセスすると“Hello {使用しているIPアドレス}”が確認できます。
修正・追加
では、前述で作成している内容をLINEBot用に修正・追加していきます(赤字部)。
デプロイ用のアーティファクト(青字部)は再度buildを実行すると作り直されます。
修正後のコードなどは以下を参考にしてください。
▶ tree . -a
.
└── sample
<span class="bold-blue"> ├── .aws-sam
│ ├── build
│ │ ├── LineBotFunction
│ │ │ └── line-bot
│ │ └── template.yaml
│ └── build.toml</span>
├── Makefile
├── README.md
├── <span class="bold-red">env.json</span>
├── <span class="bold-red">line-bot</span>
│ ├── go.mod
│ ├── go.sum
│ ├── <span class="bold-red">main.go</span>
│ └── main_test.go
└── <span class="bold-red">template.yaml</span>
中のコードはさておき、重要なのがtemplate.yamlになります。(ここの理解で2日使った、、)
意識しておいたほうが良さそうなところはコメントを入れています。
<meta charset="utf-8">▶ template.yaml
<span class="bold-green">## SAM テンプレートヘッダー(ここにテンプレートのバージョンや説明を書く)</span>
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sample
Sample SAM Template for sample
Globals:
Function:
Timeout: 5
<span class="bold-green">## SAM テンプレートリソース(デプロイするリソースの詳細を定義する)</span>
Resources:
LineBotFunction:
<span class="bold-red">Type: AWS::Serverless::Function</span> <span class="bold-green">## lambdaを指す。他にもAPI GW,DynamoDB等を指定可。</span>
Properties:
<span class="bold"> </span><span class="bold-red">CodeUri: line-bot/</span><span class="bold"> <meta charset="utf-8"><span class="bold-green">## <meta charset="utf-8"><span class="bold-green">Lambda関数</span></span></span><span class="bold-green">に<span class="bold">デ</span></span><span class="bold"><span class="bold-green">プロイするコードの場所を指定</span>
<span class="bold-red">Handler: line-bot </span> </span><span class="bold-green">##</span> <span class="bold-green">Lambda関数のハンドラを指定</span>
Runtime: go1.x
Architectures:
- x86_64
Tracing: Active
<span class="bold-red">Events:</span> <meta charset="utf-8"><span class="bold-green">##</span> <span class="bold-green">Lambda関数のトリガーをEvents以下に記載</span>
CatchAll:
<span class="bold-red">Type: Api</span> <span class="bold-green">## AWSのどのサービスをイベントソースにするか指定。(この場合はAPI GW)</span>
Properties:
<span class="bold-red">Path: /parrot</span> <span class="bold-green">## 実行されるAPI GWのパス</span>
<span class="bold-red">Method: POST</span> <meta charset="utf-8"> <span class="bold-green">## 実行されるAPI GWのメソッド</span>
Environment:
Variables:
<span class="bold-green">## 以下は<meta charset="utf-8">env.jsonで環境変数を設定・読込を行う。</span>
<span class="bold-red">LINE_CHANNEL_SECRET: LineChannelSecret</span>
<span class="bold-red">LINE_CHANNEL_ACCESS_TOKEN: LineChannelAccessToken</span>
<span class="bold-red">Outputs:</span> <span class="bold-green">## SAMによって作成されるものの定義</span>
LineBotFunctionAPI:
Description: "API Gateway endpoint URL for Prod environment for LineBotFunction"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/parrot/"
LineBotFunction:
Description: "LineBotFunction ARN"
Value: !GetAtt LineBotFunction.Arn
LineBotFunctionIamRole:
Description: "Implicit IAM Role created for LineBotFunction"
Value: !GetAtt LineBotFunctionRole.Arn
コメントにも記載していますが、事前に用意しているMessaging APIで取得出来る「Channel secret」と「Channel access token」はハードコーディングさせたくないので環境変数として扱い、env.jsonから取得させます。以下のように記載することで環境変数として読み込めるようになります。
<meta charset="utf-8">▶ env.json
{
"Parameters": {
"LINE_CHANNEL_SECRET": <span class="bold-red">"xxxxxxxxxx"</span>, <span class="bold-green">## ここに<meta charset="utf-8">Channelsecret</span>
"LINE_CHANNEL_ACCESS_TOKEN": <span class="bold-red">"yyyyyyyyyy"</span> <span class="bold-green">## <meta charset="utf-8">ここに<meta charset="utf-8">Channelaccess token</span>
}
}
localtunnelのインストール、外部公開
localtunnelを以下のコマンドでインストールします。
npm i -D localtunnel
次にsamを起動しておきます。修正後に再度buildした後、以下コマンドを実行します。(必ず、sam→localtunnelの順に起動してください)
sam local start-api --env-vars env.json
<meta charset="utf-8"><span class="bold-green">Mounting LineBotFunction at http://127.0.0.1:3000/parrot [POST]</span>
続けて使用しているポート番号を指定してlocaltunnelを起動します。
この際に「–subdomain」オプションを指定することで同一のURLを使うことができます(ただし、他に同じサブドメインを使用している人がいた場合はそちらにURLが払い出されるため使用できません)。
npx lt --port 3000 --subdomain <span class="bold-red">zzzzzzzzz</span>
<span class="bold-green">your url is: https://xxxxx-yyyy-99.loca.lt</span>
MessagingAPI Webhook URLに設定
Webhook URLに「外部公開されているURL」+「/parrot」を入力して登録します!
「Use webhook」をONにするのもお忘れなく、、
以下のように確認できたら成功です!挙動が確認できればどんどん開発すすめていけますね!
AWS SAM CLI めっちゃ便利なのでぜひ皆さん使ってみてくださいね!٩(ˊᗜˋ*)و