目的
アプリケーション構築で初めてSAMをデプロイしたので知識の整理として
前提
- AWSコンソール上でLambdaを作成済み
- ローカルでのpython環境がある(今回SAM化するLambdaがpython3.9のため)
AWS SAMの概要
AWS公式ドキュメントより抜粋(AWS Serverless Application Modelとは)
AWS Serverless Application Model (AWS SAM) は、Infrastructure as Code (IaC) を使用してサーバーレスアプリケーションを構築するためのオープンソースフレームワークです。
要するにSAMって?
- AWS CloudFormationの拡張機能
- CloudFormationよりも短い記述でテンプレートを定義できて迅速に構築することが可能
- テンプレートとLambdaのプログラムを一括管理できる
- Terraformに近いイメージでローカルでの修正、デプロイができる
今回のSAM化対象
①ConfigルールにてOwner
タグのついていない違反リソースを検知
②違反リソースの情報を取得しCloudTrailより作成者名(ARN、UserName)
を特定
③CloudTrailから取得した情報を元に違反リソースにOwner:作成者名
タグを付与
④結果をCloudWatach Logsに出力
⑤EventBridgeにて定期実行を設定
※ Lambdaの作成自体は説明しません
下記の機能をまるっと権限周り含めて自動でデプロイするスタックを作成する
Config:違反検知
Lambda:tag付与
CloudTrail:リソース作成者特定
EventBridge:Lambdaの自動定期実行
CloudWatach Logs:結果出力
SAM化の流れ
初めてのSAMなので今回はsamコマンドでAWS Quick Start Template を選択して必要なファイルを生成してから、個別に修正する方針とします。
Lambda作成
トリガーや権限なども含めLambdaを作成(今回はpython3.9で作成)
S3バケット作成
名前以外デフォルトで作成
このバケットにSAM化時のファイルやソースコードが保存され、CloudFormation実行時にスタックを作成している
SAM導入準備
ローカルのpython環境をLambdaのバージョンと揃える
pyenv global 3.9.10
AWS SAM CLIインストール
(SAMはCLIで操作するので下記をインストール。mac環境だと以下手順となる)
brew tap aws/tap brew install aws-sam-cli
SAMのインストール確認
sam --version
作業用のディレクトリ作成(ディレクトリの場所と名前はなんでもいい)
mkdir autotag-sam cd autotag-sam
SAMテンプレートを実装
sam initを実行すると対話形式でテンプレートの選択が開始される。
今回はHello World Exampleテンプレートを選択し、余分なファイルを削除修正していく
sam init で作られるテンプレートは現時点だと runtime python 3.9 がデフォルトで指定されるようなので、runtime を指定したい場合は init 時に –runtime オプションを指定
sam init
sam init実行時の対話形式 一部抜粋
Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 #AWS Quick Start Templatesを選択
Choose an AWS Quick Start application template 1 - Hello World Example 2 - Data processing 3 - Hello World Example with Powertools for AWS Lambda 4 - Multi-step workflow 5 - Scheduled task 6 - Standalone function 7 - Serverless API 8 - Infrastructure event management 9 - Lambda Response Streaming 10 - Serverless Connector Hello World Example 11 - Multi-step workflow with Connectors 12 - GraphQLApi Hello World Example 13 - Full Stack 14 - Lambda EFS example 15 - DynamoDB Example 16 - Machine Learning Template: 1 #Hello World Exampleを選択
Project name [sam-app]: auto-tag-lambda # 作成するSAMの名前を決定 ----------------------- Generating application: ----------------------- Name: auto-tag-lambda Runtime: python3.9 Architectures: x86_64 Dependency Manager: pip Application Template: hello-world Output Directory: . Configuration file: auto-tag-lambda/samconfig.toml Next steps can be found in the README file at auto-tag-lambda/README.md
公式テンプレートの中身
$ tree . ├── README.md ├── __init__.py ├── events │ └── event.json ├── hello_world │ ├── __init__.py │ ├── app.py │ └── requirements.txt ├── samconfig.toml ├── template.yaml └── tests ├── __init__.py ├── integration │ ├── __init__.py │ └── test_api_gateway.py ├── requirements.txt └── unit ├── __init__.py └── test_handler.py
必要なファイルのみに修正
- hello worldディレクトリはautotag-samに改名
$ tree . ├── README.md └── autotag-sam ├── app.py # Lambdaで実行されるソース ├── samconfig.toml #Lambdaの設定が記載されるファイル └── template.yaml # SAMの設定ファイル
削除/修正したファイルの用途説明
__init__.pyファイル
パッケージ内のモジュールをインポートする際に使用。今回はapp.pyが単独のモジュールとして機能するので削除events/ディレクトリ
,events/event.jsonファイル
Lambda関数がトリガーされる時に提供されるイベントの例を記述。今回はローカルでテストはしないので削除hello_world/ディレクトリ
,app.pyファイル
実際にLambdaのコードを記述するディレクトリ。app.pyに作成したLambdaのコードを記載する(別に名前はhello_worldじゃなくていい)test/ディレクトリ
テスト用のコードを格納するディレクトリ。今回はテストを実施しないため削除unit/ディレクトリ
ここの関数やメソッドの動作をテストするためのディレクトリ。今回は単体テストも実施しないため削除
残りのファイルを修正していく
SAM移行予定のLambdaを選択し、ダウンロードよりファンクションコード
とSAMファイル
の両方を取得する
autotag-sam配下を置き換える
- app.pyへダウンロードしたファンクションコード内の記述をコピー&ペースト
- template.ymlへダウンロードしたAWS SAMファイル内の記述をコピー&ペースト
template.ymlを調整する
修正点(下記以外はそのまま)
Handler: lambda_function.lambda_handler
↓
Handler: app.lambda_handler
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: An AWS Serverless Application Model template describing your function. Resources: mawatanabeautotag: # リソースの識別名(任意の値を設定) Type: AWS::Serverless::Function # リソースタイプ 作りたいLambdaの構成によって変わる Properties: CodeUri: . # Lambdaソースコードの場所 今回はapp.pyと同じ階層にあるためカレントディレクトリを指定 Description: '' MemorySize: 128 Timeout: 15 Handler: app.lambda_handler # Lambdaがコールされた時に、最初に実行される関数 Runtime: python3.9 Architectures: - x86_64 EphemeralStorage: Size: 512 EventInvokeConfig: MaximumEventAgeInSeconds: 21600 MaximumRetryAttempts: 2 DestinationConfig: {} PackageType: Zip Policies: - Statement: - Sid: lambdaconfigrule Effect: Allow Action: # 今回のlambdaに必要な権限など - cloudtrail:LookupEvents - config:GetComplianceDetailsByConfigRule - config:GetResourceConfigHistory - tag:TagResources - events:PutEvents - ec2:CreateTags Resource: '*' - Sid: AllowSendMessageToSlack Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: arn:aws:logs:*:*:* SnapStart: ApplyOn: None Events: Schedule1: Type: Schedule Properties: Schedule: cron(0 1 ? * FRI *) RuntimeManagementConfig: UpdateRuntimeOn: Auto
samconfig.tomlを調整する
version = 0.1 [default] [default.global.parameters] stack_name = "auto-tag-test" # CloudFormationに作成されるアプリのスタック名 [default.deploy] [default.deploy.parameters] s3_bucket = "auto-tag-sam-bucket" # 作成したS3バケットを指定 s3_prefix = "test" # 任意のプレフィックスを指定 confirm_changeset = true # 変更セットを確認した上でデプロイする capabilities = "CAPABILITY_NAMED_IAM" # 固定値 CloudFormationにスタック作成のIAM権限を与える disable_rollback = false # デプロイ失敗時にスタックをロールバックさせる region = "ap-northeast-1" image_repositories = [] resolve_s3 = false
ビルド
既存Lambdaソースの配置と設定ファイルの調整完了後、下記コマンドにてビルドを行う
sam build
コマンドを実行する際には、SAMテンプレートファイル(通常はtemplate.yaml
やtemplate.yml
)が存在するディレクトリにいる必要がある。
デプロイ
sam deploy
権限含めたリソースのCloudFromationスタックを作成してくれる
$ sam deploy ~~ 略 CloudFormation events from stack operations (refresh every 5.0 seconds) ----------------------------------------------------------------------------------------------------------------------------------------------------------------- ResourceStatus ResourceType LogicalResourceId ResourceStatusReason ----------------------------------------------------------------------------------------------------------------------------------------------------------------- CREATE_IN_PROGRESS AWS::CloudFormation::Stack auto-tag-test User Initiated CREATE_IN_PROGRESS AWS::IAM::Role mawatanabeautotagRole - CREATE_IN_PROGRESS AWS::IAM::Role mawatanabeautotagRole Resource creation Initiated CREATE_COMPLETE AWS::IAM::Role mawatanabeautotagRole - CREATE_IN_PROGRESS AWS::Lambda::Function mawatanabeautotag - CREATE_IN_PROGRESS AWS::Lambda::Function mawatanabeautotag Resource creation Initiated CREATE_IN_PROGRESS AWS::Lambda::Function mawatanabeautotag Eventual consistency check initiated CREATE_IN_PROGRESS AWS::Lambda::EventInvokeConfig mawatanabeautotagEventInvokeConfig - CREATE_IN_PROGRESS AWS::Events::Rule mawatanabeautotagSchedule1 - CREATE_IN_PROGRESS AWS::Lambda::EventInvokeConfig mawatanabeautotagEventInvokeConfig Resource creation Initiated CREATE_IN_PROGRESS AWS::Events::Rule mawatanabeautotagSchedule1 Resource creation Initiated CREATE_COMPLETE AWS::Lambda::EventInvokeConfig mawatanabeautotagEventInvokeConfig - CREATE_COMPLETE AWS::Lambda::Function mawatanabeautotag - CREATE_IN_PROGRESS AWS::Events::Rule mawatanabeautotagSchedule1 Eventual consistency check initiated CREATE_IN_PROGRESS AWS::Lambda::Permission mawatanabeautotagSchedule1Permission - CREATE_IN_PROGRESS AWS::Lambda::Permission mawatanabeautotagSchedule1Permission Resource creation Initiated CREATE_COMPLETE AWS::Lambda::Permission mawatanabeautotagSchedule1Permission - CREATE_COMPLETE AWS::Events::Rule mawatanabeautotagSchedule1 - CREATE_COMPLETE AWS::CloudFormation::Stack auto-tag-test - ----------------------------------------------------------------------------------------------------------------------------------------------------------------- Successfully created/updated stack - auto-tag-test in ap-northeast-1
デプロイ実施後
CloudFormation
作成されたLambda(関数名がとても長い。。)
作成されるLambdaの命名について
SAMでLambda関数をデプロイするとき、関数名の末尾に自動生成されたランダムな文字列が付与されます。
これはSAMがCloudFormationのスタック内でリソース名が一意になるようにするためのメカニズムです。
解決策
特定の名前を使いたい場合は、SAMテンプレートで FunctionName プロパティにて設定することができる。
下記設定後、再度ビルド、デプロイを実施することで反映することが可能
template.ymlの修正
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: An AWS Serverless Application Model template describing your function. Resources: mawatanabeautotag: Type: AWS::Serverless::Function Properties: FunctionName: AutoTagFunction # ここにFunctionNameを追加 CodeUri: . Description: '' ~~ 略
テンプレート修正後再度デプロイ
まとめ
LambdaをSAM化をしてみて感じたメリットとしては、一度作成してしまえば他のAWSアカウントなどにも複数のリソースを一括で作成、削除できる部分が強みかなと感じました。
SAM化にあたってやっていることもSAM CLIのインストール、テンプレートの調整のみで実装が出来たのでとても簡単でした。Lamdaコードの修正も手動でコンソール上のコードを書き換える必要がなくなるのはぐっど。
今回は小規模な構成のアプリケーションだったので調整部分もあまりなかったですがもっと大規模になってくるとTerraformなど他ツールの方が向いているパターンもありそうです。