Amplify CLI でカスタムリソースとして Lambda をトリガーする SQS キューを作成する

Amplify CLI でカスタムリソースとして Lambda をトリガーする SQS キューを作成する

Amplify CLI では amplify add function のような SQS を追加するコマンドは存在しません。
また、 amplify add function 実行時に、Lambda 関数のトリガー設定に関する以下のような質問が出ますが選択肢として SQS はありません。

Copied!
$ amplify add function
? Choose the function template that you want to use: Lambda trigger
? What event source do you want to associate with Lambda trigger? (Use arrow keys)
❯ Amazon DynamoDB Stream
  Amazon Kinesis Stream

SQS のような Amplify CLI ではサポートされていない他のリソースを作成する場合は、「カスタム」機能を利用する必要があります。1
この「カスタム」機能では、カスタムリソースの定義方法として AWS CDK2 と CloudFormation3 の 2 種類がありますがそれぞれの方法で Lambda 関数をトリガーする SQS キューの作成と設定をしてみます。

Amplify CLI でカスタムリソースとして Lambda をトリガーする SQS キューを作成する手順

開発環境

  • Amplify CLI: 7.6.22

作業ディレクトリの作成と初期化

まず、作業ディレクトリを作成し、Amplify プロジェクトを初期化します。

Copied!
mkdir ~/sqs-lambda
cd ~/sqs-lambda
amplify init -y

Lambda 関数の作成と SQS へのアクセス許可の付与

amplify add function コマンドで Lambda 関数を作成します。
取り敢えずここでは実行できればいいの、Hello World テンプレートを使用します。

Copied!
$ cd ~/sqs-lambda
$ amplify add function
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: handleNotifySQS
? Choose the runtime that you want to use: NodeJS
? Choose the function template that you want to use: Hello World

Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration
- Environment variables configuration
- Secret values configuration

? Do you want to configure advanced settings? No
? Do you want to edit the local lambda function now? No

amplify/backend ディレクトリに Lambda 関数(handleNotifySQS)が追加されます。

Copied!
.
└── amplify
    └── backend
        └── function
            └── handleNotifySQS
                ├── amplify.state
                ├── custom-policies.json
                ├── dist
                │   └── latest-build.zip
                ├── function-parameters.json
                ├── handleNotifySQS-cloudformation-template.json
                └── src
                    ├── event.json
                    ├── index.js
                    ├── node_modules
                    ├── package.json
                    └── yarn.lock

Lambda 関数には SQS キューからメッセージを読み取るためのアクセス許可が必要です。
付与するアクセス許可は AWS マネージドポリシーの AWSLambdasqsqueueExecutionRole4 を参考にします。
CloudWatch Logs に関するアクセス許可はすでに定義済みなので、残りの以下の 3 つのアクションのアクセス許可を追加します。

  • sqs:ReceiveMessage
  • sqs:DeleteMessage
  • sqs:GetQueueAttributes
amplify/backend/function/handleNotifySQS/handleNotifySQS-cloudformation-template.json
Copied!
'lambdaexecutionpolicy':
  {
    'DependsOn': ['LambdaExecutionRole'],
    'Type': 'AWS::IAM::Policy',
    'Properties':
      {
        'PolicyName': 'lambda-execution-policy',
        'Roles': [{ 'Ref': 'LambdaExecutionRole' }],
        'PolicyDocument':
          {
            'Version': '2012-10-17',
            'Statement':
              [
                {
                  'Effect': 'Allow',
                  'Action':
                    [
                      'logs:CreateLogGroup',
                      'logs:CreateLogStream',
                      'logs:PutLogEvents',
                    ],
                  'Resource':
                    {
                      'Fn::Sub':
                        [
                          'arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*',
                          {
                            'region': { 'Ref': 'AWS::Region' },
                            'account': { 'Ref': 'AWS::AccountId' },
                            'lambda': { 'Ref': 'LambdaFunction' },
                          },
                        ],
                    },
                },
                {
                  'Effect': 'Allow',
                  'Action':
                    [
                      'sqs:ReceiveMessage',
                      'sqs:DeleteMessage',
                      'sqs:GetQueueAttributes',
                    ],
                  'Resource': '*',
                },
              ],
          },
      },
  }

