Amazon EventBridge にイベントを別リージョンに自動でフェイルオーバーするグローバルエンドポイントが追加されました

グローバルエンドポイントを活用することでイベント駆動型アーキテクチャのシステムの可用性を高めることができそう
2022.04.26

イベント駆動アーキテクチャでもリージョン障害に対応したい

こんにちは、のんピ(@non____97)です。

皆さんはイベント駆動アーキテクチャでもリージョン障害に対応したいと思ったことはありますか? 私はあります。

Amazon EventBridgeのイベントはリージョン内で閉じています。そのため、EventBridgeでリージョン障害が発生した場合に、別リージョンにシステムをフェイルオーバーしたとしても、障害が発生してからフェイルオーバーが完了するまでに発生したイベントを拾うことができません。

今回、Amazon EventBridge にイベントを別リージョンに自動でフェイルオーバーするグローバルエンドポイントが追加されました。

グローバルエンドポイントを使うことによって、プライマリリージョンに障害が発生した場合にも、イベントがセカンダリリージョンに自動でフェイルオーバーされます。Amazon EventBridgeのアーカイブ機能と組み合わせることで、障害が発生してからフェイルオーバーが完了するまでのイベントをセカンダリリージョンで拾うことができ、サービス中断の影響を最小限にすることが可能です。

いきなりまとめ

  • グローバルエンドポイントを使うことで、イベントの配信先をセカンダリリージョンのイベントバスに自動でフェイルオーバーできる
  • イベントを常時セカンダリリージョンにレプリケーションすることも可能
  • フェイルオーバーするか否かはCloudWatchアラーム (Route 53ヘルスチェック経由) で判断
  • グローバルエンドポイントにPutEventsをする場合は、AWS Common Runtime (CRT) ライブラリが必要
  • グローバルエンドポイント使用時の追加料金はなし
  • グローバルエンドポイントは東京リージョンを含む18リージョンで利用可能
  • グローバルエンドポイントは2022/4/25時点ではカスタムイベントのみに対応
    • 「S3バケットにオブジェクトが追加された」や「EC2インスタンスが起動した」などの各AWSサービスからのイベントには対応していない

グローバルエンドポイントの特徴

グローバルエンドポイントの仕組み

グローバルエンドポイントの仕組みはAWS公式ブログに記載があります。

グローバルエンドポイントはマネージドのAmazon Route53 DNSエンドポイントです。グローバルエンドポイントは以下2つの仕組みによって動作します。

  1. イベントがAmazon EventBridgeに取り込まれてから、ルールの中でターゲットが最初に呼び出されるまでの処理時間のメトリクスであるIngestionToInvocationStartLatencyを用いて、Amazon EventBridgeサービスの状態を判断する
  2. グローバルエンドポイントはIngestionToInvocationStartLatencyからプライマリリージョンのサービスの状態を判断し、イベントをプライマリリリージョンもしくはセカンダリリージョンのイベントバスにルーティングする

フェイルオーバーのトリガーはプライマリリージョンでIngestionToInvocationStartLatencyを監視しているCloudWatchアラームと連携するRoute 53ヘルスチェックです。

以下はCloudWatchアラームがRoute 53ヘルスチェックを介してフェイルオーバーをトリガーし、グローバルエンドポイントがイベントの配信先をプライマリリージョンのイベントバスからセカンダリリージョンのイベントバスに変更する際の図です。

グローバルエンドポイントの仕組み

抜粋 : Introducing global endpoints for Amazon EventBridge | AWS Compute Blog

フェイルオーバーといえば、気になるのはRTOとRPOです。

アラーム設定の規定のガイダンスに従ってグローバルエンドポイントを使うと、RTOとRPOが360秒で最大420秒になるようです。

Recovery Time & Recovery Point Objectives

The Recovery Time Objective (RTO) is the time that it takes for the secondary Region to start receiving events after a failure. For RTO, the time includes time period for triggering CloudWatch alarms and updating statuses for Route 53 health checks. The Recovery Point Objective (RPO) is the measure of the data that will be left unprocessed during a failure. For RPO, the time includes events that are not replicated to the secondary Region and are stuck in the primary Region until the service or Region recovers. With global endpoints, if you follow our prescriptive guidance for alarm configuration, you can expect the RTO and RPO to be 360 seconds with a maximum of 420 seconds.

