serverless deployで何が更新されるのか確認してみました(Serverless Framework / AWS)

2020.07.08

はじめに

Serverless FrameworkをAWS環境に対してサービスの作成・更新・削除で利用する場合に、実際にはどのAWSサービスのリソースが変更されているのか、というのがなんとなくわかっていたけど曖昧だったのと、実際に動かしてみたくなったため、各コマンドについて動かしつつ整理してみることにしました。

前提

  • 作業環境
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G4032
  • 執筆時点で最新(Latest release: 1.68.0)のバージョンでの動作を確認しています
  • AWSで利用する場合 について記載しています
  • AWS CLIの結果をターミナル上で整形するためにjqを利用しています

まとめ

やってみた結果は次の通りでした。

コマンド CloudFormationスタック それ以外(Lambda, API Gateway, S3, etc...)
1. deploy 更新する 更新する※
2. deploy function 更新しない 更新する
3. remove 更新する 更新する※

※注 スタックの更新に伴い間接的に更新

ちなみに、service名+stage名がスタック名として自動設定されるため、同じservice名&同じstageで同じリージョンに対するserverless.ymlを作ると以前の設定が上書きされるので要注意です。(定義していないリソースは、消えます。)

やってみたこと

やってみた結果わかったことは「まとめ」のセクションに書いたとおりですが、実際に確認したプロセスを記載します。

サービスの新規作成

1. テンプレートからサービスを作成

作業用ディレクトリを作成して、その中に新規サービスをテンプレートから作成します

$ mkdir app
$ cd app
$ serverless create --template aws-nodejs

2. -v オプションを付けてデプロイ実行してログを追ってみる

deployコマンドに -v を付けて実行します。 リソースの作成に関係しそうな部分としては以下の表示がありました。

$ serverless deploy -v
CloudFormation - CREATE_COMPLETE - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_COMPLETE - AWS::S3::BucketPolicy - ServerlessDeploymentBucketPolicy
CloudFormation - CREATE_COMPLETE - AWS::CloudFormation::Stack - app-dev
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service app.zip file to S3 (389 B)...
CloudFormation - CREATE_COMPLETE - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_COMPLETE - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Version - HelloLambdaVersionWmPiX0uxnqMasoXkiuYJx9ARiVG14cpohy5OECjVrA

ここからやっぱりCloudFormationを使ってバケットとかビルド成果物のアップロード等を行っているんだな、ということは分かりました。

3. 生成されたリソースを整理してみる

2.で作成されたリソースに加え、ローカルにも中間ファイルが作成されています。 それらも含めて整理すると、deployコマンド実行後は次のようなリソースが出来上がっていました。

  • 作業マシン側
    • コードのzip
    • 内部的に使うCloudFormationテンプレート
  • AWS側
    • CloudFormationスタック
    • デプロイ中間ファイル配置用S3バケット
    • LambdaのIAMロール
    • Lambdaのロググループ
    • Lambdaのfunction

サービスの更新

更新パターンについて

サービスの更新を行うパターンは次の2つがあります。

  • serverless deploy
  • serverless deploy function

serverless deploy コマンドによる更新は「サービスの新規作成」のセクションで記述した挙動と同じでCloudFormationスタックの更新が行われますが、serverless deploy functionを実行する場合にはスタックの更新は行われません。

Serverless Framework Commands - AWS Lambda - Deploy Function https://serverless.com/framework/docs/providers/aws/cli-reference/deploy-function/

The sls deploy function command deploys an individual function without AWS CloudFormation

serverless deploy function による更新をやってみた

1. ソースを修正

handler.jsの出力メッセージ部分を編集します。 「Go Serverless〜」という文言を「Goo Serverless」に編集します。

$ sed -n 8p handler.js 
message: 'Go Serverless v1.0! Your function executed successfully!!',
$ sed -i '' '8s/Go/Goo/' handler.js 
$ sed -n 8p handler.js 
message: 'Goo Serverless v1.0! Your function executed successfully!!',
2. デプロイ

serverless deploy function によって指定した関数のみをデプロイします。

  • デプロイ前にスタックの更新時刻を確認
$ aws cloudformation describe-stacks --stack-name app-dev --region us-east-1 | jq .Stacks[].LastUpdatedTime
"2020-04-27T14:01:14.579Z"
  • デプロイ実行
$ sls deploy function --function hello
Serverless: Packaging function: hello...
(中略)
Serverless: Successfully updated function: hello
  • デプロイ後にスタックの更新時刻を確認
$ aws cloudformation describe-stacks --stack-name app-dev --region us-east-1 | jq .Stacks[].LastUpdatedTime
"2020-04-27T14:01:14.579Z"

serverless deploy function 前後で確認したスタックの更新時刻から、スタックは更新されていないことが分かります。

serverless deploy による更新

新規作成時と同じ挙動なので、確認したプロセスは割愛します。

サービスの削除

serverless remove によってリソースを削除してみました。 なるべく内部の挙動を確認したかったので -v を付けて実行しました。

$ sls remove -v
:
CloudFormation - DELETE_COMPLETE - AWS::S3::BucketPolicy - ServerlessDeploymentBucketPolicy
:
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction
:
Serverless: Stack removal finished...

removeコマンドの実行結果からは、CloudFormationを通じてS3のデプロイメントバケットやLambda関数が削除されたことを確認できました。

$ aws cloudformation list-stack-resources --stack-name app-dev --region us-east-1

An error occurred (ValidationError) when calling the ListStackResources operation: Stack with id app-dev does not exist

スタックが削除されていることも確認できました。

サービス名が同じで、リソースの定義が違うセットを用意します。「サービスの新規作成」「サービスの更新」で用意したディレクトリをコピーして、関数名だけ変更したものを用意しました。

$ cp -r app app2
$ vim app2/serverless.yml
$ diff app app2
diff app/serverless.yml app2/serverless.yml
61c61
<   hello:
---
>   hello2:

まず1つ目のディレクトリで serverless deploy を行います

$ cd app
$ sls deploy

次に、2つめのディレクトリでは -v オプションを付けて serverless deploy を行います

$ cd app2
$ sls deploy -v

すると、stack名が同じ(service名とstage名が同じ)であるため、「hello」関数の定義が差分として検出され、削除されました

CloudFormation - DELETE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction

この状態で1つめのディレクトリへ移動して serverless remove コマンドを実行してみます( -v オプションを付けて )

$ cd app
$ sls remove -v

すると、2つめのディレクトリ内で定義していた関数もすべて削除されました。

CloudFormation - DELETE_COMPLETE - AWS::S3::BucketPolicy - ServerlessDeploymentBucketPolicy
:
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Function - Hello2LambdaFunction

つまり、service名とstage名が同じ組み合わせのファイルを別々に作成すると、片方の設定が最新として処理されるため注意が必要です。

参考

  • Serverless Framework Documentation https://www.serverless.com/framework/docs/