TL; DR
sam build でビルド先ディレクトリの出力先を指定した場合は、 sam package で --template-file を指定しましょう。
そうでない場合(殆どが指定しないと思います)は、指定しない方が無難です。
はじめに
下記のような記事がありました。
私も最初は sam package に --template-file オプションを付けて苦しめられていたため、参考になりました。
ローカルでビルドしたものをpackageするときは --template-file オプションはつけない - Qiita
では、逆に --template-file を指定するのはいつなのか、調べてみました。
フローの種類
sam build と sam package の挙動を知るには、ビルド手順を追うと分かりやすいです。
そこで、本章ではアプリケーションビルド手順を順次追っていきます。
SAM-CLIによるアプリケーションビルド手法は、次の4種類があります。
- deploy
- build -> deploy
- build -> package -> deploy
- build -> package -> publish
各フローについて、それぞれ説明します。
今回は、Node.jsによるLambdaアプリケーションのSAMテンプレートファイルを用いて説明します。
そのため、一部に npm コマンドの比喩が登場します。
Node.js固有の問題は無いと思うので、LambdaランタイムがPythonの場合はpipと読替えるなど、よしなに読んでください。
deploy
直接デプロイする手法です。
デプロイとは、テンプレートファイルで指定したディレクトリを直接SAMアプリケーション(CloudFormationスタック)として生成することです。
そのため、 --template-file で指定したテンプレートファイルの中身にアプリケーションリソースのURLを指定している必要があります。
sam deploy --template-file template.yaml
application/
|- sample-app/
| |- node_modules/*
| |- package.json
| |- index.js
|
|- template.yaml
Resources:
DirectlyDeploymentFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./sample-app/
Handler: index.handler
Runtime: nodejs12.x
Description: ローカルの sample-app/index.js ファイルにおける index.handler をAWS Lambdaに展開
直接デプロイする際は、テンプレートファイルの CodeUri で指定しているディレクトリ内のソースコードを実行できる必要があります(npm run などの実行スクリプトが動作可能な状態である必要がある、という意味です)。
依存ライブラリなどがある場合は、事前に npm install などでインストールしておきましょう。
sam deploy - AWS サーバーレスアプリケーションモデル
build -> deploy
ビルドしてからデプロイする手法です。
ビルドとは、 テンプレートファイル自身、および、テンプレートファイルの CodeUri で指定しているディレクトリをコピーした「ビルド先ディレクトリ」の2つを生成し、生成先ディレクトリ内の package.json や requirement.txt を再帰的に探し、 npm install を実施することです。
既定では、 .aws-sam/build/ ディレクトリ内にコピーしますが、 --build-dir オプションで出力先を変更できます。
デプロイ時のテンプレートファイルは、既定では .aws-sam/build/ ディレクトリ内の template.yaml または template.yml ファイルを取込みます。
そのため、 --template-file での指定は必要ありません。
しかも、 .aws-sam/build/ ディレクトリ内のテンプレートファイルに書いてある CodeUri は、自動で書換えられます。
sam build
sam deploy
application/
|- sample-app/
| |- package.json
| |- index.js
|
|- .aws-sam/
| |- build/
| |- DeploymentBuildedFunction/
| | |- node_modules/*
| | |- package.json
| | |- index.js
| |
| |- template.yaml
|
|- template.yaml
Resources:
DeploymentBuildedFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: DeploymentBuildedFunction # 書換えられている
Handler: index.handler
Runtime: nodejs12.x
Description: ローカルの .aws-sam/build/index.js ファイルにおける index.handler をAWS Lambdaに展開
コピー先ディレクトリ .aws-sam/build/ 内で npm install をするため、 sample-app/ ディレクトリ内での npm install は必要ありません。
sam build - AWS サーバーレスアプリケーションモデル
build -> package -> deploy
ビルド/パッケージングしてデプロイする手法です。
パッケージングとは、作業中PC(SAM-CLIを実行しているPCのこと)のソースコードを指定したS3バケットにパッケージングしてアップロードすることです。
そして、指定したS3バケットのURLを示すように CodeUri を書換えたテンプレートを出力します。
なぜか既定では標準出力に出力しますが、 --output-template-file オプションでファイル出力ができます。
デプロイする際は、パッケージングで出力されたテンプレートファイルを指定します。
sam build
sam package \
--s3-bucket UploadedApplication \
--output-template-file output-template.yaml # 出力ファイルを指定する
sam deploy --template-file output-template.yaml # sam packageコマンドで出力されたファイルを指定する
application/
|- sample-app/
| |- package.json
| |- index.js
|
|- .aws-sam/
| |- build/
| |- DeploymentPackagedFunction/
| | |- node_modules/*
| | |- package.json
| | |- index.js
| |
| |- template.yaml
|
|- output-template.yaml
|- template.yaml
Resources:
DeploymentPackagedFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: s3://UpploadedApplication/xxxxxxxx # --s3-bucket オプションで指定したディレクトリ先のランダムな名前のパッケージファイル
Handler: index.handler
Runtime: nodejs12.x
Description: S3バケットのパッケージファイルにおける index.handler をAWS Lambdaに展開
前節を読んだ方はお気づきかと思いますが、パッケージングする際の入力テンプレートファイルは、 .aws-sam/build/ ディレクトリ内のテンプレートファイルです。
また、パッケージング対象は、上記で(明示的または暗黙的に)指定したテンプレートファイルの CodeUri で指定しているディレクトリです。
パッケージファイルにテンプレートファイル自身は含まれません。
sam package - AWS サーバーレスアプリケーションモデル
build -> package -> publish
ビルド/パッケージングして発行(パブリッシュ)する手順です。
発行(パブリッシュ)とは、SAR (Serverless Application Repository) と呼ばれる公開可能なアプリケーションリポジトリにテンプレートファイルを登録することです。
--template-file オプションで指定したテンプレートファイルを、AWSのクラウドサービスに登録するため、ローカルパスを指定しているパッケージング前のテンプレートファイルではなく、S3バケットを指定しているパッケージング後のテンプレートファイルを指定する必要があります。
sam build
sam package \
--s3-bucket UploadedApplication \
--output-template-file output-template.yaml
sam publish --template-file output-template.yaml
- sam publish - AWS サーバーレスアプリケーションモデル
- AWS Serverless Application Repository(サーバーレスアプリを検索、デプロイ、公開)| AWS
- AWS Serverless Application Repository とは - AWS Serverless Application Repository
なお、2020年6月時点では、SARに発行したアプリケーションをデプロイする場合、AWSマネジメントコンソール上で手動デプロイするか、AWS-CLIを使う必要があります。
sam publish した際にアプリケーションARNを出力してくれるため、 aws serverlessrepo コマンドでデプロイすれば良いです。
本記事では話がズレてしまうため、詳細は省略します。
アプリケーションをデプロイする方法 - AWS Serverless Application Repository
ローカルでビルドしたものを package するときに --template-file オプションを付けるタイミング
本題です。
結論を先に言ってしまうと、ローカルでビルドしたものを package するときに --template-file オプションを付けるタイミングとは、__ビルド先のディレクトリを変更した場合__です。
ビルドの振舞いが理解できれば、パッケージングの振舞いも理解できると思います。
sam build は、既定ではテンプレートファイルの CodeUri で指定しているディレクトリを .aws-sam/build/ ディレクトリにコピーすると書きました。
また、 sam package は、既定では .aws-sam/build/ ディレクトリ内のテンプレートファイルを呼出してパッケージファイルをS3にアップロードすると書きました。
つまり、 sam build でビルド先(コピー先)ディレクトリを --build-dir オプションで書換えた場合、 sam package でテンプレートファイルを --template-file で指定する必要があります。
sam build \
--build-dir builded-sample-app/ # ここで出力先を指定すると
sam package \
--s3-bucket UploadedApplication \
--template-file builded-sample-app/template.yaml \ # ここで入力先を指定する必要がある
--output-template-file output-template.yaml
sam deploy --template-file output-template.yaml
application/
|- sample-app/
| |- package.json
| |- index.js
|
|- builded-sample-app/
| |- DeploymentPackagedFunction/
| | |- node_modules/*
| | |- package.json
| | |- index.js
| |
| |- template.yaml
|
|- output-template.yaml
|- template.yaml
次のような場合に使えると思います。
- 複数のアプリケーションを1つのディレクトリ内でデプロイしたい
- ネステッドスタックを作りたい(ビルドを2回する必要がある)
おわりに
SAM-CLIの挙動は、チュートリアルからでは全く理解できませんが、少しずつ理解していくと意外とシンプルです。
Serverlessの時代、SAMを使ってAWSゾッコンになっていきましょう!