Making applications Regional-fault tolerant with global endpoints and event replication - Amazon EventBridge

グローバルエンドポイントはオプションでイベントを常時セカンダリリージョンにレプリケーションすることも可能です。

イベントレプリケーションはグローバルエンドポイントを設定する場合のベストプラクティスとして、以下の2つの理由から有効にすることをお勧めされています。

  1. グローバルエンドポイントが正しく構成されていることを確認するのに役立つため
  2. 自動でフェイルバックするには、イベントレプリケーションが必要であるため
    • イベントレプリケーションを有効にしていない場合、フェイルバックするためにRoute 53ヘルスチェックを手動で「healthy」にリセットする必要がある

イベントレプリケーションはAmazon EventBridgeのアーカイブ機能と組み合わせることで、システムをフェイルオーバー/フェイルバック完了するまでのイベントのロスを減らすことができます。

Amazon EventBridgeのアーカイブ機能の説明は以下記事をご覧ください。

グローバルエンドポイントの料金

グローバルエンドポイント使用時の追加料金は発生しません。

ただし、2022/4/25時点ではグローバルエンドポイントはカスタムイベントのみに使用できます。そのため、グローバルエンドポイントを使用する場合はPUTしたカスタムイベント分の課金が発生します。

また、イベントレプリケーションを有効化すると、セカンダリリージョンでもカスタムイベント分の課金が発生します。

使用できるリージョン

グローバルエンドポイントは東京リージョン、大阪リージョンを含む18リージョンで利用可能です。

  • us-east-1 (バージニア北部)
  • us-east-2 (オハイオ)
  • us-west-1 (北カリフォルニア)
  • us-west-2 (オレゴン)
  • ca-central-1 (カナダ中部)
  • eu-central-1 (フランクフルト)
  • eu-west-1 (アイルランド)
  • eu-west-2 (ロンドン)
  • eu-west-3 (パリ)
  • eu-south-1 (ミラノ)
  • eu-north-1 (ストックホルム)
  • ap-south-1 (ムンバイ)
  • ap-northeast-1 (東京)
  • ap-northeast-2 (ソウル)
  • ap-northeast-3 (大阪)
  • ap-southeast-1 (シンガポール)
  • ap-southeast-2 (シドニー)
  • sa-east-1 (サンパウロ)

やってみた

検証の構成

検証の構成は以下の通りです。

構成図

グローバルエンドポイントを介して、正しくイベントの配信先をセカンダリリージョン(ap-northeast-1)のイベントバスに自動でフェイルオーバーできるか確認します。

グローバルエンドポイントとCloudWatchアラーム、Route 53ヘルスチェック以外のリソースはAWS CDKでデプロイします。

こちらのコードのリポジトリは以下になります。

npx cdk deploy --allで各種リソースをデプロイします。

グローバルエンドポイントの作成

それでは、グローバルエンドポイントを作成します。

EventBridgeのコンソールからイベント-グローバルエンドポイント-エンドポイントを作成をクリックします。

エンドポイントを作成

まず、エンドポイントの名前とプライマリリージョンとセカンダリリージョンのイベントバスの設定を行います。

名前はglobal-endpoints-testで、プライマリリージョンはus-east-1globalEndpointsBus、セカンダリリージョンはap-northeast-1にしました。

なお、セカンダリリージョンのイベントバスは、プライマリージョンのイベントバスと同じ名前である必要があるので注意が必要です。

プライマリージョンとセカンダリリージョンのイベントバスの詳細

グローバルエンドポイントを作成する際には、Route 53ヘルスチェックを指定する必要があります。今回は新しくRoute 53ヘルスチェックを作成します。

新しくRoute 53ヘルスチェックを作成する場合は、新しいヘルスチェックをクリックします。

新しいヘルスチェック

すると、CloudFormationのスタック作成画面が表示されます。

今回はTreat missing data asのみデフォルトのbreakingからmissingに変更して、スタックの作成をクリックします。

Global endpoints health check

