[アップデート]AWS SAM CLIのsam syncコマンドが一定条件下でドリフトの生成をスキップするようになりました

2023.03.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

初めに

Release 1.78.0 - SAM Accelerate Skip Infra Sync and Python3.10 Support Latest

AWS SAM CLI v1.78.0においてsam syncの実行時に一定条件下でスタックのドリフトのスキップをコントロールするオプションの --no-skip-deploy-syncおよび--skip-deploy-syncオプションが追加されました。

変更について

これまではsam syncの実行直後にはSAMテンプレートには変更がなくともドリフトを発生させる仕様でしたが、 今回実行前後のテンプレートの単純比較で変更がなかった場合はこのドリフトをスキップする機能が追加されました。

これまでの挙動が--no-skip-deploy-syncの動作、今回追加された挙動が--skip-deploy-syncとなります。

また今後はsam sync実行時のデフォルトの動作が--skip-deploy-syncに変更されます。

これまで通り実行時にドリフトを発生させたい場合は明示的に--no-skip-deploy-syncを指定する必要が出てきます。

What's newのにまだ上がっていませんがドキュメントは既に更新され該当のオプションが追加されていました。

Using the AWS SAM CLI sam sync command - Skip the initial AWS CloudFormation deployment

ただし--skip-deploy-syncが明示的に指定されている場合であっても
前回の実行から7日が経過もしくは一定以上のLambda関数のコードに変更が入っている場合はオプションの指定状況に関わらずドリフトが生成されます。

Using the AWS SAM CLI sam sync command - Skip the initial AWS CloudFormation deployment
- If its been 7 days or more since your last AWS CloudFormation deployment.
- If a large number of Lambda function code changes are detected, making AWS CloudFormation deployment the quickest method to update your application.

ちなみに大量の変更というのはいくつだろうと思ったのですがコードを流し見する限り具体的には50以上のようです。
(SYNC_FLOW_THRESHOLDの値より)

具体的にはこの辺りの変更となるので興味のある方はコードを読んでみてはいかがでしょうか。
https://github.com/aws/aws-sam-cli/compare/v1.77.0...v1.78.0

また7日については最後にsam syncを実行したタイミングではなくドリフトが実行されてタイミングのようです。

ただしこの比較となる値はCloudFormation側に見に行っているわけではなくsync.tomlに記載されている値を読んでいるようなので、
手動で調整すれば実際は7日過ぎていても無理やりスキップが可能とは思われます(やらない方がいい気はしますが...)。

 [sync_state]
 dependency_layer = true
 latest_infra_sync_time = "2023-03-24T18:13:34.750262"

実際に試してみる

準備

SAM CLIのバージョンは今回リリースされた1.78.0を利用します。

% sam --version
SAM CLI, version 1.78.0

サンプルの適当なプロジェクトを作成しまずはベースとなるコードをデプロイしておきます。

$ sam init
#Hello Worldのサンプルで作成しています
...
$ sam deploy
....

しばらく前はsamconfig.tomlは手動で作るかdeploy時に--guidedオプションを指定するなどで作らないといけなかったような気がするのですがいつの間にかinit時に作成されるようになっていました。

--no-skip-deploy-syncを指定し実行する

まずはこれまで相当の挙動を改めて確認してみます。

上記の準備処理の後特に何も変更を行わずsam sync --no-skip-deploy-syncを実行します。

% sam sync --no-skip-deploy-sync
...

	Deploying with following values
	===============================
	Stack name                   : sam-app
	Region                       : ap-northeast-1
	Disable rollback             : False
	Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-xxxxxx
	Capabilities                 : ["CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
	Parameter overrides          : {}
	Signing Profiles             : null

Initiating deployment
=====================


2023-03-25 02:37:07 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 0.5 seconds)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                     ResourceType                                       LogicalResourceId                                  ResourceStatusReason
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
UPDATE_IN_PROGRESS                                 AWS::CloudFormation::Stack                         sam-app                                            User Initiated
UPDATE_IN_PROGRESS                                 AWS::CloudFormation::Stack                         sam-app                                            Transformation succeeded
UPDATE_IN_PROGRESS                                 AWS::CloudFormation::Stack                         AwsSamAutoDependencyLayerNestedStack               -
UPDATE_COMPLETE                                    AWS::CloudFormation::Stack                         AwsSamAutoDependencyLayerNestedStack               -
UPDATE_COMPLETE_CLEANUP_IN_PROGRESS                AWS::CloudFormation::Stack                         sam-app                                            -
UPDATE_COMPLETE                                    AWS::CloudFormation::Stack                         AwsSamAutoDependencyLayerNestedStack               -
UPDATE_COMPLETE                                    AWS::CloudFormation::Stack                         sam-app                                            -
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
...
CodeTrigger not created as CodeUri or DefinitionUri is missing for ServerlessRestApi.
Infra sync completed.

CLI上の表示でスタックの開始が02:37:07
マネジメントコンソール上でスタックの更新完了が02:37:30のためおおよそ20秒ほどかかっています。

実際はスタックの作成までの時間もあるのでiTermの機能で表示されたタイミングを確認していたのですが全体としてはおおよそ30秒ほどです。 (検証のために何度か試しましたが割と早いケースした)

あくまでサンプルのデフォルトプロジェクトでの実施ですので内容によってはもっと長くなる可能性があります。

--skip-deploy-syncを指定し実行する

これまでの動作が確認できたので新しく追加されたオプションを試してみます。

 % sam sync --skip-deploy-sync

The SAM CLI will use the AWS Lambda, Amazon API Gateway, and AWS StepFunctions APIs to upload your code without
performing a CloudFormation deployment. This will cause drift in your CloudFormation stack.
**The sync command should only be used against a development stack**.

Queued infra sync. Waiting for in progress code syncs to complete...
Starting infra sync.
Manifest is not changed for (HelloWorldFunction), running incremental build
Building codeuri: /xxxx/sam-app/hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction
Running PythonPipBuilder:CopySource

Build Succeeded

Successfully packaged artifacts and wrote output template to file /var/folders/8m/xxxxx/T/xxxxxx.
Execute the following command to deploy the packaged template
sam deploy --template-file /var/folders/8m/xxxxx/T/xxxxx --stack-name <YOUR STACK NAME>

Template haven't been changed since last deployment, skipping infra sync...

スキップの判定が出るまでは先ほどとほとんど同じで7秒ほどでしたが、
スキップの部分は1秒もかからずほぼ一瞬でした。

ちょうどスキップ前にMFAの要求が出るため比較その点を基準としていますが、
入力直ほぼ一瞬で表示される感じです。

(コードを読む限り)嬉しいことにネストスタックにも対応していますが、
ファイル量が多くなると単純に比較量が増えるので多少変わってくるかもしれません。

ただ流石にドリフトを待つよりは早いのではないかなと思っています。

終わりに

今回のアップデートで条件次第でsam syncの起動が高速化する変更が行われました。

sam syncは一度起動してしまえば--codeオプションをつけた時を筆頭に高速に反映を適用可能です。

一度起動して仕舞えば早いとはいえ起動が遅いという地味にストレスになる部分が条件付きですが大きく改善したため是非試してみてはいかがでしょうか。

MFA入力失敗時の挙動が怪しい(余談)

検証している中で--skip-deploy-syncを指定しているにも関わらずなぜかドリフトが走るケースがありました。

試している限りどうもMFAの入力を途中に挟むような場合
MFAの入力に失敗あると次に実行する際に指定に関わらずドリフトがスキップされないケースがあるようです。

別タブ等で起動すると直るため環境変数か何かの周りでもしかしたらバグがあるのかもしれません(未報告)。