何をするか?
AWS CloudFormation を使うと Lambda 関数を含むインフラ(AWS リソース群)をまとめて生成することができますが、AWS CloudFormation の拡張である AWS SAM を使うと、もっと簡潔に Lambda 関数のリソースを生成することができます。
例えば、CloudFormation テンプレートの AWS::Lambda::Function
リソースでは、Role
プロパティが必須でしたが、SAM テンプレートの AWS::Serverless::Function
リソースでは、Role
プロパティはオプショナルになっています。
Role
プロパティを省略すると、Lambda 関数に付けた論理 ID (Logical ID) をもとに、<論理ID>Role
という名前のロールが自動生成されます。
ここでは、AWS SAM を使った Lambda 関数生成の基本として、次のようなパターンで CloudFormation スタックを生成してみます。
- SAM テンプレートに関数コードを埋め込んでデプロイ
- S3 バケット上の関数の ZIP ファイルを使ってデプロイ
SAM テンプレートに関数コードを埋め込んでデプロイ
まずは、一番シンプルな例として、SAM テンプレート内に Lambda 関数の実装をハードコーディングしてしまい、それをデプロイ(CloudFormation スタックの生成)してみます。
下記が SAM テンプレートです。
SAM で Lambda 関数のリソースを定義するときは、リソースタイプとして AWS::Serverless::Function
を指定します(CloudFormation では AWS::Lambda::Function
です)。
ここでは関数の実装を InlineCode
プロパティでハードコーディングし、単純な Hello World!
メッセージをレスポンスとして返すようにしています。
この例では省略していますが、Function
リソースのプロパティ PackageType
はデフォルトで Zip
となっており、この場合は、関数の実体を CodeUri
(ZIP ファイルのパス)か、InlineCode
(ハードコーディング)のどちらかで指定します。
この例では、InlineCode
で関数の内容を埋め込んでいます。
SAM テンプレートを記述したら、次のようにして CloudFormation のスタックを生成できます。
Lambda 関数のサービスロール(実行ロール)を自動生成するために、--capabilities CAPABILITY_IAM
オプションの指定が必要です。
スタックの作成が完了したら、次のようにしてスタック情報を確認できます。 スタック内に生成された Lambda 関数リソースの情報を見てみましょう。
作成された Lambda 関数リソース (AWS::Lambda::Function
) の PhysicalResouceID
を見ると、Lambda 関数の物理 ID (Physical ID) が、スタック名と論理 ID (Logical ID) の組み合わせで自動的に作成されていることが分かります(ここでは mystack-HelloFunction-1DVW05LYWG4L2
)。
この物理 ID は、Lambda のマネージメントコンソール上で関数名として表示される名前です。
つまり、CloudFormation の外の世界から見える名前であり、アカウント内で一意な Lambda 関数名です。
Lambda 関数の物理 ID が分かれば、次のように CLI からテスト実行することができます。
最後に CloudFormation のスタックを削除しておきます。
これで、スタック内に生成した Lambda 関数(およびそれ用のロール)などのリソースが全て消え去ります。すっきりすっきり。
S3 バケット上の関数の ZIP ファイルを使ってデプロイ
外部ライブラリなどを利用する Lambda 関数を作成する場合は、それらをまとめて ZIP 化して S3 バケットにアップロードしておく必要があります。 SAM テンプレート(CloudFormation テンプレート)では、S3 バケット上の ZIP ファイルを参照して Lambda 関数リソースを生成するように記述します。
S3 バケットに Lambda 関数の ZIP をアップロード
まずは ZIP ファイル置き場にする S3 バケットを作成しておきます。 関数のコード自体は GitHub などで管理するでしょうから、この S3 バケットは一時的な転送用のバッファ、くらいの感覚で使えばよいと思います。
ここでは、次のような Lambda 関数コードを ZIP 化することにします(簡単にするため依存ライブラリはなし)。
src
ディレクトリ内のコードを ZIP ファイルにまとめます。
あとは、次のように S3 バケットにアップロードします。
S3 バケットの ZIP を使って Lambda 関数をデプロイ(CloudFormation スタックを生成)
SAM テンプレート内から、S3 バケット上の ZIP ファイルを参照するには次のように記述します。
InlineCode
プロパティで関数実装をハードコードしていた部分を削除し、CodeUri
プロパティで S3 バケット上の ZIP ファイルを指定するようにします。
スタックの生成コマンドは、前述の例と同じです。
(応用)S3 への ZIP アップロードも CloudFormation で行う
上記の例では、aws s3 cp
コマンドで Lambda 関数の ZIP ファイルを S3 バケットにアップロードしていましたが、aws cloudformation package
コマンドで同様のことを行うことができます。
前提条件として、ローカルに function.zip
の作成はできているとします。
SAM テンプレートを次のように書き換えます。
変更点は、CodeUri
プロパティの値が、S3 バケット上の ZIP オブジェクトではなく、ローカルファイルを示す function.zip
になっているところです。
次のように実行すると、ローカルの function.zip
ファイルが --s3-bucket
オプションで指定した S3 バケットにアップロードされ、新しい SAM テンプレートファイル (template-pkg.yml
) が生成されます。
生成される SAM テンプレートの内容は次のようになっています。
CodeUri
の値が置換されており、S3 バケット上にアップロードされた ZIP ファイルを示す URI に変わっています。
オブジェクト名は function.zip
ファイルのハッシュコードになっており、ZIP ファイルの内容が変わるとオブジェクト名も変わるようになっています(つまり、package
するたびに、S3 バケット内に別名の ZIP ファイルが溜まっていきます)。
あとは、前述の例と同様に、自動生成された SAM テンプレートを使って、CloudFormation スタックを生成するだけです(template.yml
ではなく、自動生成された template-pkg.yml
を指定することに注意してください)。
(応用)ZIP パッケージ化も CloudFormation で行う
ここまでは、ローカルに Lambda 関数用の ZIP ファイルを作成しておく前提でしたが、実は ZIP 化と S3 へのアップロードは aws cloudformation package
コマンドでまとめて行うことができます。
例えば、プロジェクトのディレクトリ構成が次のようになっていて、src
以下のファイル群を ZIP 化したいとします。
SAM テンプレート内の CodeUri
プロパティ で、ZIP ファイル名の代わりに src
ディレクトリを指定するようにします。
Handler
プロパティは、src
ディレクトリからの相対パスで指定します。
あとはこれまでと同様に、次のように package
コマンドを実行します。
すると、src
ディレクトリ内のファイル群が内部的に ZIP 化されて S3 バケットにアップロードされます(ローカルに ZIP ファイルは生成されません)。
CodeUri
が S3 バケットの URI に書き換わったテンプレートが生成されるので、次のように deploy
コマンドで CloudFormation スタックを生成(更新)すればデプロイ完了です。
この方法の注意点としては、CodeUri
で指定したディレクトリ(ここでは src
)の下のファイル群がすべて ZIP にパッケージングされてしまう という点です。
カスタマイズされた方法で ZIP パッケージを作成したい場合(特定のファイルを含めたくないときなど)は、この方法は使えないかもしれません。