なお、Treat missing data asで選択できる各値の意味は以下の通りです。

  • breaking : 欠落データを不正 (しきい値を超えている)として処理
  • noBreaching : 欠落データを適正 (しきい値を超えていない) と処理
  • ignore : 欠落データを無視(アラーム状態を維持する)として処理
  • missing : 欠落データを見つかりませんとして処理

デフォルトのbreakingだと、CloudWatchアラームが最初からアラーム状態となり正しく検証ができないので、missingを選択しました。

スタックの作成が完了すると、CloudWatchアラームとRoute 53ヘルスチェックの2つのリソースが作成されたことが確認できます。

CloudFormationスタックで作成されたリソース

CloudWatchアラームを確認すると、スタック作成時のパラメーターで作成されていることが確認できました。

CloudWatchアラームの確認

Route 53ヘルスチェックを確認すると、一緒にCloudFormationで作成されたCloudWatchアラームと連携していることが分かります。

Route 53ヘルスチェックの確認

グローバルエンドポイントの作成画面に戻り、ロードすると先ほど作成したRoute 53ヘルスチェックを選択できるようになるので、選択します。

Route 53ヘルスチェックの選択

最後にイベントレプリケーションの設定です。今回はせっかくなのでイベントレプリケーションを有効化して、セカンダリリージョン(ap-northeast-1)にイベントがレプリケーションされるかを確認します。設定に問題がなければ作成をクリックします。

イベントレプリケーションの設定

数十秒ほど待つと、グローバルエンドポイントの作成が完了します。

グローバルエンドポイント作成完了確認

EventBridgeルールを確認すると、説明がManaged Rule for Global Endpoint Event Replicationとイベントレプリケーション用のEventBridgeルールが作成されていました。

Managed Rule for Global Endpoint Event Replication

Managed Rule for Global Endpoint Event Replicationのターゲット

また、イベントレプリケーション用のIAMロール(Amazon_EventBridge_Invoke_Event_Bus_593797116)のポリシーを確認すると、以下のようになっていました。

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Action": [
              "events:PutRule",
              "events:PutTargets",
              "events:DeleteRule",
              "events:RemoveTargets"
          ],
          "Resource": "arn:aws:events:*:<AWSアカウントID>:rule/globalEndpointsBus/GlobalEndpointManagedRule-*"
      },
      {
          "Effect": "Allow",
          "Action": [
              "events:PutEvents"
          ],
          "Resource": "arn:aws:events:*:<AWSアカウントID>:event-bus/globalEndpointsBus"
      },
      {
          "Effect": "Allow",
          "Action": [
              "iam:PassRole"
          ],
          "Resource": "arn:aws:iam::<AWSアカウントID>:role/service-role/Amazon_EventBridge_Invoke*",
          "Condition": {
              "StringLike": {
                  "iam:PassedToService": "events.amazonaws.com"
              }
          }
      }
  ]
}

イベントレプリケーションの確認

それではイベントレプリケーションの確認を行います。

用意したLambda関数は以下のように指定したイベントバスにuuidと現在のタイムスタンプをPutEventsするシンプルなものです。

./src/lambda/handlers/put-events-to-global-endpoints.ts

import {
  EventBridgeClient,
  PutEventsCommand,
} from "@aws-sdk/client-eventbridge";
import { v4 as uuidv4 } from "uuid";

export const handler = async (events: {
  EndpointId: string;
}): Promise<void | Error> => {
  const detail = {
    id: uuidv4(),
    date: Date.now(),
  };

  const client = new EventBridgeClient({
    region: process.env.AWS_REGION!,
  });

  const command = new PutEventsCommand({
    EndpointId: events.EndpointId,
    Entries: [
      {
        Detail: JSON.stringify(detail),
        DetailType: "put-events-to-global-endpoints",
        EventBusName: process.env.EVENT_BUS_NAME!,
        Source: "global-endpoints-test.non-97.net",
      },
    ],
  });

  const response = await client.send(command);

  console.log(response);

  return;
};

また、グローバルエンドポイントにPutEventsをする場合は、AWS Common Runtime (CRT) ライブラリが必要です。

今回はNode.jsで動作させるので、npm i aws-crtをした後、Lambda関数にバンドルするようにします。