CloudFormation で SQS をカスタムリソースとして作成する方法

amplify add custom コマンドでカスタムリソースを作成します。
カスタムリソースの定義方法として AWS CloudFormation を選択してください。

Copied!
$ cd ~/sqs-lambda
$ amplify add custom
✔ How do you want to define this custom resource? · AWS CloudFormation
✔ Provide a name for your custom resource · notifySQSByCfn
✔ Do you want to access Amplify generated resources in your custom CloudFormation file? (y/N) · yes
? Select the categories you want this custom resource to have access to. function
✅ Created skeleton CloudFormation stack in amplify/backend/custom/notifySQSByCfn directory
✔ Do you want to edit the CloudFormation stack now? (Y/n) · no

amplify/backend/custorm ディレクトリにカスタムリソース(notifySQSByCfn)が追加されます。

Copied!
.
└── amplify
    └── backend
        └── custom
            └── notifySQSByCfn
                └── notifySQSByCfn-cloudformation-template.json

json 形式の CloudFormation テンプレートで SQS キューと Lambda のイベントソースマッピングを定義します。

amplify/custom/notifySQSByCfn/notifySQSByCfn-cloudformation-template.json
Copied!
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters": {
    "env": {
      "Type": "String"
    },
    "functionhandleNotifySQSName": {
      "Type": "String",
      "Description": "Input parameter describing Name attribute for function/handleNotifySQS resource"
    },
    "functionhandleNotifySQSArn": {
      "Type": "String",
      "Description": "Input parameter describing Arn attribute for function/handleNotifySQS resource"
    },
    "functionhandleNotifySQSRegion": {
      "Type": "String",
      "Description": "Input parameter describing Region attribute for function/handleNotifySQS resource"
    },
    "functionhandleNotifySQSLambdaExecutionRole": {
      "Type": "String",
      "Description": "Input parameter describing LambdaExecutionRole attribute for function/handleNotifySQS resource"
    }
  },
  "Resources": {
    "NotifySQSByCfn": {
      "Type": "AWS::SQS::Queue"
    },
    "LambdaFunctionEventSourceMapping": {
      "Type": "AWS::Lambda::EventSourceMapping",
      "Properties": {
        "BatchSize": 10,
        "Enabled": true,
        "EventSourceArn": {
          "Fn::GetAtt": ["NotifySQSByCfn", "Arn"]
        },
        "FunctionName": {
          "Ref": "functionhandleNotifySQSArn"
        }
      }
    }
  },
  "Outputs": {}
}

AWS SDK で SQS をカスタムリソースとして作成する方法

amplify add custom コマンドでカスタムリソースを作成します。
カスタムリソースの定義方法として AWS CDK を選択してください。

Copied!
$ cd ~/sqs-lambda
$ amplify add custom
✔ How do you want to define this custom resource? · AWS CDK
✔ Provide a name for your custom resource · notifySQSByCDK
✅ Created skeleton CDK stack in amplify/backend/custom/notifySQSByCDK directory
✔ Do you want to edit the CDK stack now? (Y/n) · no

amplify/backend/custorm ディレクトリにカスタムリソース(notifySQSByCDK)が追加されます。

Copied!
.
└── amplify
    └── backend
        └── custom
            └── notifySQSByCDK
                ├── build
                │   ├── cdk-stack.js
                │   └── notifySQSByCDK-cloudformation-template.json
                ├── cdk-stack.ts
                ├── node_modules
                ├── package.json
                ├── tsconfig.json
                └── yarn.lock

