🎲

CFnと AWS SAMのテンプレートの違いをTransform宣言、Globals・Resourceセクションから学習。

2022/11/02に公開約13,200字

はじめに

未着手だった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 SAM リソースとプロパティのリファレンス
では

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

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

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

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

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

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

AWS::Serverless::SimpleTable

DynamoDBのシンプル版を作成する事が出来るようです。

ドキュメントで

単一属性のプライマリキーに限り

限定されていました。

DynamoDBのより高度な機能を使用するには、代わりに AWS::DynamoDB::Table リソースを使用してください。

という注意書きも併記されています。

SimpleTable の例:

Properties:
  TableName: my-table
  Tags:
    Department: Engineering
    AppType: Serverless

AWS::Serverless::StateMachine

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

ログインするとコメントできます