LoginSignup
27
22

More than 1 year has passed since last update.

AWS SAMでAPI Gateway、Lambda、Layersをサクッとデプロイできるようにする

Last updated at Posted at 2021-12-15

AWS SAMとは

AWS サーバーレスアプリケーションモデル (SAM、Serverless Application Model) は、サーバーレスアプリケーション構築用のオープンソースフレームワークです。迅速に記述可能な構文で関数、API、データベース、イベントソースマッピングを表現できます。リソースごとにわずか数行で、任意のアプリケーションを定義して YAML を使用してモデリングできます。

テンプレートのYMALファイルに構成を記載することで、
サーバーレスアプリケーションをまとめて管理できます。

インストール方法はこちら↓

テンプレートの構成について

基本的に必須なのは、TransformとResourcesのみ。
Resourcesの論理IDにAPI GatewayやLambdaなどの構成を記載していきます。また論理IDはテンプレート内で一意となる必要があります。
論理名でテンプレートの他の部分のリソースを参照したりできます。

ちなみにこの論理IDは、CloudFormationのイベントの論理IDに紐づきます。
※誤字があったりでデプロイ後、変えるのはやめましょう(戒め)

今回は、LambdaExecutionRoleとWebSecurityGroupも一緒に作成してみます。

以下、yamlファイルです。
なんとなく感じを掴んでもらえればと思います。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sample API
Globals:
  Api:
    OpenApiVersion: 3.0.2
Resources:
  LambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: "sts:AssumeRole"
      ManagedPolicyArns:
        - !Sub 'arn:aws:iam::aws:policy/AmazonVPCFullAccess'
  WebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "sample API SecurityGroup"
      GroupName: sample-API-SecurityGroup
      VpcId: vpc-XXXXXXXX
  RestApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: dev
      OpenApiVersion: 3.0.2
      DefinitionBody:
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: ./sample-api-dev-swagger-apigateway.yaml # API Gatewayの構成のパス
  SampleFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: sample-function
      Handler: lambda_function.lambda_handler
      Runtime: python3.8
      Role: !GetAtt LambdaExecutionRole.Arn # Roleを紐付け
      CodeUri: ./sample-function/ # Lambdaのコードのパス
      Description: ''
      MemorySize: 128
      Timeout: 25
      Events:
        Api:
          Type: Api
          Properties:
            RestApiId: !Ref RestApi # RestApiと紐付け
            Path: '/v1/sample-function/{param}'
            Method: GET
      VpcConfig:
        SecurityGroupIds:
          - !Ref WebSecurityGroup # WebSecurityGroupと紐付け
        SubnetIds:
          - subnet-XXXXXXXX
          - subnet-XXXXXXXX
      Environment:
        Variables:
          ID: 1234 # 環境変数その1
          PASS: hogehoge # 環境変数その2
      Tags:
        STAGE: dev
      Layers:
      - Ref: SampleLayers # Layersと紐付け
  SampleLayers:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: sample-layers
      Description: Sample API Resource Layer
      CompatibleRuntimes: 
      - python3.8
      ContentUri: ./sample-layers # Layersのパス

YAMLの短縮記法で論理IDを指定していきます。

OpenApiVersionの記載については、こちらも合わせてどうぞ

Makefileでデプロイできるようにする

CI的にもなるべく簡単にデプロイできるようにしたいです。
開発環境と本番環境で、設定値などが分けられる様にもします。

feq ($(ENV), dev)
    PROFILE := sample-api-dev
    STACK_NAME := sample-api-dev-stack
    BUCKET_NAME := sample-api-dev-bucket
    TEMPLATE := template_dev.yaml
    TEMPLATE_OUT := template_dev_output.yaml
else ifeq ($(ENV), prd)
    PROFILE := sample-api-prd
    STACK_NAME := sample-api-prd-stack
    BUCKET_NAME := sample-api-prd-bucket
    TEMPLATE := template_prd.yaml
    TEMPLATE_OUT := template_prd_output.yaml
endif

check:
    @echo Profile: $(PROFILE)
    @echo Stack Name: $(STACK_NAME)
    @echo Bucket Name: $(BUCKET_NAME)
    @echo Template File: $(TEMPLATE)

make_bucket:
    aws s3 mb s3://${BUCKET_NAME} --region ap-northeast-1 --profile ${PROFILE}

encrypt_bucket:
    aws s3api put-bucket-encryption --bucket ${BUCKET_NAME} --server-side-encryption-configuration '{"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}]}'

bucket: make_bucket encrypt_bucket

get_cert:
    aws s3 --profile ${PROFILE} cp s3://${BUCKET_NAME}/certs/ ./sample-layers/certs/ --recursive

del_cert:
    rm -rf ./sample-layers/certs/

pac:
    aws cloudformation package \
    --template ${TEMPLATE} \
    --output-template-file ${TEMPLATE_OUT} \
    --s3-bucket ${BUCKET_NAME} --profile ${PROFILE} \

deploy:
    aws cloudformation deploy \
    --template-file ${TEMPLATE_OUT} \
    --stack-name  ${STACK_NAME} \
    --capabilities CAPABILITY_NAMED_IAM --profile ${PROFILE} \

delete:
    @echo "Are you sure to delete the stack ${STACK_NAME}? [y/N] " && read ans && [ $${ans:- N} = y ]
    aws cloudformation delete-stack --stack-name ${STACK_NAME} --profile ${PROFILE}

all: check get_cert pac deploy del_cert

利用する環境のプロファイルを設定し、
環境ごとに分けられるようにします。

$ aws configure --profile sample-api-dev
AWS Access Key ID [None]: アクセスキーID
AWS Secret Access Key [None]: シークレットアクセスキー
Default region name [None]: ap-northeast-1
Default output format [None]: 

設定の確認↓

$ aws configure list
[sample-api-dev]
aws_access_key_id=アクセスキーID
aws_secret_access_key=シークレットアクセスキー

初めのみバケットを作成します。
※2回目以降は重複エラーになります。

$ make bucket ENV=dev

デプロイします。

$ make all ENV=dev
Profile: sample-api-dev
Stack Name: sample-api-dev-stack
Bucket Name: sample-api-dev-bucket
Template File: template_dev.yaml
Template Output File: template_dev_output.yaml
Are you sure to deploy with these settings? [y/N] 

以下で完了

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - sample-api-dev-stack

最終的な構成

sample-app
│  .gitignore
│  Makefile
│  README.md
│  sample-api-dev-swagger-apigateway.yaml # 開発用API Gatewayのテンプレート
│  sample-api-prd-swagger-apigateway.yaml # 本番用API Gatewayのテンプレート
│ template_dev_output.yaml # デプロイ時に作成されたアウトプットファイル S3のロケーションなどが記載される。
│  template_dev.yaml  # 開発用のテンプレート
│  template_prd.yaml  # 本番用のテンプレート
│
├─ sample-function # Lambda関数
│    └─ lambda_function.py
│
└─ sample-layers

参考

27
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
22