AWS CDKでaws_lambda_nodejsモジュールを使用する場合は、以下のようにCRTライブラリをバンドルするようにLambda関数を定義します。

./lib/global-endpoints-stack.ts

new nodejs.NodejsFunction(this, "PutEventsToGlobalEndpointsFunction", {
  entry: path.join(
    __dirname,
    "../src/lambda/handlers/put-events-to-global-endpoints.ts"
  ),
  runtime: lambda.Runtime.NODEJS_14_X,
  bundling: {
    minify: true,
    sourceMap: true,
    nodeModules: ["aws-crt"],
  },
  environment: {
    EVENT_BUS_NAME: globalEndpointsEventBus.eventBusName,
    REGION: this.region,
    NODE_OPTIONS: "--enable-source-maps",
  },
  role: new iam.Role(this, "PutEventsToGlobalEndpointsFunctionIamRole", {
    assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
    managedPolicies: [
      iam.ManagedPolicy.fromAwsManagedPolicyName(
        "service-role/AWSLambdaBasicExecutionRole"
      ),
      new iam.ManagedPolicy(
        this,
        "PutEventsToGlobalEndpointsFunctionIamPolicy",
        {
          statements: [
            new iam.PolicyStatement({
              effect: iam.Effect.ALLOW,
              actions: ["events:PutEvents"],
              resources: [`arn:aws:events:*:${this.account}:event-bus/*`],
            }),
          ],
        }
      ),
    ],
  }),
  logRetention: logs.RetentionDays.TWO_WEEKS,
  timeout: Duration.seconds(60),
  tracing: lambda.Tracing.ACTIVE,
});

CRTライブラリをバンドルしない場合は、Lambda関数実行時に以下のようなエラーが出力されます。

{
  "errorType": "Error",
  "errorMessage": "Cannot find module '@aws-sdk/signature-v4-crt'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js\nPlease check if you have installed \"@aws-sdk/signature-v4-crt\" package explicitly. \nFor more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt",
  "trace": [
    "Error: Cannot find module '@aws-sdk/signature-v4-crt'",
    "Require stack:",
    "- /var/task/index.js",
    "- /var/runtime/UserFunction.js",
    "- /var/runtime/index.js",
    "Please check if you have installed \"@aws-sdk/signature-v4-crt\" package explicitly. ",
    "For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt",
    "    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)",
    "    at Function.Module._load (internal/modules/cjs/loader.js:746:27)",
    "    at Module.require (internal/modules/cjs/loader.js:974:19)",
    "    at require (internal/modules/cjs/helpers.js:101:18)",
    "    at qf.getSigv4aSigner (/node_modules/@aws-sdk/signature-v4-multi-region/dist-cjs/SignatureV4MultiRegion.js:30:64)",
    "    at qf.sign (/node_modules/@aws-sdk/signature-v4-multi-region/dist-cjs/SignatureV4MultiRegion.js:14:25)",
    "    at null.<anonymous> (/node_modules/@aws-sdk/middleware-signing/dist-cjs/middleware.js:13:31)",
    "    at zu.retry (/node_modules/@aws-sdk/middleware-retry/dist-cjs/StandardRetryStrategy.js:51:46)",
    "    at null.<anonymous> (/node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:6:22)",
    "    at Runtime.eW (/src/lambda/handlers/put-events-to-global-endpoints.ts:30:20)"
  ]
}

ちなみに、エラーメッセージ内の@aws-sdk/signature-v4-crtをインストールしてLambda関数にバンドルしても、CRTライブラリがない場合はLambda関数実行時に以下のようなエラーが出力されます。

