この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
どうも!大阪オフィスの西村祐二です。
サーバーレスアプリケーションを開発するときにServerless Frameworkを使って開発している人は多いのではないでしょうか。
Lambda関数、プラグインの設定、AWSリソースが増えてくるとserverless.ymlがどんどん長くなってきます。
拡張やメンテナンスなど行いやすくするために、今回、serverless.ymlの設定を外部のファイルから読み込むようにしてみたいと思います。
環境
- OS : macOS Mojave 10.14.3
- Node.js : v10.15.1
- Serverless Framework: 1.37.0
対象のserverless.yml
今回は下記のようなサンプルを用意しました。
複数のLambda関数、プラグイン、S3、DynamoDBのAWSリソースを管理した構成になっています。
下記のサンプルをもとに設定していきます。
serverless.yml
service: test-blog # NOTE: update this with your service name
provider:
name: aws
runtime: python3.7
stage: v1
apiName: ${self:custom.env}-${self:service}
environment:
DYNAMODB_TABLE: ${self:custom.env}-${self:service}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
plugins:
- serverless-dynamodb-local
custom:
env: ${opt:env, 'itg'}
dynamodb:
start:
port: 8000
inMemory: true
migrate: true
seed: true
seed:
development:
sources:
- table: ${self:provider.environment.DYNAMODB_TABLE}
sources: [./data/test.json]
package:
individually: true
include:
- handler.py
exclude:
- "**"
functions:
hello:
handler: handler.hello
events:
- http:
path: sample/test
method: get
create:
handler: handler.create
events:
- http:
path: todos
method: post
cors: true
list:
handler: handler.list
events:
- http:
path: todos
method: get
cors: true
get:
handler: handler.get
events:
- http:
path: todos/{id}
method: get
cors: true
update:
handler: handler.update
events:
- http:
path: todos/{id}
method: put
cors: true
delete:
handler: handler.delete
events:
- http:
path: todos/{id}
method: delete
cors: true
resources:
Resources:
testS3Bucket:
Type: "AWS::S3::Bucket"
Properties:
BucketName: hoge-ynishimura-bucket
testTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.env}-${self:service}
AttributeDefinitions:
- AttributeName: email
AttributeType: S
KeySchema:
- AttributeName: email
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
IAMに関する設定を外部ファイルから読み込むようにする
configというディレクトリを作り、そこの配下にiam.ymlを作成します。(これは任意で各々で適切な形で作成してください。)
そこに、IAMの設定を書き出します。
嬉しい点としては外部から設定を読み込む形にしても${self:provider.environment.DYNAMODB_TABLE}
など変数をきちんとパースして認識してくれるところです。
./config/iam.yml
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
serverless.yml
は下記のようにfileプロパティを使うことで読み込むことができます。
serverless.yml
environment:
DYNAMODB_TABLE: ${self:provider.custom.env}-${self:service}
iamRoleStatements: ${file(./config/iam.yml)}
plugins:
- serverless-dynamodb-local
どのように読込されるかの動作確認としては下記コマンドで簡単に確認できます。
$ sls print
service: test-blog
provider:
stage: v1
apiName: itg-test-blog
name: aws
runtime: python3.7
environment:
DYNAMODB_TABLE: itg-test-blog
iamRoleStatements:
- Effect: Allow
Action:
- 'dynamodb:Query'
- 'dynamodb:Scan'
- 'dynamodb:GetItem'
- 'dynamodb:PutItem'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource: 'arn:aws:dynamodb:us-east-1:*:table/itg-test-blog'
plugins:
- serverless-dynamodb-local
.
.
.
プラグインの設定を外部から読み込む
先程と同様に下記のようにプラグインの設定を外出しします。
./config/plugin/serverless-dynamodb-local.yml
start:
port: 8000
inMemory: true
migrate: true
seed: true
seed:
development:
sources:
- table: ${self:provider.environment.DYNAMODB_TABLE}
sources: [./data/test.json]
serverless.yml
は下記のようにfileプロパティを使うことで読み込むことができます。
serverless.yml
plugins:
- serverless-dynamodb-local
custom:
env:
dynamodb: ${file(./config/plugin/serverless-dynamodb-local.yml)}
package:
・
・
・
Lambda関数のイベントに関する設定を外部から読み込む
今回、configディレクトリ配下にevents.yml
を作成し、そこから読み込むようにしてみました。
下記のように、各Lambdaのイベントの設定を書き出します。
./config/events.yml
hello_event:
- http:
path: sample/test
method: get
create_event:
- http:
path: todos
method: post
cors: true
list_event:
- http:
path: todos
method: get
cors: true
get_event:
- http:
path: todos/{id}
method: get
cors: true
update_event:
- http:
path: todos/{id}
method: put
cors: true
delete_event:
- http:
path: todos/{id}
method: delete
cors: true
serverless.yml
は下記のようにfileプロパティのあとにキーを指定することで個別に読み込むことができます。
serverless.yml
functions:
hello:
handler: handler.hello
events: ${file(./config/events.yml):hello_event}
create:
handler: handler.create
events: ${file(./config/events.yml):create_event}
list:
handler: handler.list
events: ${file(./config/events.yml):list_event}
get:
handler: handler.get
events: ${file(./config/events.yml):get_event}
update:
handler: handler.update
events: ${file(./config/events.yml):update_event}
delete:
handler: handler.delete
events: ${file(./config/events.yml):delete_event}
resources:
AWSリソースのcfnテンプレートを外部から読み込む
今回、configディレクトリ配下にcfnディレクトリを作りs3.yml
とdynamodb.yml
に分けて、そこから読み込むようにしてみました。
下記のように、cfnテンプレートの設定を書き出します。
./config/cfn/s3.yml
Resources:
testS3Bucket:
Type: "AWS::S3::Bucket"
Properties:
BucketName: hoge-ynishimura-bucket
./config/cfn/dynamodb.yml
Resources:
testTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.env}-${self:service}
AttributeDefinitions:
- AttributeName: email
AttributeType: S
KeySchema:
- AttributeName: email
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
注意点としてはResources
ではじまるように記述しないといけないところです。
https://serverless.com/framework/docs/providers/aws/guide/variables#multiple-configuration-files
serverless.yml
は下記のようにfileプロパティを使ってファイルを指定するだけでcfnテンプレートを読み込むことができます。
serverless.yml
delete:
handler: handler.delete
events: ${file(./config/events.yml):delete_event}
resources:
- ${file(./config/cfn/s3.yml)}
- ${file(./config/cfn/dynamodb.yml)}
最終的なserverless.yml
最終的なserverless.ymlは下記のようになりました。
ある程度スッキリしたのではないでしょうか。
serverless.yml
service: test-blog # NOTE: update this with your service name
provider:
name: aws
runtime: python3.7
stage: v1
apiName: ${self:custom.env}-${self:service}
environment:
DYNAMODB_TABLE: ${self:custom.env}-${self:service}
iamRoleStatements: ${file(./config/iam.yml)}
plugins:
- serverless-dynamodb-local
custom:
env: ${opt:env, 'itg'}
dynamodb: ${file(./config/plugin/serverless-dynamodb-local.yml)}
package:
individually: true
include:
- handler.py
exclude:
- "**"
functions:
hello:
handler: handler.hello
events: ${file(./config/events.yml):hello_event}
create:
handler: handler.create
events: ${file(./config/events.yml):create_event}
list:
handler: handler.list
events: ${file(./config/events.yml):list_event}
get:
handler: handler.get
events: ${file(./config/events.yml):get_event}
update:
handler: handler.update
events: ${file(./config/events.yml):update_event}
delete:
handler: handler.delete
events: ${file(./config/events.yml):delete_event}
resources:
- ${file(./config/cfn/s3.yml)}
- ${file(./config/cfn/dynamodb.yml)}
また、分割した設定ファイルとserverless.ymlのディレクトリ構成は下記のようになっています。(他の関連ファイルは非表示)
.
├── config
│ ├── cfn
│ │ ├── dynamodb.yml
│ │ └── s3.yml
│ ├── events.yml
│ ├── iam.yml
│ └── plugin
│ └── serverless-dynamodb-local.yml
└── serverless.yml
さいごに
いかがだったでしょうか。
serverless.ymlの設定を外部のファイルから読み込むようにしてみました。
イベント、AWSリソースだけでも外部ファイルから読み込むようにするとかなりスッキリするのではないでしょうか。
また、他にもいろいろ試していたのですが、かなり柔軟性があり、コマンド引数によって動的に読み込む設定を切り替えたりもできますので、興味のある方は是非試してみてください。
誰かの参考になれば幸いです。