CFnと AWS SAMのテンプレートの違いをTransform宣言、Globals・Resourceセクションから学習。
はじめに
未着手だったAWS SAMの全体像に触れる為、理解に重要そうな部分や例をドキュメントから抜粋しながら勉強します。
利用後に正確な把握を得て説明を行っている類のものではない為、一部完全でない理解の箇所もあります。間違ったアウトプットをしないよう使い倒してから正しい発信をしたいではありますが、一旦その気持ちは封印しています。
大事な部分を抜き出しているつもりなので流し読みされた方の勉強にもなればとても嬉しいです。
AWS SAM(Serverless Application Model)とは
AWS Serverless Application Model (AWS SAM) は、AWS でサーバーレスアプリケーションを構築するために使用できるオープンソースのフレームワークです。
サーバレスとは
サーバーレスとは、サーバーの構築や保守などの面倒な管理をすることなく、サーバー上でプログラムを実行できる仕組みです。
サーバー“レス”とは言っても、冒頭の絵のようにサーバーがない(レス)ということではなく、実際にサーバーは存在します。ただ、そのサーバーの構築や保守はサーバーレスの提供会社がすべてやってくれるうえに、負荷対策まで面倒を見てくれるのです。そのため利用者はサーバーの管理が一切不要(サーバー管理レス)になるので、「サーバーレス」と呼ばれているわけです。
たとえばプログラム開発者がサーバーレスを利用する場合、サーバーのことを一切考えなくてよくなるため、いいプログラムを書くことにのみ集中できます。これがサーバーレスの一番の利点です。
「サーバーレスアプリケーション」 とは
タスクを実行するために連動するLambda関数、イベントソース、およびその他のリソースの組み合わせです。
AWS SAMは以下2つのコンポーネントで構成
・AWS SAM テンプレート(AWS SAMの仕様)
・AWS SAM CLI(AWS SAM CLI コマンドリファレンス)
AWS SAM テンプレートは AWS CloudFormation テンプレートの拡張機能であり、これらを操作しやすくするコンポーネントがいくつか追加されています。
AWS SAM CLI は、AWS SAM テンプレートおよびアプリケーションコードで動作するコマンドラインツールです。ローカルで Lambda 関数の呼び出し、サーバーレスアプリケーションのデプロイパッケージの作成、サーバーレスアプリケーションの AWS クラウドへのデプロイなどを行うことができます。
AWS SAMテンプレートの構造(全体)
Transform: AWS::Serverless-2016-10-31
Globals: set of globals
Description: String
Metadata: template metadata
Parameters: set of parameters
Mappings: set of mappings
Conditions: set of conditions
Resources: set of resources
Outputs: set of outputs
上記の見ると、基本はCloudFormationと同じですが、
AWS SAMの独自部分として、
① 「Transform: AWS::Serverless-2016-10-31」(※=Transform宣言。)が必要になる事。
※記事をUPした時点では
「AWSTemplateFormatVersion: '2010-09-09」の代わりに「Transform: AWS::Serverless-2016-10-31」を設置する認識でしたが、
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
と連続してそれぞれ設置するのが正しいようです。失礼いたしました。
②「Globalsセクション」が存在する事。
Globals セクションは、AWS SAM に固有のセクションです。これは、すべてのサーバーレス関数と API に共通するプロパティを定義します。
が違いのようです。
今回勉強するリソースについても厳密にはCloudFormationとは若干概念の違いがあるので、そこも触れていきたいと思います。
Globalsセクションについて
Globals セクションで定義されているプロパティは、すべての
AWS::Serverless::Function
AWS::Serverless::Api
AWS::Serverless::SimpleTable
リソースによって継承されます。
上記説明だと当該セクション自体の意図がわかりにくいですが、
例えば、アプリケーションに 同一の[中略]設定を持つ複数の
リソースタイプ(※例:AWS::Serverless::Function)
がある場合
すべてのリソースにこの情報を複製する代わりに、Globals セクションでそれらを一度だけ宣言し、リソースに継承させることができます。
つまり、
反復して同じ値を設定するつもりのプロパティを、事前に定義しておいて後でそれを使い回す。
という事のようです。
具体的には以下のようなプロパティがあるようです。
AWS SAMが、Globals セクションでサポートするリソースとプロパティ
Globals:
Function:
Handler:
Runtime:
CodeUri:
DeadLetterQueue:
Description:
MemorySize:
Timeout:
VpcConfig:
Environment:
Tags:
Tracing:
KmsKeyArn:
Layers:
AutoPublishAlias:
DeploymentPreference:
PermissionsBoundary:
ReservedConcurrentExecutions:
ProvisionedConcurrencyConfig:
AssumeRolePolicyDocument:
EventInvokeConfig:
Architectures:
EphemeralStorage:
Api:
Auth:
Name:
DefinitionUri:
CacheClusterEnabled:
CacheClusterSize:
Variables:
EndpointConfiguration:
MethodSettings:
BinaryMediaTypes:
MinimumCompressionSize:
Cors:
GatewayResponses:
AccessLogSetting:
CanarySetting:
TracingEnabled:
OpenApiVersion:
Domain:
HttpApi:
Auth:
AccessLogSettings:
StageVariables:
Tags:
SimpleTable:
SSESpecification:
「プロパティを指定していなければ参照されるデフォルト値を事前設定しておけるもの」なのか、継承というくらいなのでクラスだとかextendsとかそういうイメージのものか、触らないとわからなそうなので、ここは今回は一旦イメージの理解だけに留めます。
AWS SAMにおけるリソースType
AWS::Serverless::Api
AWS::Serverless::Application
AWS::Serverless::Connector
AWS::Serverless::Function
AWS::Serverless::HttpApi
AWS::Serverless::LayerVersion
AWS::Serverless::SimpleTable
AWS::Serverless::StateMachine
があるとしています。
前章で抜粋したGlobalsの(コードブロック)をみる限り、
上記ので8つのタイプの内、先程のGlobalsセクションの機能を使えるのは、
::Function
::Api
::HttpApi
::SimpleTable
の4つであるという事かと思います。
順番に8つのタイプにをついて読んでいきます。
AWS::Serverless::Api
HTTPS エンドポイント経由で呼び出すことができる Amazon API Gateway リソースとメソッドのコレクションを作成します。
AWS::Serverless::Api リソースを AWS サーバーレスアプリケーション定義テンプレートに明示的に追加する必要はありません。このタイプのリソースは、AWS::Serverless::Function リソースを参照しないテンプレートで定義された AWS::Serverless::Api リソースに定義される Api イベントの和集合から暗黙的に作成されます。
AWS::Serverless::Application
AWS Serverless Application Repository から、または Amazon S3 バケットからのサーバーレスアプリケーションを、ネストされたアプリケーションとして埋め込みます。
Serverless Application Repository からの例:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: 'arn:aws:serverlessrepo:us-east-1:012345678901:applications/my-application'
SemanticVersion: 1.0.0
Parameters:
StringParameter: parameter-value
IntegerParameter: 2
S3urlからの例:
Type: AWS::Serverless::Application
Properties:
Location: https://s3.amazonaws.com/demo-bucket/template.yaml
いずれかに置いたアプリをスタックとして埋め込む為に使用するようです。
AWS::Serverless::Connector
2つのリソース間のアクセス許可を有効にします。
例:
MyTableというAWS::Serverless::SimpleTable(DynamoDB)と
MyFunctionというAWS::Serverless::Function(Lambda)を
MyConnector:
Type: AWS::Serverless::Connector
Properties:
Source:
Id: MyFunction
Destination:
Id: MyTable
Permissions:
- Write
のようにリソース同士を接続できる。
詳しくはAWS SAM コネクタリファレンス-コネクタに対してサポートされている送信元リソースと送信先リソースのタイプを参照。
名前の通り繋いでアクセス関係もよしなにしてくれる物と理解。
AWS::Serverless::Function
LambdaFUnction+αのようです。
このリソースタイプには、「PackageType」というプロパティがあって、
有効な値は「Zip」または「Image」の二種類のようです。
このプロパティが Zip (デフォルト) に設定されている場合は、CodeUriまたはInlineCodeが適用され、ImageUriは無視されます。
このプロパティがImageに設定されている場合は、ImageUriのみが適用されCodeUri とInlineCode は無視されます。
とあります。
Zipリソース+S3バケット内にある関数コードの例:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: python3.6
CodeUri: s3://bucket-name/key-name
InlineCode、Layers、Tracing、Policies、Amazon EFS、および Api イベントソースを使用するZipリソースの例:
Type: AWS::Serverless::Function
DependsOn: MyMountTarget # This is needed if an AWS::EFS::MountTarget resource is declared for EFS
Properties:
Handler: index.handler
Runtime: python3.6
InlineCode: |
def handler(event, context):
print("Hello, world!")
ReservedConcurrentExecutions: 30
Layers:
- Ref: MyLayer
Tracing: Active
Timeout: 120
FileSystemConfigs:
- Arn: !Ref MyEfsFileSystem
LocalMountPath: /mnt/EFS
Policies:
- AWSLambdaExecute
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectACL
Resource: 'arn:aws:s3:::my-bucket/*'
Events:
ApiEvent:
Type: Api
Properties:
Path: /path
Method: get
ImageパッケージタイプのLambda関数向けのImageConfigの例:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
ImageUri: account-id.dkr.ecr.region.amazonaws.com/ecr-repo-name:image-name
ImageConfig:
Command:
- "app.lambda_handler"
EntryPoint:
- "entrypoint1"
WorkingDirectory: "workDir"
Lambda関数とそれに関わる実行ロールを作成したり、ECRのようなリポジトリからイメージ引っ張ってきてラムダ関数にするようです。
AWS::Serverless::HttpApi
REST APIよりもレイテンシーとコストが低いRESTful APIを作成できる Amazon API Gateway HTTP APIを作成します。
AWS SAMが作成するデフォルトのHTTP APIを使用した例:
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS SAM template with a simple API definition
Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
Events:
ApiEvent:
Type: HttpApi
Handler: index.handler
InlineCode: |
def handler(event, context):
return {'body': 'Hello World!', 'statusCode': 200}
Runtime: python3.7
Transform: AWS::Serverless-2016-10-31
Authを使用したHTTP API(APIエンドポイントで認証をセットアップした)例:
Properties:
FailOnWarnings: true
Auth:
DefaultAuthorizer: OAuth2
Authorizers:
OAuth2:
AuthorizationScopes:
- scope4
JwtConfiguration:
issuer: "https://www.example.com/v1/connect/oauth2"
audience:
- MyApi
IdentitySource: "$request.querystring.param"
OpenIdAuth:
AuthorizationScopes:
- scope1
- scope2
OpenIdConnectUrl: "https://www.example.com/v1/connect/oidc/.well-known/openid-configuration"
JwtConfiguration:
issuer: "https://www.example.com/v1/connect/oidc"
audience:
- MyApi
IdentitySource: "$request.querystring.param"
テンプレートにOpenAPI定義を追加した例:
Properties:
FailOnWarnings: true
DefinitionBody:
info:
version: '1.0'
title:
Ref: AWS::StackName
paths:
"/":
get:
security:
- OpenIdAuth:
- scope1
- scope2
responses: {}
openapi: 3.0.1
securitySchemes:
OpenIdAuth:
type: openIdConnect
x-amazon-apigateway-authorizer:
identitySource: "$request.querystring.param"
type: jwt
jwtConfiguration:
audience:
- MyApi
issuer: https://www.example.com/v1/connect/oidc
openIdConnectUrl: https://www.example.com/v1/connect/oidc/.well-known/openid-configuration
AWS::Serverless::LayerVersion
Lambda 関数に必要なライブラリまたはランタイムコードが含まれる Lambda LayerVersion を作成します。
例:
Properties:
LayerName: MyLayer
Description: Layer description
ContentUri: 's3://my-bucket/my-layer.zip'
CompatibleRuntimes:
- nodejs10.x
- nodejs12.x
LicenseInfo: 'Available under the MIT-0 license.'
RetentionPolicy: Retain
AWS::Serverless::SimpleTable
DynamoDBのシンプル版を作成する事が出来るようです。
ドキュメントで
単一属性のプライマリキーに限り
限定されていました。
DynamoDBのより高度な機能を使用するには、代わりに AWS::DynamoDB::Table リソースを使用してください。
という注意書きも併記されています。
SimpleTable の例:
Properties:
TableName: my-table
Tags:
Department: Engineering
AppType: Serverless
AWS::Serverless::StateMachine
名前の通り、Step Functionsステートマシンを作成するもののようです。
定義ファイルで定義されたステートマシンの例:
MySampleStateMachine:
Type: AWS::Serverless::StateMachine
Properties:
DefinitionUri: statemachine/my_state_machine.asl.json
Role: arn:aws:iam::123456123456:role/service-role/my-sample-role
Tracing:
Enabled: true
DefinitionSubstitutions:
MyFunctionArn: !GetAtt MyFunction.Arn
MyDDBTable: !Ref TransactionTable
インラインステートマシン定義の例:
MySampleStateMachine:
Type: AWS::Serverless::StateMachine
Properties:
Definition:
StartAt: MyLambdaState
States:
MyLambdaState:
Type: Task
Resource: arn:aws:lambda:us-east-1:123456123456:function:my-sample-lambda-app
End: true
Role: arn:aws:iam::123456123456:role/service-role/my-sample-role
Tracing:
Enabled: true
リソース属性
リソース属性は、追加の動作と関係性を制御するために AWS SAMとAWS CloudFormationのリソースに追加できる属性です。
SAMは各リソースタイプの中で特定のプロパティの指定の有無によってシナリオを判断し、該当するシナリオに追加のCFnリソースを生成してくれる。
例えば、「AWS::StepFunctions::StateMachine」をテンプレート内で定義していたとして、その中で「Role:」プロパティの指定がない場合→必要な「AWS::IAM::Role」リソースを作ってくれる ようなイメージです。
各シナリオは必要に応じて生成された AWS CloudFormation リソースを確認ください。
以上です。
触れなかった部分やGlobalsセクションの真意を確認次第リンクをここにしたいと思います。
Discussion