みずラテ

牛乳と水を2対1で。

AWS SAMでAPI GatewayからSQSにメッセージを溜める

今回はAWS SAMを使って初めてのサーバーレスを体験してみようと思います。

具体的にはAPI GatewayにPOSTされたメッセージをそのままSQSに送信して溜め込むというのをSAMのテンプレートを作ってコマンドでデプロイしてみるところまでをやってみます。

前提

前回、SAMの開発環境をDocker上に構築していますので、今回はそのDocker上での作業が前提となります。

djandjan.hateblo.jp

sam init

まず初めにやることはsam initですね。Docker remoteしているVSCode上のターミナルで以下を実行します。

sam init -n firstApp

すると対話形式で構築が始まります。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Which runtime would you like to use?
        1 - nodejs12.x
        2 - python3.8
        3 - ruby2.5
        4 - go1.x
        5 - java11
        6 - dotnetcore2.1
        7 - nodejs10.x
        8 - python3.7
        9 - python3.6
        10 - python2.7
        11 - java8
        12 - dotnetcore2.0
        13 - dotnetcore1.0
Runtime: 2

AWS quick start application templates:
        1 - Hello World Example
        2 - EventBridge Hello World
        3 - EventBridge App from scratch (100+ Event Schemas)
Template selection: 1

最初の質問はCustom Templateを持っていないので、Quick Startの方の1を選択。
次の質問はlambdaで使用する言語ですが、今回はPythonを選択しました。
最後はサンプルテンプレートの選択で1を選びました。

これで、firstAppというディレクトリが作成され、中に最初の一式が入っていると思います!

.
|-- README.md
|-- events
|   `-- event.json
|-- hello_world
|   |-- __init__.py
|   |-- app.py
|   `-- requirements.txt
|-- template.yaml
`-- tests
    `-- unit
        |-- __init__.py
        `-- test_handler.py
4 directories, 8 files

ただ、今回使用するのはtemplate.yamlだけなので、それ以外は全て消してしまいました。

.
`-- template.yaml

0 directories, 1 file

あらら、、めちゃくちゃシンプルになってしまった。まあいいや。早速、templateをいじっていきます。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  firstApp
  send message to SQS via API Gateway.

Resources:
  # SQSの作成
  SampleQueue: 
    Type: AWS::SQS::Queue
    Properties: 
      QueueName: "SampleQueue"
      MaximumMessageSize: 1024 # 最大メッセージサイズ(バイト)
      MessageRetentionPeriod: 604800 # メッセージ保持期間: 7日
  
  # API Gatewayにアタッチするロール SQSへのSendMeessage権限を持たせる
  SampleIAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Join
                - ""
                - - !Ref AWS::Region
                  - "RoleSendMassageToSQS"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: apigateway.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: send_message_to_sqs
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - sqs:SendMessage
                Resource: !GetAtt SampleQueue.Arn
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: '*'
  
  # API Gatewayの設定
  SampleAPIGateway:
    Type: "AWS::ApiGateway::RestApi"
    Properties:
      Name: Sample_API_Gateway
      ApiKeySourceType: HEADER
      EndpointConfiguration:
        Types:
          - REGIONAL
  ApiMethod:
    Type: "AWS::ApiGateway::Method"
    Properties:
      RestApiId: !Ref SampleAPIGateway
      ResourceId: !GetAtt SampleAPIGateway.RootResourceId
      ApiKeyRequired: true
      AuthorizationType: NONE
      HttpMethod: POST
      Integration:
        Type: AWS
        Credentials: !GetAtt SampleIAMRole.Arn
        IntegrationHttpMethod: POST
        IntegrationResponses:
          - StatusCode: '200'
        PassthroughBehavior: NEVER
        RequestParameters:
          integration.request.header.Content-Type: '''application/x-www-form-urlencoded'''
        RequestTemplates:
          application/json: Action=SendMessage&MessageBody=$input.body
        Uri: !Join
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - :sqs:path/
            - !Ref 'AWS::AccountId'
            - /
            - !GetAtt SampleQueue.QueueName
      MethodResponses:
        - ResponseModels:
            application/json: Empty
          StatusCode: '200'

aws 接続設定

aws configureコマンドで接続設定をしていきます。
予め、AWSマネジメントコンソールでユーザーを作成し、アクセスキー IDとシークレットアクセスキーをメモしておいてください。

aws configure
AWS Access Key ID [None]: <<自分のアクセスキーID>>
AWS Secret Access Key [None]: <<自分のシークレットアクセスキー>>
Default region name [None]: ap-northeast-1
Default output format [None]: 

S3バケットを作成する

SAMがデプロイ用に使用するバケットを事前に作成しておきます。

aws s3 mb s3://sam-cli-bucket-xxxxxxxx

名前は適当につけて良いですが、全世界でユニークな名前が必要なので、上記のバケット名だとできないかもしれません。各自自分でバケット名は設定してください。

ビルドする

コマンド一発

sam build

デプロイする

こちらもコマンド一発

sam deploy --stack-name firstApp --s3-bucket sam-cli-bucket-xxxxxxxx --region ap-northeast-1 --capabilities CAPABILITY_NAMED_IAM

こんな感じでSuccessfullyとなったら成功!
f:id:taris777:20200218001314p:plain

試してみる

早速試してみましょう。
AWSマネジメントコンソールにログインして、CloudFormationを開いてみてください。
f:id:taris777:20200218001455p:plain
新しいスタックが作成されています。

続いてAPI Gatewayに行ってみてください。
こちらも新しい、Sample_API_GatewayというAPIが作成されていると思います。
このAPIを開いてリソース→POSTをクリックすると、こんな感じの設定画面になります。

f:id:taris777:20200218001649p:plain

ここで、テストをクリックして、リクエスト本文に以下のように入力してテストボタンを押してみると・・・

{
  "body": "this is a test."
}

f:id:taris777:20200218001840p:plain

SendMessageResponseが返ってきたら成功していると思います。

AWSマネジメントコンソールでSQSを開いてみると、

f:id:taris777:20200218002027p:plain

1件入ってる!ポーリングして中身を確認してみても、さっきテストでリクエストを投げたものがそのまま入っています!

f:id:taris777:20200218002114p:plain

おわりに

というわけで、API GatewayからSQSにメッセージを入れ込むところまでSAMでやってみました。
実戦で使うにはAPIのデプロイをしなくちゃいけないのですが、それはまた次回にやってみようと思います。

今日は以上です。

図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書

図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書

  • 作者:小笠原 種高
  • 出版社/メーカー: 技術評論社
  • 発売日: 2019/11/07
  • メディア: 単行本(ソフトカバー)