概要
最近、LINE Botを開発しました。
そのプロジェクトで、サーバレスアーキテクチャの構築と管理を容易にするServerless Frameworkを使用しました。
Serverless Frameworkを利用することで、AWSへのデプロイや管理が簡単になり、開発プロセスがスムーズになりました。
この記事では、その設定やプロセスについて詳しく説明していきます。
実行環境
前提条件として、Node.jsおよびAWS CLIインストールが必要です。
私の実行環境は以下の通りです。
$ node -v
v20.0.0
$ aws --version
aws-cli/2.15.12 Python/3.11.7 Darwin/23.2.0 source/x86_64 prompt/off
Serverless Framework のインストール
まずServerless Frameworkをインストールします。
$ npm install -g serverless
$ serverless --version
Framework Core: 3.38.0
Plugin: 7.2.0
SDK: 4.5.1
ちなみに、serverless
のエイリアスとしてsls
が登録されているので、以下コマンドでも実行できます。
$ sls --version
Framework Core: 3.38.0
Plugin: 7.2.0
SDK: 4.5.1
Serverless Frameworkが使うIAMユーザーの作成
次にAWSアカウントのセットアップを行います。
AWSコンソールにログインし、IAMのユーザーの作成をクリックし、任意のユーザー名を入力します。
ポリシーを直接アタッチするを選択し、AdministratorAccessを選択し、ユーザーを作成します。
IAMロールの権限を制限したい場合は以下サイトを参考に独自でセットアップして下さい。
ユーザーが作成できたら、アクセスキーを作成からアクセスキーとシークレットアクセスキーを作成します。
AWS CLI の設定
次にAWS CLIを設定します。
先ほど作成したアクセスキーとシークレットアクセスキーをAWSの認証情報としてAWS CLIに設定します。
$ serverless config credentials --provider aws --key "Your Access Key ID" --secret "Your AWS Secret Access Key"
✔ Profile "default" has been configured
上記コマンドは、~/.aws/credentials
ファイルに認証情報を書き込む操作を内部で行います。
そのため、aws configure
コマンドを使っても同じ設定が可能です。
$ aws configure
AWS Access Key ID [None]: Your Access Key ID
AWS Secret Access Key [None]: Your AWS Secret Access Key
Default region name [None]:
Default output format [None]:
もしdefault
プロファイルが既に設定されている場合、次のようなエラーメッセージが表示されます。
Error:
Profile "default" is already configured in ~/.aws/credentials. Use the overwrite flag ("-o" or "--overwrite") to force the update.
その場合--profile
オプションでプロファイル名を指定して新しいプロファイルを作成するか、--overwrite
オプションで既存のプロファイルを上書く必要があります。
$ serverless config credentials --provider aws --key "Your Access Key ID" --secret "Your AWS Secret Access Key" --profile sample
$ serverless config credentials --provider aws --key "Your Access Key ID" --secret "Your AWS Secret Access Key" --overwrite
設定が完了したら、~/.aws/credentials
ファイルに保存された認証情報を確認できます。
$ cat ~/.aws/credentials
[default]
aws_access_key_id=Your Access Key ID
aws_secret_access_key=Your AWS Secret Access Key
[sample]
aws_access_key_id=Your Access Key ID
aws_secret_access_key=Your AWS Secret Access Key
プロジェクトの作成
次に、プロジェクトを作成します。
serverless
コマンドを実行するとプロジェクトのテンプレートを選択するように求められるので、今回はAWS - Node.js - Express API
を選択します。
$ serverless
Creating a new serverless project
? What do you want to make? (Use arrow keys)
AWS - Node.js - Starter
AWS - Node.js - HTTP API
AWS - Node.js - Scheduled Task
AWS - Node.js - SQS Worker
❯ AWS - Node.js - Express API
AWS - Node.js - Express API with DynamoDB
AWS - Python - Starter
AWS - Python - HTTP API
AWS - Python - Scheduled Task
AWS - Python - SQS Worker
AWS - Python - Flask API
AWS - Python - Flask API with DynamoDB
Other
プロジェクト名には任意の値を入力します。
今回はserverless-sample
とします。
Serverless Frameworkへの登録やログイン、そして即時デプロイを行うかどうかの質問が表示されます。
これらに答えることでプロジェクトが作成されます。
$ serverless
Creating a new serverless project
? What do you want to make? AWS - Node.js - Express API
? What do you want to call this project? serverless-sample
✔ Project successfully created in serverless-sample folder
? Register or Login to Serverless Framework No
? Do you want to deploy now? No
What next?
Run these commands in the project directory:
serverless deploy Deploy changes
serverless info View deployed endpoints and resources
serverless invoke Invoke deployed functions
serverless --help Discover more commands
プロジェクト構造
プロジェクトが作成されると基本的なフォルダ構造が自動的に生成されます。
ファイル | 説明 |
---|---|
serverless.yml |
Serverless Frameworkの設定ファイルです。 サービス名や使用するクラウドプロバイダー、Lambda関数の設定などを記述します。 |
index.js |
Lambda関数の具体的なロジックを実装するファイルです。 |
serverless.yml の初期設定
serverless.yml
の初期設定は以下の通りです。
service: serverless-sample
frameworkVersion: '3'
provider:
name: aws
runtime: nodejs18.x
functions:
api:
handler: index.handler
events:
- httpApi: '*'
セクション | 説明 |
---|---|
service |
Serverless プロジェクトの名前を指定します。 この例では serverless-sample としています。 |
frameworkVersion |
使用するServerless Frameworkのバージョンを指定します。'3' はバージョン 3 を示します。 |
provider |
使用するクラウドプロバイダーを指定します。 この例では、プロバイダー aws と、Node.jsのランタイムバージョンnodejs18.x を設定しています。 |
functions |
Lambda関数とその設定を指定します。 このセクションで関数のハンドラー、イベントトリガーなどを設定しています。 |
今回の設定では、functions
セクションでapi
という名前のLambda関数を設定しています。
handler
はその関数がどのファイルに記述されているかを指定します。
今回の設定ではindex.js
のhandler
関数にそのロジックが実装されています。
events
はどのイベントがこの関数をトリガーするかを定義しています。
今回の設定ではhttpApi
を使用しAPI Gateway経由で受け取る全てのHTTPリクエストをこの関数にルーティングするように設定されています。
index.jsの初期設定
index.js
の初期設定は以下の通りです。
const serverless = require("serverless-http");
const express = require("express");
const app = express();
app.get("/", (req, res, next) => {
return res.status(200).json({
message: "Hello from root!",
});
});
app.get("/path", (req, res, next) => {
return res.status(200).json({
message: "Hello from path!",
});
});
app.use((req, res, next) => {
return res.status(404).json({
error: "Not Found",
});
});
module.exports.handler = serverless(app);
上記のindex.js
はExpressフレームワークを使ったNode.jsのコードです。
このコードは、ルートパス("/")と"/path"へのGETリクエストに応じて、異なるJSONメッセージを返します。
また、未定義のパスへのリクエストに対しては404エラーとエラーメッセージが返されます。
serverless(app)
により、Expressで作成されたWebアプリケーションapp
をServerless Frameworkを通じてAWS Lambda関数としてデプロイすることが可能です。
ローカルのテスト
Serverless Frameworkをローカルでテストする方法は2通りあります。
serverless offline
1つ目はserverless offline
を使用する方法です。
この方法では、ローカル環境でAPI GatewayやLambda関数の動作をエミュレートし、実際のAWS環境を模倣してテストを行うことができます。
開発中のAPIの挙動を確認したり、フロントエンドの開発と連携させて動作テストを行うのに便利です。
serverless offline
プラグインをプロジェクトに追加し、設定を行うことで、簡単にローカル環境でのAPIテスト環境を構築できます。
以下コマンドでserverless-offline
を導入します。
$ npm install serverless-offline --save-dev
その後serverless.yml
のplugins
に以下を追記します。
plugins:
- serverless-offline
serverless offline
コマンドを実行すると、ローカルエンドポイントが出力されます。
このエンドポイントに対してcurl
コマンドなどを用いることで、関数の動作をテストできます。
$ serverless offline
(中略)
┌───────────────────────────────────────────────────────────────────────┐
│ │
│ ANY | http://localhost:3000/{default*} │
│ POST | http://localhost:3000/2015-03-31/functions/api/invocations │
│ │
└───────────────────────────────────────────────────────────────────────┘
Server ready: http://localhost:3000 🚀
serverless invoke local
2つ目はserverless invoke local
コマンドを使用する方法です。
このコマンドを使うと、特定のLambda関数をローカル環境で直接実行することができます。
デプロイする前に個々の関数の挙動をテストしたい場合に便利です。
$ serverless invoke local --function api
{
"statusCode": 200,
"headers": {
"x-powered-by": "Express",
"content-type": "application/json; charset=utf-8",
"content-length": "30",
"etag": "W/\"1e-n7v8BWYZG0cayfAnplsH5ynO6ec\""
},
"isBase64Encoded": false,
"body": "{\"message\":\"Hello from root!\"}"
}
AWS へのデプロイ
serverless deploy
コマンドを使用してアプリケーションを AWS にデプロイする事が出来ます。
$ serverless deploy
Deploying serverless-sample to stage dev (us-east-1)
✔ Service deployed to stack serverless-sample-dev (117s)
endpoint: ANY - https://XXXXXXXXX.execute-api.us-east-1.amazonaws.com
functions:
api: serverless-sample-dev-api (894 kB)
デプロイ後、エンドポイントURLにアクセスすることで、API Gateway経由でLambda関数を呼び出す事ができます。
デプロイしたサービスの削除
デプロイしたサービスは、serverless remove
コマンドを使ってAWSから削除できます。
$ serverless remove
Removing serverless-sample from stage dev (us-east-1)
✔ Service serverless-sample has been successfully removed (29s)
プロジェクトが完了したり、不要になったサービスは削除しておきましょう。
serverless.ymlのカスタマイズ
最近、LINE Botの実装に使用したserverless.yml
を紹介します。
定期実行、もしくはメッセージに対する応答時にLambda関数が実行されます。
service: amazon-wishlist-to-line
frameworkVersion: "3"
useDotenv: true
provider:
name: aws
runtime: nodejs18.x
region: ap-northeast-1
environment:
AMAZON_WISHLIST_URL: ${env:AMAZON_WISHLIST_URL}
CHANNEL_ACCESS_TOKEN: ${env:CHANNEL_ACCESS_TOKEN}
CHANNEL_SECRET: ${env:CHANNEL_SECRET}
USER_ID: ${env:USER_ID}
timeout: 600
functions:
lineWebhookHandler:
handler: src/index.handler
events:
- http:
method: post
path: "/webhook"
cors: true
scheduledHandler:
handler: src/handlers/scheduledHandler.handleScheduledEvent
events:
- schedule:
rate: cron(0 22 * * ? *)
enabled: true
plugins:
- serverless-offline
サービスの設定
サービス名をamazon-wishlist-to-line
と指定し、Serverless Frameworkのバージョン3を使用します。
useDotenv
を使用する事で、.env
ファイルから環境変数を読み込むように設定します。
プロバイダーの設定
AWSをクラウドプロバイダーとして、Node.js 18.xをランタイムとして使用します。
必要な環境変数とLambda関数のタイムアウト時間も設定しています。
関数の定義
lineWebhookHandler
LINEのWebhookからのリクエストを処理する関数です。
src/index.handler
にそのロジックが実装されています。
/webhook
のパスで待機していて、HTTP POSTリクエストを受け取ります。
CORSを有効にして、外部のドメインからのリクエストも受け入れるようにしています。
scheduledHandler
定期的に実行される関数です。
src/handlers/scheduledHandler.handleScheduledEvent
にそのロジックが実装されています。
この関数はAWS EventBridgeを利用しており、cron(0 22 * * ? *)
により、UTC時間で毎日22時(日本時間の朝7時)に実行されるようスケジュールされています。
ローカル開発のサポート
serverless-offline
プラグインを使用してローカルでの開発を容易にします。
このプラグインを導入することでAPIのローカルテストを可能にします。
AWS へのデプロイ
serverless deploy
コマンドを使用してアプリケーションを AWS にデプロイできます。
この実装では、API Gatewayを通じてLambda関数(lineWebhookHandler
のみ)が呼び出されます。
そのため、HTTP POSTリクエスト用のエンドポイントURLのみが出力されます。
scheduledHandler
はAWS EventBridgeを使用して定期的に実行されるため、エンドポイントURLは出力されません。
$ serverless deploy
(中略)
Deploying amazon-wishlist-to-line to stage dev (ap-northeast-1)
✔ Service deployed to stack kindle-wishlist-to-line-dev (49s)
endpoint: POST - https://XXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/webhook
functions:
lineWebhookHandler: amazon-wishlist-to-line-dev-lineWebhookHandler (71 MB)
scheduledHandler: amazon-wishlist-to-line-dev-scheduledHandler (71 MB)
詳細なコードは、GitHubのリポジトリでも公開しています。
興味のある方は是非チェックしてみてください。
まとめ
この記事では、Serverless Frameworkを利用したAWSへのデプロイや管理について解説しました。
間違っている箇所や疑問に思ったことがあれば、ぜひコメントをください!
最後まで読んでいただき、ありがとうございました。
上記Serverless Frameworkを基にしたLINE Botの開発について記事を書いているので、こちらも読んでいただけると嬉しいです。