概要
Serverless Framework はServerless Applicationを構成管理デプロイするためのツールです。この記事ではその使い方をまとめています。
※ 2022.4.17 – Serverless Framework v3 の変更内容を反映しました。
インストール
Node.jsのインストール
ServerlessはNode.jsで作られたCLIツールです。
なので、あなたのマシンにNode.jsをインストールする必要があります。Node.jsの公式サイトからあなたのPCにNode.jsをインストールしましょう。ServerlessはNode.jsのv12以上が必要となります。
Serverlessのインストール
Serverlessはnpmのパッケージとして公開されています。ターミナルを開いて、npm install -g serverless
でインストールが完了します。
正しくインストールされているかは、serverless --version
にて確認しましょう。以下のようにバージョンが表示されれば正しくインストールされています。
$ serverless --version
Framework Core: 3.14.0
Plugin: 6.2.1
SDK: 4.3.2
プロバイダーアカウントのセットアップ
プロバイダーのアカウントをセットアップします。プロバイダーとは、要はどのクラウドサービスを使用してServerlessを動かすかということです。AWS, GCP, Azure, IBM Cloudなど様々なクラウドプロバイダーに対応しています。
ここではAWSにスポットを当てて解説します。
AWS account Setup
ここにAWSアカウントのセットアップ方法が書いていますが、要は以下を実施すればOKです。
- Serverless用のIAMユーザを発行
- IAMユーザに
AdministratorAccess
の管理ポリシーを与える
基本的にはこのアカウントを使って、ServerlessのデプロイやLambdaファンクションのローカルからの実行を行います。
また、IAMロールを制限したい場合は、serverless-puresec-cliやNarrowing the Serverless IAM Deployment Policyを参考に独自でセットアップしましょう。
サービスの作成
Serverlessはサービス
という単位で実行環境を作っていきます。
まずはサービスを開設してみましょう。
AWSをプロバイダーとしてNode.jsでサービスを開設する場合は以下の手順になります。
$ serverless create --template aws-nodejs --name my-special-service --path my-special-service
すると、my-special-serviceのディレクトリが作られ、その配下に以下のファイルが出来ているはずです。
これでサービスの作成は完了です。
- serverless.yml
- handler.js
また、サービス用のテンプレートですが、以下の言語用のテンプレートが用意されています。
- aws-nodejs
- aws-nodejs-typescript
- aws-nodejs-ecma-script
- aws-python
- aws-python3
- aws-kotlin-jvm-maven
- aws-kotlin-jvm-gradle
- aws-kotlin-nodejs-gradle
- aws-groovy-gradle
- aws-java-maven
- aws-java-gradle
- aws-scala-sbt
- aws-csharp
- aws-fsharp
どの言語でLambdaを動かしたいかによってテンプレートを変更してあげましょう
serverless.yml
serverless.ymlは各サービス全体の設定を行うためのファイルです。
AWSでは、以下のような設定が可能です。
- サービス内のLambdaファンクション群の設定
- Lambdaに設定されるIAMロールの設定
- デプロイ時にどのファイル/ディレクトリを含めるか/含めないかの設定
- 使用するプラグインの定義
- Lambdaファンクションごとのトリガーとなるイベントの定義
- Lambdaファンクションが他のAWSリソースを連携する場合は、そのIAMを含めた定義
まずは、serverless.ymlの設定をしてあげましょう。もろもろサービスを実行するために必要な設定はすべてこのファイルで行います。
handler.js
これはファンクションを定義するためのスケルトンとして生成されるファイルです。これを参考に実際のファンクションのプログラムを作っていきます。
event.json
ServerlessのCLIでファンクションを実行する際に入力値となるデータを定義するファイルです。Lambdaファンクション内でevent
変数に展開されます。
※2022年4月時点ではテンプレートに event.json が含まれないので、後述しますがサンプルで event.json を利用する場合別途作成しておく必要があります。
Githubに上がった既存のサービスをインポートする場合
既にGithubに上がっている既存サービスの開発を行う場合は、そのままローカルにインポートしてServerlessをセットアップしたいと思います。その際はserverless install -u [GITHUB URL OF SERVICE]
でインポート可能です。
サービスのデプロイ
次に作ったサービスをプロバイダー上へデプロイしましょう。
serverless deploy -v
でデプロイは開始されます。-vオプションを付けるとverbose
というモードでデプロイが実施され、途中経過がターミナル上で確認できます。
また、Serverlessのデプロイにはstage
という概念が導入されています。いわゆる本番環境とテスト環境といった環境をstageという単位で切り分けています。
Serverlessはデフォルトで、dev
というステージかつus-east-1
リージョンにデプロイされるようになっています。
もしこれを変更したければ serverless.yml
に以下のように設定します。
serverless.yml
service: service-name
provider:
name: aws
stage: beta
region: us-west-2
これでbeta
ステージのus-west-2
リージョンにデプロイされるようになります。
serverless.ymlで定義したものと異なるサービス及びリージョンへのデプロイ
また、deploy
コマンドはデプロイするstageやregionを引数で指定することも出来ます。
production
ステージのap-northeast-1
リージョンに上げたければ、serverless deploy --stage production --region ap-northeast-1
とすれば、引数通りの指定でデプロイが実施されます。
ファンクション単位のデプロイ
serverless deploy -v
はサービス全体のデプロイを行います。ファンクションの一部を修正したなどのケースで、サービス全体がデプロイされるのは大変です。
Serverlessはファンクション単位でのデプロイもserverless deploy function -f <yourfunction>
にて可能です。
ファンクションの実行
デプロイしたファンクションを実行してみましょう。
event.json の作成
ServerlessのCLIでファンクションを実行する際に入力値となるデータを定義したファイルを作成します。Lambdaファンクション内でevent
変数に展開されます。
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
helloファンクションの実行
サービス作成時にhandler.jsとして作成されるhelloファンクションを実行する場合を考えてみましょう。serverless invoke --function hello -p event.json
で実行できます。
実行時にログを表示させる
ファンクションの実行時にログを見たいを思います。Lambdaの実行時にCloudwatchのログが同時に見れれば便利ですよね? Serverlessはそれにも対応しています。serverless invoke --function Yourfunction -p event.json --log
でlogオプションを付与するとこで以下の通りログが確認できます。
$ serverless invoke --function hello -p event.json --log
{
"statusCode": 200,
"body": "{\n \"message\": \"Go Serverless v1.0! Your function executed successfully!\",\n \"input\": {\n \"key1\": \"value1\",\n \"key2\": \"value2\",\n \"key3\": \"value3\"\n }\n}"
}
--------------------------------------------------------------------
START
END RequestId: 4767edc0-b1cc-4dcb-9128-2474967ec40a
END Duration: 2.09 ms Memory Used: 56 MB
body の中身をパースすると event.json の内容が含まれた以下のオブジェクトに展開されます。
{
message: 'Go Serverless v1.0! Your function executed successfully!',
input: {
key1: 'value1',
key2: 'value2',
key3: 'value3'
}
}
各ファンクションのログの履歴を確認する
後からファンクション毎のログを確認する場合はserverless logs --function Yourfunction
というコマンドを実行します。
すると以下の通りログがリストで表示されます。
$ serverless logs --function hello
START
END Duration: 2.47 ms (init: 167.55 ms) Memory Used: 55 MB
START
2022-04-16 02:16:58.039 { key1: 'value1', key2: 'value2', key3: 'value3' }
END Duration: 4.56 ms (init: 155.54 ms) Memory Used: 55 MB
※確認のため handler.js 関数内で console.log(event)
のようにログ出力を追加しています。
他のAWSリソースにIAMでポリシーを設定する
実行時に他のAWSリソースを参照する場合は、serverless.yml内のprovider.iam
を使用して必要なポリシーを設定します。
DynamoDBのexampleテーブルに対する全権限を付与する場合は以下のような設定をします。
# serverless.yml
provider:
iam:
role:
statements:
- Effect: "Allow"
Action:
- "dynamodb:*"
Resource:
- arn:aws:dynamodb:us-east-1:*:table/example
イベントトリガーの設定
Serverless Frameworkはファンクションにイベントを設定することでイベント駆動のアーキテクチャを実現することをサポートしています。
イベントにはHTTPリクエスト(AWSではAPI Gateway)やS3 bucket、スケジュールイベントなど、設定を行うことが出来ます。
今回は、AWS Gatewayを使用したhttpイベントの設定を例にあげます。
HTTP eventを追加する
greet
というパスでhttpリクエストを受けた場合にhello
ファンクションを実行させたい場合は以下のようにserverless.ymlを設定します。
# serverless.yml
functions:
hello:
handler: handler.hello
events:
# HTTP API endpoint (API Gateway v2)
- httpApi:
path: /greet
method: GET
# REST API endpoint (API Gateway v1)
- http:
path: /greet
method: GET
この設定を行い、serverless deploy
を実行してデプロイに成功すれば以下のようなEndpointがターミナル上に表示されるはずです。 上が REST API、下が HTTP API のエンドポイントです。
endpoints:
GET - https://xxx.execute-api.us-east-1.amazonaws.com/dev/greet
GET - https://yyy.execute-api.us-east-1.amazonaws.com/greet
これに対して実際にリクエストを送ってみるとLambdaで定義した返り値が返ってくるはずです。
$ curl https://xxx.execute-api.us-east-1.amazonaws.com/dev/greet
$ curl https://yyy.execute-api.us-east-1.amazonaws.com/greet
https://serverless.com/framework/docs/providers/aws/events/apigateway/
API Gatewayを使ったhttpイベントは様々なパラメータを設定することが可能です。詳しくは公式のドキュメントを確認してみてください。個人的にはlambda-proxyの機能が、手軽にLambdaからステータスコードの設定が出来て便利だと感じています。
また、現段階でAWSをプロバイダーとして以下のイベントが設定可能です。
- API Gatewayを使用したhttpイベント
- S3の操作をトリガーとしたイベント
- Lambdaのスケジュールイベント
- SNSの通知をトリガーとしたイベント
- DynamoDB / Kinesis Streamsイベント
- Allexa Skill / Alexa Smart Homeイベント
- AWS IoTイベント
- CloudWatch Event
- CloudWatch Log
- Cognito User Poolのトリガーファンクション
- SQS
https://serverless.com/framework/docs/providers/aws/events/
Serverlessで使用できる変数
Serverless Frameworkはserverless.yml
内で変数を定義することで柔軟なサービス設定が可能となっています。
環境変数を参照する
環境変数を参照する場合は${env:SOME_VAR}
というシンタックスをserverless.ymlに記述します。以下がその例です。serverless.yml
service: new-service
provider: aws
functions:
hello:
name: ${env:FUNC_PREFIX}-hello
handler: handler.hello
world:
name: ${env:FUNC_PREFIX}-world
handler: handler.world
この例ではあなたのPC内のFUNC_PREFIX
という環境変数を参照するようになりました。
CLIオプションを参照する
serverlessコマンド実行時のオプションを参照させたい場合は${opt:SOME_VAR}
というシンタックスをserverless.ymlに記述します。以下がその例です。
serverless.yml
service: new-service
provider: aws
functions:
hello:
name: ${opt:stage}-hello
handler: handler.hello
world:
name: ${opt:stage}-world
handler: handler.world
serverless deploy --stage dev
とした場合は、${opt:stage}
はdevが返ります。また、serverless deploy --stage production
とした場合は、productionが返ります。
自身で定義した変数を参照する
serverless.yml内で自身で定義した変数を参照させることも出来ます。${self:someProperty}
というシンタックスで定義可能です。以下がその例です。
serverless.yml
service: new-service
provider: aws
custom:
globalSchedule: rate(10 minutes)
functions:
hello:
handler: handler.hello
events:
- schedule: ${self:custom.globalSchedule}
world:
handler: handler.world
events:
- schedule: ${self:custom.globalSchedule}
他のファイルで定義した変数を参照する
serverless.ymlとは別で定義したファイルを読み込んで、その変数を参照することも出来ます。${file(../myFile.yml):someProperty}
というシンタックスでserverless.ymlに定義してください。以下がその例になります。
myCustomFile.yml
globalSchedule: rate(10 minutes)
serverless.yml
service: new-service
provider: aws
custom: ${file(../myCustomFile.yml)} # You can reference the entire file
functions:
hello:
handler: handler.hello
events:
- schedule: ${file(../myCustomFile.yml):globalSchedule} # Or you can reference a specific property
world:
handler: handler.world
events:
- schedule: ${self:custom.globalSchedule} # This would also work in this case
変数のネスト
以下のように変数をネストさせることも可能です。
serverless.yml
service: new-service
provider: aws
custom:
myFlexibleArn: ${env:${opt:stage}_arn}
functions:
hello:
handler: handler.hello
変数の上書き
以下のような記述を例にあげます。
serverless.yml
service: new-service
provider:
name: aws
stage: dev
custom:
myStage: ${opt:stage, self:provider.stage}
functions:
hello:
handler: handler.hello
この場合にserverless deploy
を発行したとします。この時、opt:stage
は定義されていないため、self:provider.stage
に定義されているdevが参照されます。
serverless deploy --stage production
が指定されている場合は、opt:stage
が定義されているためopt:stage
が優先して参照されます。
サービスの削除
あなたのつくったサービス内で、serverless remove
を実行してください。これでサービスがプロバイダー上から削除されます。
Tips
アクセスキーなど見せたくない情報をserverless.ymlで扱う
SSM秘匿パラメータの機能を使いましょう
https://serverless.com/framework/docs/providers/aws/guide/variables/#reference-variables-using-the-ssm-parameter-store