{
  "errorType": "Error",
  "errorMessage": "AWS CRT binary not present in any of the following locations:\n\t/bin/native/aws-crt-nodejs\n\t/bin/linux-x64/aws-crt-nodejs",
  "stack": [
    "Error: AWS CRT binary not present in any of the following locations:",
    "\t/bin/native/aws-crt-nodejs",
    "\t/bin/linux-x64/aws-crt-nodejs",
    "    at null.<anonymous> (/node_modules/aws-crt/lib/native/binding.js:46:11)",
    "    at /var/task/index.js:1:733",
    "    at null.<anonymous> (/node_modules/aws-crt/lib/native/crt.ts:22:1)",
    "    at /var/task/index.js:1:733",
    "    at null.<anonymous> (/node_modules/aws-crt/lib/index.ts:18:1)",
    "    at /var/task/index.js:1:733",
    "    at null.<anonymous> (/node_modules/@aws-sdk/signature-v4-crt/dist-cjs/CrtSignerV4.js:7:19)",
    "    at /var/task/index.js:1:733",
    "    at null.<anonymous> (/node_modules/@aws-sdk/signature-v4-crt/dist-cjs/index.js:4:22)",
    "    at /var/task/index.js:1:733"
  ]
}

us-east-1のLambda関数でグローバルエンドポイントのIDをイベントとして、テストをクリックします。

{
  "EndpointId": "wshsmf4fgu.veo"
}

Lambda関数のテスト

実行時のLambda関数のログは以下のようになっていました。

START RequestId: 57681032-dfcd-4113-b5b0-5e1feaee8e9f Version: $LATEST
2022-04-25T04:52:49.515Z	57681032-dfcd-4113-b5b0-5e1feaee8e9f	INFO	{
  '$metadata': {
    httpStatusCode: 200,
    requestId: '94d45ad6-f3ee-48ba-90a5-cebf544e0e98',
    extendedRequestId: undefined,
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  },
  Entries: [
    {
      ErrorCode: undefined,
      ErrorMessage: undefined,
      EventId: '9c186089-1f7a-0c1b-fe57-78176bc686b4'
    }
  ],
  FailedEntryCount: 0
}
END RequestId: 57681032-dfcd-4113-b5b0-5e1feaee8e9f
REPORT RequestId: 57681032-dfcd-4113-b5b0-5e1feaee8e9f	Duration: 12225.95 ms	Billed Duration: 12226 ms	Memory Size: 128 MB	Max Memory Used: 124 MB	Init Duration: 290.12 ms	
XRAY TraceId: 1-62662914-791bd5a1237d5b7b28068756	SegmentId: 3f1a49030d8b7a2f	Sampled: true

Lambda関数実行後にus-east-1のステートマシンを確認すると、Lambda関数の実行が完了したタイミングでステートマシンが実行されていることが確認できました。

us-east-1のステートマシンの実行結果確認

Passタスクが受け取ったイベントは以下の通りです。

{
  "version": "0",
  "id": "9c186089-1f7a-0c1b-fe57-78176bc686b4",
  "detail-type": "put-events-to-global-endpoints",
  "source": "global-endpoints-test.non-97.net",
  "account": "<AWSアカウントID>",
  "time": "2022-04-25T04:52:49Z",
  "region": "us-east-1",
  "resources": [
    "arn:aws:events:us-east-1:<AWSアカウントID>:endpoint/global-endpoints-test"
  ],
  "detail": {
    "id": "80a5f686-aefd-490a-9ade-b7b4b8371497",
    "date": 1650862357334
  }
}

ap-northeast-1のステートマシンを確認すると、us-east-1のステートマシンとほぼ同じタイミングでステートマシンが実行されていることが確認できました。

ap-northeast-1のステートマシンの実行結果確認

Passタスクが受け取ったイベントは、us-east-1のステートマシンのPassタスクが受け取ったイベントと全く同じでした。

regionus-east-1であり、us-east-1で発生したイベントがap-northeast-1にレプリケーションできたことが確認できました。

また、CloudWatchアラームを確認すると、IngestionToInvocationStartLatency259.5と しきい値の30,000を下回っていることからステータスがOKとなっています。

OK状態のCloudWatchアラームの確認

イベントのフェイルオーバー確認

次にイベントのフェイルオーバー確認を行います。

フェイルオーバーの確認を行う際は、グローバルエンドポイントと関連づいているRoute 53ヘルスチェックでヘルスチェックステータスを反転にチェックを入れて保存します。

ヘルスチェックステータスを反転

すると、Route 53ヘルスチェックが異常状態に遷移します。

異常状態のRoute 53ヘルスチェックの確認