package.json を編集して、必要なパッケージを追加してついでに使わないパッケージを削除します。
aws-sdk のバージョンが 1.124 と古いですが、今回やることには支障がないのでそのままで行きます。

amplify/custom/notifySQSByCDK/package.json
Copied!
{
  "name": "custom-resource",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "@aws-amplify/cli-extensibility-helper": "^2.0.0",
    "@aws-cdk/core": "~1.124.0",
    "@aws-cdk/aws-sqs": "~1.124.0",
    "@aws-cdk/aws-lambda": "~1.124.0"
  },
  "devDependencies": {
    "typescript": "^4.2.4"
  }
}

package.json を編集したら、パッケージを再インストールします。

Copied!
cd ~/sqs-lambda/amplify/custom/notifySQSByCDK
yarn install --check-files

スタックファイル(cdk-stack.ts)に SQS キューと Lambda のイベントソースマッピングを定義します。

amplify/custom/notifySQSByCDK/cdk-stack.ts
Copied!
import * as cdk from '@aws-cdk/core'
import * as AmplifyHelpers from '@aws-amplify/cli-extensibility-helper'
import { AmplifyDependentResourcesAttributes } from '../../types/amplify-dependent-resources-ref'
import { Queue } from '@aws-cdk/aws-sqs'
import { Function, EventSourceMapping } from '@aws-cdk/aws-lambda'

export class cdkStack extends cdk.Stack {
  constructor(
    scope: cdk.Construct,
    id: string,
    props?: cdk.StackProps,
    amplifyResourceProps?: AmplifyHelpers.AmplifyResourceProps
  ) {
    super(scope, id, props)
    /* Do not remove - Amplify CLI automatically injects the current deployment environment in this input parameter */
    new cdk.CfnParameter(this, 'env', {
      type: 'String',
      description: 'Current Amplify CLI env name',
    })

    const queue = new Queue(this, 'notifySQSByCDK', {})

    const dependencies: AmplifyDependentResourcesAttributes =
      AmplifyHelpers.addResourceDependency(
        this,
        amplifyResourceProps.category,
        amplifyResourceProps.resourceName,
        [{ category: 'function', resourceName: 'handleNotifySQS' }]
      )

    const lambdaArn = cdk.Fn.ref(dependencies.function.handleNotifySQS.Arn)
    const target = Function.fromFunctionArn(this, 'handleNotifySQS', lambdaArn)
    const eventSourceMapping = new EventSourceMapping(
      this,
      'NotifySQSByCDKEventSourceMapping',
      {
        target,

        // the properties below are optional
        batchSize: 10,
        enabled: true,
        eventSourceArn: queue.queueArn,
      }
    )
  }
}

スタックファイル(cdk-stack.ts) を編集したら、amplify build コマンドでビルドを実行します。

Copied!
cd ~/sqs-lambda
amplify build

Lambda 関数と SQS のデプロイ

amplify push コマンドでデプロイを実行します。

Copied!
cd ~/sqs-lambda
amplify push

AWS マネジメントコンソールで Lambda 関数と SQS キューが作成されていることを確認します。

Lambda 一覧

SQS 一覧

動作確認

動作確認してみます。
まず、各 SQS キューからテストメッセージを送信します。

テストメッセージ1

テストメッセージ2

テストメッセージ送信後、Lambda 関数の CloudWatch Logs で送信したメッセージが確認できれば動作確認完了です。

テスト結果1

テスト結果2

Footnotes

  1. AWS CDK または CloudFormation を使用し、カスタム AWS リソースで Amplify バックエンドを拡張する新機能「カスタム」のご紹介 | Amazon Web Services ブログ

  2. Custom AWS resources - Use CDK to add custom AWS resources - AWS Amplify Docs

  3. Custom AWS resources - Use CloudFormation to add custom AWS resources - AWS Amplify Docs

  4. AWS Lambda 実行ロール - AWS Lambda