目次

template.yml

Lambda単体

AWS::Lambda::Function リソースを使用して定義した場合、コード変更だけ行った場合に aws cloudformation deploy では更新されない(※)ので、素直に AWS::Serverless変換 を使用した方が良さそう。
※「No updates are to be performed」と怒られる。( cloudformation update-stack でも同様 )
※ aws lambda update-function-code であれば多分大丈夫。

参考
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/transform-aws-serverless.html
https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Sample Lambda

Resources:
  CloudFormationLambda2:
    Type: "AWS::Serverless::Function"
    Properties:
      FunctionName: CloudFormationLambda2
      Description: "CloudFormationで作成したLambda2(AWS::Serverless変換)"
      Runtime: python3.6
      Handler: index.handler
      # CodeUri に指定したパス配下がアップロードされる
      # ※S3のPATHを指定する事も可能。(自分でS3にアップロードする必要あり)
      # ※省略した場合はカレント配下のファイルが全てアップロード対象となる。
      CodeUri: ./src
      MemorySize: 128
      Timeout: 60
      Role: !GetAtt CloudFormationLambda2Role.Arn
  CloudFormationLambda2Role:
    Type: "AWS::IAM::Role"
    Properties: 
      RoleName: CloudFormationLambda2Role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service: "lambda.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: "CloudFormationLambda2Policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: "*"

Lambda & API Gateway (AWS::Serverless 変換を利用する場合)

AWS::Serverless 変換を使用しない場合と比べるとかなりシンプルに書ける。

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Test serverless application.

Resources:

  SampleApi:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: CloudFormationApiLambda2
      Description: "CloudFormationApiLambda2"
      Handler: index.handler
      Runtime: python3.6
      CodeUri: ./src
      Events:
        ListApi:
          Type: Api 
          Properties:
            Path: /
            Method: get 
        GetApi:
          Type: Api 
          Properties:
            Path: /{id}
            Method: get 
      Role: !GetAtt CloudFormationApiLambda2Role.Arn
  CloudFormationApiLambda2Role:
    Type: "AWS::IAM::Role"
    Properties: 
      RoleName: CloudFormationApiLambda2Role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service: "lambda.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: "CloudFormationApiLambda2Policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: "*" 
Outputs:
  SampleBookApiUri:
    # 作成したAPIのURIをエクスポートしておく(AWS::Serverless::Function を使用した場合、ステージは Stage,Prod の2つが作成される)
    # ※AWS::Serverless変換を使用した場合の RestApi は "ServerlessRestApi" という論理名で定義されるので、これを使用してAPIのIDを取得する事が可能。
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
    Export:
      Name: CloudFormationApiLambda2Uri

※実際の運用ではカスタムドメインを使用してベースパスマッピングを設定する事になるが、ここでは割愛する。(関連: CloudFormationでカスタムドメイン対応の API Gateway を作成する)

Lambda & API Gateway (AWS::Serverless 変換を利用しない場合)

上記にも記載したが、AWS::Lambda::Function リソースを使用して定義した場合、コード変更だけ行った場合に cloudformation deploy では更新されない為、
Lambda自体の定義は AWS::Serverless::Function を使用し、API部分のみ AWS::Serverless変換をしない形で書いてみた。

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Sample API Gateway template.

Parameters:
  StageName:
    Type: "String"
    Default: "dev"

Resources:

  # Lambda本体
  SampleFunction1:
    Type: "AWS::Serverless::Function"
    Properties:
      FunctionName: SampleFunction1
      Runtime: python3.6
      Handler: index.handler
      CodeUri: ./src
      MemorySize: 128
      Timeout: 60
      Role: !GetAtt SampleFunction1Role.Arn

  # Lambdaのロール
  SampleFunction1Role:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: SampleFunction1Role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service: "lambda.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: "SampleFunction1Policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: "*"

  # RestApiの定義
  # (AWS::ApiGateway::Resource と AWS::ApiGateway::Method に分けて書くこともできるが、
  #  ここでは Body プロパティに全て定義した。)
  SampleRestApi1:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Body:
        swagger: '2.0'
        info:
          version: '1.0'
          title: !Ref 'AWS::StackName'
        paths:
          /:  
            get:
              # Lambdaプロキシ統合をONにする場合は x-amazon-apigateway-integration オブジェクトを使用して type: aws_proxy を指定する
              # (参考) https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-swagger-extensions-integration.html
              x-amazon-apigateway-integration:
                httpMethod: POST  # 統合リクエストで使用されるHTTP メソッド。Lambdaの場合はPOSTを指定
                type: aws_proxy   # Lambdaプロキシ統合
                uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SampleFunction1.Arn}/invocations"
              responses: {}
          '/{id}':
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SampleFunction1.Arn}/invocations"
              responses: {}

  # API GatewayへのLambda実行許可
  SampleRestApi1Permission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:invokeFunction'
      Principal: apigateway.amazonaws.com
      FunctionName: !Ref SampleFunction1
      Principal: "apigateway.amazonaws.com"  # SourceArn でURI毎に個別定義する事もできる
      #SourceArn: !Sub
      #  - >-
      #    arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/{id}
      #  - __Stage__: Prod
      #    __ApiId__: !Ref SampleRestApi1

  # デプロイ対象ステージの作成
  # (カスタムドメインやステージ変数を使用しない場合は、定義しなくてもOK)
  #SampleRestApi1ProdStage:
  #  Type: 'AWS::ApiGateway::Stage'
  #  Properties:
  #    DeploymentId: !Ref SampleRestApi1Deploy
  #    RestApiId: !Ref SampleRestApi1
  #    StageName: !Ref StageName

  # ステージへのデプロイ
  SampleRestApi1Deploy:
    Type: 'AWS::ApiGateway::Deployment'
    #DependsOn: "SampleApiMethod"
    Properties:
      RestApiId: !Ref SampleRestApi1
      StageName: !Ref StageName

Outputs:
  SampleRestApi1Uri:
    Export:
      Name: SampleRestApi1Uri
    Value: !Sub "https://${SampleRestApi1}.execute-api.${AWS::Region}.amazonaws.com/${StageName}/"

デプロイ用シェル

デプロイ処理をシェルやMakefileにしておくと、開発、運用ともに楽。

CloudFormation実行用のシェル を参照

デプロイと動作確認

# デプロイ
./build.sh

# スタック状況確認
./build.sh events

# アンデプロイ
./build.sh delete

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-03-20 (水) 04:44:32 (267d)