続いて、イベントレプリケーションをしているとフェイルオーバーされたイベントなのか、レプリケーションされたイベントなのかが分からなくなるので、イベントレプリケーションを無効化します。

イベントレプリケーションの無効化

イベントレプリケーションの無効化

イベントレプリケーションの無効化後、再度us-east-1のLambda関数でグローバルエンドポイントのIDをイベントとして、Lambda関数を実行します。

実行時のLambda関数のログは以下のようになっていました。

START RequestId: 65f42599-06da-41d6-b2ce-ac051c36abca Version: $LATEST
2022-04-25T05:14:09.524Z	65f42599-06da-41d6-b2ce-ac051c36abca	INFO	{
  '$metadata': {
    httpStatusCode: 200,
    requestId: '50935dc0-2b8a-4e6b-8b57-fd84cecaf388',
    extendedRequestId: undefined,
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  },
  Entries: [
    {
      ErrorCode: undefined,
      ErrorMessage: undefined,
      EventId: 'a9da377f-2775-b457-c424-89a4ed8e62f5'
    }
  ],
  FailedEntryCount: 0
}
END RequestId: 65f42599-06da-41d6-b2ce-ac051c36abca
REPORT RequestId: 65f42599-06da-41d6-b2ce-ac051c36abca	Duration: 13362.91 ms	Billed Duration: 13363 ms	Memory Size: 128 MB	Max Memory Used: 125 MB	Init Duration: 291.98 ms	
XRAY TraceId: 1-62662e13-41f47b936a98e17c3f78f16a	SegmentId: 326f56ba7daddf14	Sampled: true

Lambda関数実行後にus-east-1のステートマシンを確認すると、新しく実行はされていないようでした。

フェイルオーバーテスト時のus-east-1のステートマシン実行結果確認

一方、ap-northeast-1のステートマシンを確認すると、Lambda関数の実行が完了したタイミングでステートマシンが実行されていることが確認できました。

フェイルオーバーテスト時のap-northeast-1のステートマシン実行結果確認

{
  "version": "0",
  "id": "a9da377f-2775-b457-c424-89a4ed8e62f5",
  "detail-type": "put-events-to-global-endpoints",
  "source": "global-endpoints-test.non-97.net",
  "account": "<AWSアカウントID>",
  "time": "2022-04-25T05:14:09Z",
  "region": "ap-northeast-1",
  "resources": [
    "arn:aws:events:us-east-1:<AWSアカウントID>:endpoint/global-endpoints-test"
  ],
  "detail": {
    "id": "17feb162-0f19-489a-8b59-95c661061886",
    "date": 1650863636220
  }
}

regionもLambda関数が存在しているus-east-1ではなく、ap-northeast-1となっており、イベントがセカンダリリージョンにフェイルオーバーしたことが確認できました。

なお、イベントレプリケーションを有効化してから再度us-east-1のLambda関数を実行すると、us-east-1のステートマシンが実行されました。

フェイルオーバーテスト時のus-east-1のステートマシン実行結果確認

Passタスクが受け取ったイベントは以下の通りで、regionがLambda関数が存在しているus-east-1ではなく、ap-northeast-1となっていることから、フェイルオーバーした場合は、イベントレプリケーションの方向がセカンダリリージョンからプライマリリージョンになっていることが分かります。

{
  "version": "0",
  "id": "e2ed6473-afd7-14c0-60da-82a9f9a58968",
  "detail-type": "put-events-to-global-endpoints",
  "source": "global-endpoints-test.non-97.net",
  "account": "<AWSアカウントID>",
  "time": "2022-04-26T00:30:30Z",
  "region": "ap-northeast-1",
  "resources": [
    "arn:aws:events:us-east-1:<AWSアカウントID>:endpoint/global-endpoints-test"
  ],
  "detail": {
    "id": "9c86fee9-70dd-43e0-9189-e7391c155569",
    "date": 1650933016829
  }
}

リージョンレベルでの障害に対応する場合はグローバルエンドポイントを

Amazon EventBridgeのグローバルエンドポイントを紹介しました。

グローバルエンドポイントを上手に使うことで、イベント駆動型アーキテクチャのシステムの可用性を高めることができそうです。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!