AWS SAMとCloudFormationで同じ構成のAPI Gateway + Lambdaを構築
API Gateway + Lambdaの同じ構成をSAMとCloudFormationの2通りで作成しました。
SAMのほうが簡単に作成できるのですが、細かい設定が中途半端に隠蔽されている感じが好きではないです。
CloudFormationのほうがテンプレートが長いのですが、細かい設定ができます。
SAM
aws-sam-cli
のインストールが必要です。
$ pip install aws-sam-cli $ sam --version SAM CLI, version 1.6.2
SAMのテンプレートの雛形をコマンドで作成します。
$ sam init --runtime python3.8 Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 Project name [sam-app]: hello1 Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git AWS quick start application templates: 1 - Hello World Example 2 - EventBridge Hello World 3 - EventBridge App from scratch (100+ Event Schemas) 4 - Step Functions Sample App (Stock Trader) 5 - Elastic File System Sample App Template selection: 1 ----------------------- Generating application: ----------------------- Name: hello1 Runtime: python3.8 Dependency Manager: pip Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./hello1/README.md
でき上がったテンプレートのファイル構成は以下のとおりです。
$ cd hello1 $ tree . ├── events │ └── event.json ├── hello_world │ ├── app.py │ ├── __init__.py │ └── requirements.txt ├── README.md ├── template.yaml └── tests └── unit ├── __init__.py └── test_handler.py 4 directories, 8 files
template.yaml
もsam
コマンドにより自動生成されますが、Resources
は次の内容が書かれています。CloudFormationで書くよりも短いです。
Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.8 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get
これをデプロイするには以下のコマンドです。 --profile AWS_CREDENTIAL_PROFILE_NAME
のところは ~/.aws/credentials
に複数のプロファイルが設定されている場合に必要に応じて指定するものです。 --s3-bucket MYBUCKET_NAME
はLambdaのソースコードを保存するS3バケット名を指定します。
$ sam package --profile AWS_CREDENTIAL_PROFILE_NAME --template-file template.yaml --output-template-file packaged.yaml --s3-bucket MYBUCKET_NAME --s3-prefix hello1 $ sam deploy --profile AWS_CREDENTIAL_PROFILE_NAME --region ap-northeast-1 --template-file packaged.yaml --stack-name hello1 --capabilities CAPABILITY_IAM
これでAPI Gatewayにcurl
コマンドでアクセスできます。
$ curl 'https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello' {"message": "hello world"}
このSAMにより作成されるCloudFormationのStackのテンプレートは以下のコマンドで確認できます。JSON形式です。
$ aws --profile AWS_CREDENTIAL_PROFILE_NAME cloudformation get-template --stack-name hello1 | jq .TemplateBody -C | less -R
CloudFormation
上記SAMで作成したAWSのリソースとほぼ同じ構成をCloudFormationで作成します。
次のようなディレクトリ構成で2ファイルのみです。
$ tree . ├── hello_world │ └── app.py └── template.yaml 1 directory, 2 files
template.yaml
は以下の内容です。
AWSTemplateFormatVersion: '2010-09-09' Resources: HelloWorldFunction: Type: AWS::Lambda::Function Properties: Code: hello_world Handler: app.lambda_handler FunctionName: hello2 Role: !GetAtt HelloWorldFunctionRole.Arn Runtime: python3.8 Timeout: 3 HelloWorldFunctionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Action: - "sts:AssumeRole" Effect: Allow Principal: Service: - lambda.amazonaws.com ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" ServerlessRestApi: Type: AWS::ApiGateway::RestApi Properties: Body: info: version: 1.0 title: !Ref AWS::StackName paths: "/hello": get: x-amazon-apigateway-integration: httpMethod: POST type: aws_proxy uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorldFunction.Arn}/invocations swagger: 2.0 ServerlessRestApiProdStage: Type: AWS::ApiGateway::Stage Properties: DeploymentId: !Ref ServerlessRestApiDeployment RestApiId: !Ref ServerlessRestApi StageName: Prod ServerlessRestApiDeployment: Type: AWS::ApiGateway::Deployment Properties: RestApiId: !Ref ServerlessRestApi StageName: Stage HelloWorldFunctionHelloWorldPermissionProd: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction Principal: apigateway.amazonaws.com FunctionName: !Ref HelloWorldFunction SourceArn: !Sub - arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello - __Stage__: "*" __ApiId__: !Ref ServerlessRestApi
hello_world/app.py
はSAMのケースと同じPythonソースです。次の内容です。
import json def lambda_handler(event, context): return { "statusCode": 200, "body": json.dumps({ "message": "hello world", }), }
これをデプロイするには以下のコマンドです。 --profile AWS_CREDENTIAL_PROFILE_NAME
のところは ~/.aws/credentials
に複数のプロファイルが設定されている場合に必要に応じて指定するものです。 --s3-bucket MYBUCKET_NAME
はLambdaのソースコードを保存するS3バケット名を指定します。
$ aws --profile AWS_CREDENTIAL_PROFILE_NAME cloudformation package --template-file template.yaml --s3-bucket MYBUCKET_NAME --s3-prefix hello2 --output-template-file packaged.yaml $ aws --profile AWS_CREDENTIAL_PROFILE_NAME cloudformation deploy --template-file packaged.yaml --stack-name hello2 --capabilities CAPABILITY_IAM
これでAPI Gatewayにcurl
コマンドでアクセスできます。
$ curl 'https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello' {"message": "hello world"}
このCloudFormationのStackのテンプレートは以下のコマンドで確認できます。といってもローカルに残っている package.yaml
と同じです。YAML形式です。
$ aws --profile AWS_CREDENTIAL_PROFILE_NAME cloudformation get-template --stack-name hello2 | jq .TemplateBody -r | less