要約
AWS Lambda APIは、開発者がサーバーレス関数をプログラムでデプロイ、管理、呼び出すことを可能にします。IAM認証、関数管理のためのRESTfulエンドポイント、非同期および同期呼び出しオプションを使用し、アカウントレベルの同時実行制限があります。このガイドでは、認証設定、関数デプロイ、呼び出しパターン、イベントソースマッピング、および本番環境でのサーバーレスアーキテクチャ戦略について説明します。
はじめに
AWS Lambdaは、100万人以上のアクティブユーザーのために毎月数兆のリクエストを処理しています。サーバーレスアプリケーション、自動化ツール、またはイベント駆動型アーキテクチャを構築する開発者にとって、Lambda APIの統合はオプションではありません。これはインフラストラクチャ・アズ・コード(IaC)やCI/CDパイプラインにとって不可欠です。
現実として、50以上のLambda関数を手動で管理しているチームは、デプロイ、設定更新、監視に毎週10〜15時間を費やしています。堅牢なLambda API統合は、デプロイを自動化し、ブルー/グリーンリリースを実装し、需要に基づいた動的なスケーリングを可能にします。
このガイドでは、AWS Lambda APIの統合プロセス全体を説明します。IAM認証、関数の作成とデプロイ、呼び出しパターン(同期/非同期)、イベントソースマッピング、レイヤー化されたアーキテクチャ、および本番環境デプロイ戦略を学びます。最終的には、本番環境に対応したLambda統合が手に入ります。
AWS Lambda APIとは?
AWS Lambda は、サーバーレスコンピューティング関数を管理するためのRESTful APIを提供します。このAPIは以下を処理します。
- 関数の作成、更新、削除
- コードのデプロイとバージョン管理
- 関数の呼び出し(同期および非同期)
- イベントソースマッピング(SQS、Kinesis、DynamoDB、S3)
- 共有コードのためのレイヤー管理
- エイリアスとルーティング設定
- 同時実行と予約容量の管理
- ロギングと監視の統合
主要機能
| 機能 | 説明 |
|---|---|
| RESTful API | 標準的なHTTPSエンドポイント |
| IAM認証 | AWS署名バージョン4 |
| 非同期呼び出し | 処理後に結果を待たないイベント処理 |
| 同期呼び出し | リクエスト-レスポンスパターン |
| イベントソース | 200以上のAWSサービス統合 |
| レイヤー | 共有コードと依存関係 |
| バージョン/エイリアス | トラフィックシフトとロールバック |
| プロビジョニングされた同時実行 | コールドスタートの排除 |
Lambdaランタイムサポート
| ランタイム | バージョン | ユースケース |
|---|---|---|
| Node.js | 18.x, 20.x | APIバックエンド、イベント処理 |
| Python | 3.9, 3.10, 3.11 | データ処理、ML推論 |
| Java | 11, 17, 21 | エンタープライズアプリケーション |
| Go | 1.x | 高性能API |
| Rust | 1.x | 低レイテンシ関数 |
| .NET | 6, 8 | Windowsワークロード |
| Ruby | 3.x | ウェブアプリケーション |
| カスタム | 任意 | コンテナベースのランタイム |
APIアーキテクチャの概要
LambdaはAWSサービスAPIの構造を使用します:
https://lambda.{region}.amazonaws.com/2015-03-31/
APIバージョン
| バージョン | ステータス | ユースケース |
|---|---|---|
| 2015-03-31 | 現行 | すべてのLambda操作 |
| 2018-01-31 | ランタイムAPI | カスタムランタイムインターフェース |
はじめに:認証設定
ステップ1:AWSアカウントとIAMユーザーの作成
APIにアクセスする前に:
- AWSコンソールにアクセス
- AWSアカウントを作成
- IAMコンソール > ユーザー > ユーザーの作成 に進む
- Lambda実行ポリシーをアタッチする
ステップ2:IAM認証情報の生成
プログラムによるアクセス用のアクセスキーを作成します:
# AWS CLIメソッド
aws iam create-access-key --user-name lambda-deployer
# 出力:これらを安全に保管してください
{
"AccessKey": {
"AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
}
セキュリティ上の注意: 認証情報を安全に保管してください:
# ~/.aws/credentials
[lambda-deployer]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# または環境変数を使用
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_DEFAULT_REGION="us-east-1"
ステップ3:AWS署名バージョン4を理解する
すべてのLambda APIリクエストにはSigV4署名が必要です:
const crypto = require('crypto');
class AWSSigner {
constructor(accessKeyId, secretAccessKey, region, service = 'lambda') {
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.region = region;
this.service = service;
}
sign(request, body = null) {
const now = new Date();
const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
const dateStamp = amzDate.slice(0, 8);
// タスク1:カノニカルリクエストを作成
const hashedPayload = body ? crypto.createHash('sha256').update(body).digest('hex') : 'UNSIGNED-PAYLOAD';
const canonicalUri = request.path;
const canonicalQuerystring = request.query || '';
const canonicalHeaders = `host:${request.host}\nx-amz-date:${amzDate}\n`;
const signedHeaders = 'host;x-amz-date';
const canonicalRequest = `${request.method}\n${canonicalUri}\n${canonicalQuerystring}\n${canonicalHeaders}\n${signedHeaders}\n${hashedPayload}`;
// タスク2:署名する文字列を作成
const algorithm = 'AWS4-HMAC-SHA256';
const credentialScope = `${dateStamp}/${this.region}/${this.service}/aws4_request`;
const hash = crypto.createHash('sha256').update(canonicalRequest).digest('hex');
const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${hash}`;
// タスク3:署名を計算
const kDate = this.hmac(`AWS4${this.secretAccessKey}`, dateStamp);
const kRegion = this.hmac(kDate, this.region);
const kService = this.hmac(kRegion, this.service);
const kSigning = this.hmac(kService, 'aws4_request');
const signature = this.hmac(kSigning, stringToSign, 'hex');
// タスク4:認証ヘッダーを追加
const authorizationHeader = `${algorithm} Credential=${this.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
return {
'Authorization': authorizationHeader,
'X-Amz-Date': amzDate,
'X-Amz-Content-Sha256': hashedPayload
};
}
hmac(key, string, encoding = 'buffer') {
return crypto.createHmac('sha256', key).update(string).digest(encoding);
}
}
// 使用例
const signer = new AWSSigner(
process.env.AWS_ACCESS_KEY_ID,
process.env.AWS_SECRET_ACCESS_KEY,
'us-east-1'
);
ステップ4:Lambda APIクライアントの作成
const LAMBDA_BASE_URL = 'https://lambda.us-east-1.amazonaws.com/2015-03-31';
const lambdaRequest = async (path, options = {}) => {
const url = new URL(`${LAMBDA_BASE_URL}${path}`);
const method = options.method || 'GET';
const body = options.body ? JSON.stringify(options.body) : null;
const signer = new AWSSigner(
process.env.AWS_ACCESS_KEY_ID,
process.env.AWS_SECRET_ACCESS_KEY,
'us-east-1'
);
const headers = signer.sign({ method, host: 'lambda.us-east-1.amazonaws.com', path }, body);
const response = await fetch(url.toString(), {
method,
headers: {
'Content-Type': 'application/json',
...headers,
...options.headers
},
body
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Lambda API Error: ${error.Message}`);
}
return response.json();
};
// 使用例
const functions = await lambdaRequest('/functions');
console.log(`Found ${functions.Functions.length} functions`);
代替手段:AWS SDKを使用する
本番環境では、AWS SDKが自動的に署名を処理します:
const { LambdaClient, ListFunctionsCommand, CreateFunctionCommand, InvokeCommand } = require('@aws-sdk/client-lambda');
const lambda = new LambdaClient({ region: 'us-east-1' });
// 関数をリスト表示
const listCommand = new ListFunctionsCommand({});
const result = await lambda.send(listCommand);
// 関数を作成
const createCommand = new CreateFunctionCommand({
FunctionName: 'my-function',
Runtime: 'nodejs20.x',
Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
Handler: 'index.handler',
Code: {
S3Bucket: 'my-bucket',
S3Key: 'function.zip'
}
});
const fn = await lambda.send(createCommand);
関数管理
関数の作成
API経由でLambda関数を作成します:
const createFunction = async (functionConfig) => {
const response = await lambdaRequest('/functions', {
method: 'POST',
body: {
FunctionName: functionConfig.name,
Runtime: functionConfig.runtime || 'nodejs20.x',
Role: functionConfig.roleArn,
Handler: functionConfig.handler || 'index.handler',
Code: {
S3Bucket: functionConfig.s3Bucket,
S3Key: functionConfig.s3Key
},
Description: functionConfig.description || '',
Timeout: functionConfig.timeout || 3,
MemorySize: functionConfig.memorySize || 128,
Environment: {
Variables: functionConfig.environment || {}
},
Tags: functionConfig.tags || {}
}
});
return response;
};
// 使用例
const fn = await createFunction({
name: 'order-processor',
roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
handler: 'index.handler',
runtime: 'nodejs20.x',
s3Bucket: 'my-deployments-bucket',
s3Key: 'order-processor/v1.0.0.zip',
description: 'Process orders from SQS queue',
timeout: 30,
memorySize: 512,
environment: {
DB_HOST: 'db.example.com',
LOG_LEVEL: 'info'
}
});
console.log(`Function created: ${fn.FunctionArn}`);
コードの直接アップロード
小規模な関数(圧縮後50MB未満)の場合:
const fs = require('fs');
const path = require('path');
const createFunctionWithZip = async (functionName, zipPath) => {
const zipBuffer = fs.readFileSync(zipPath);
const base64Code = zipBuffer.toString('base64');
const response = await lambdaRequest('/functions', {
method: 'POST',
body: {
FunctionName: functionName,
Runtime: 'nodejs20.x',
Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
Handler: 'index.handler',
Code: {
ZipFile: base64Code
}
}
});
return response;
};
// 関数をパッケージ化
// zip -r function.zip index.js node_modules/
await createFunctionWithZip('my-function', './function.zip');
関数コードの更新
新しいコードバージョンをデプロイします:
const updateFunctionCode = async (functionName, updateConfig) => {
const response = await lambdaRequest(`/functions/${functionName}/code`, {
method: 'PUT',
body: {
S3Bucket: updateConfig.s3Bucket,
S3Key: updateConfig.s3Key,
Publish: updateConfig.publish || false
}
});
return response;
};
// 使用例
const updated = await updateFunctionCode('order-processor', {
s3Bucket: 'my-deployments-bucket',
s3Key: 'order-processor/v1.1.0.zip',
publish: true // 新しいバージョンを作成
});
console.log(`Updated to version: ${updated.Version}`);
関数設定の更新
タイムアウト、メモリ、環境を変更します:
const updateFunctionConfig = async (functionName, config) => {
const response = await lambdaRequest(`/functions/${functionName}/configuration`, {
method: 'PUT',
body: {
Runtime: config.runtime,
Handler: config.handler,
Description: config.description,
Timeout: config.timeout,
MemorySize: config.memorySize,
Environment: {
Variables: config.environment
}
}
});
return response;
};
// 使用例
const updated = await updateFunctionConfig('order-processor', {
timeout: 60,
memorySize: 1024,
environment: {
DB_HOST: 'new-db.example.com',
LOG_LEVEL: 'debug'
}
});
関数の削除
関数を削除します:
const deleteFunction = async (functionName, qualifier = null) => {
const path = qualifier
? `/functions/${functionName}?Qualifier=${qualifier}`
: `/functions/${functionName}`;
await lambdaRequest(path, { method: 'DELETE' });
console.log(`Function ${functionName} deleted`);
};
関数呼び出し
同期呼び出し(リクエスト-レスポンス)
関数を呼び出し、レスポンスを待ちます:
const invokeFunction = async (functionName, payload, qualifier = null) => {
const path = qualifier
? `/functions/${functionName}/invocations?Qualifier=${qualifier}`
: `/functions/${functionName}/invocations`;
const response = await lambdaRequest(path, {
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'RequestResponse', // 同期
'X-Amz-Log-Type': 'Tail' // ログを含む
},
body: payload
});
// レスポンスをパース
const result = JSON.parse(Buffer.from(response.Payload).toString());
const logs = Buffer.from(response.LogResult, 'base64').toString();
return { result, logs };
};
// 使用例
const { result, logs } = await invokeFunction('order-processor', {
orderId: 'ORD-12345',
customerId: 'CUST-67890',
items: [
{ sku: 'PROD-001', quantity: 2 },
{ sku: 'PROD-002', quantity: 1 }
]
});
console.log(`Result: ${JSON.stringify(result)}`);
console.log(`Logs:\n${logs}`);
非同期呼び出し(ファイア・アンド・フォーゲット)
待機せずに関数を呼び出します:
const invokeAsync = async (functionName, payload) => {
const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'Event', // 非同期
'X-Amz-Log-Type': 'None'
},
body: payload
});
return {
statusCode: response.StatusCode,
executionId: response['X-Amz-Execution-Id']
};
};
// 使用例 - 非同期処理をトリガー
const result = await invokeAsync('email-sender', {
to: 'customer@example.com',
template: 'order-confirmation',
data: { orderId: 'ORD-12345' }
});
console.log(`Async invocation ID: ${result.executionId}`);
ドライラン呼び出し
実行せずに権限をテストします:
const dryRunInvocation = async (functionName) => {
const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'DryRun'
}
});
return response;
};
// 使用例 - IAM権限の検証
try {
await dryRunInvocation('order-processor');
console.log('Invocation permissions OK');
} catch (error) {
console.error('Permission denied:', error.message);
}
呼び出しレスポンスタイプ
| 呼び出しタイプ | 動作 | ユースケース |
|---|---|---|
RequestResponse |
同期、結果を待機 | API呼び出し、CLIコマンド |
Event |
非同期、処理後に結果を待たない | イベント処理、通知 |
DryRun |
権限のみテスト | 検証、デバッグ |
バージョンとエイリアス管理
バージョンの公開
イミュータブルな関数バージョンを作成します:
const publishVersion = async (functionName, description = null) => {
const response = await lambdaRequest(`/functions/${functionName}/versions`, {
method: 'POST',
body: description ? { Description: description } : {}
});
return response;
};
// 使用例
const version = await publishVersion('order-processor', 'v1.2.0 - Add tax calculation');
console.log(`Published version: ${version.Version}`);
エイリアスの作成
バージョンへの名前付きポインタを作成します:
const createAlias = async (functionName, aliasName, version, description = null) => {
const response = await lambdaRequest(`/functions/${functionName}/aliases`, {
method: 'POST',
body: {
Name: aliasName,
FunctionVersion: version,
Description: description
}
});
return response;
};
// 使用例 - 本番エイリアスを作成
const prodAlias = await createAlias('order-processor', 'prod', '5', 'Production version');
console.log(`Alias ARN: ${prodAlias.AliasArn}`);
ルーティング設定によるトラフィックシフト
新しいバージョンへ徐々にトラフィックをシフトします:
const updateAliasWithRouting = async (functionName, aliasName, routingConfig) => {
const response = await lambdaRequest(`/functions/${functionName}/aliases/${aliasName}`, {
method: 'PUT',
body: {
RoutingConfig: {
AdditionalVersionWeights: routingConfig
}
}
});
return response;
};
// 使用例 - バージョン6に10%、バージョン5に90%のトラフィックをシフト
await updateAliasWithRouting('order-processor', 'prod', {
'6': 0.1
});
// 検証後、100%にシフト
await updateAliasWithRouting('order-processor', 'prod', {});
エイリアスのユースケース
| エイリアス | バージョン | 目的 |
|---|---|---|
dev |
$LATEST | 開発テスト |
staging |
最新のテスト済み | QA検証 |
prod |
安定版 | 本番トラフィック |
blue |
現在の本番 | ブルー/グリーンデプロイ |
green |
新しいバージョン | ブルー/グリーンデプロイ |
イベントソースマッピング
SQSトリガーの作成
SQSキューをLambdaに接続します:
const createSQSEventSource = async (functionName, queueArn, batchSize = 10) => {
const response = await lambdaRequest('/event-source-mappings', {
method: 'POST',
body: {
EventSourceArn: queueArn,
FunctionName: functionName,
BatchSize: batchSize,
Enabled: true
}
});
return response;
};
// 使用例
const mapping = await createSQSEventSource(
'order-processor',
'arn:aws:sqs:us-east-1:123456789012:orders-queue',
10
);
console.log(`Event source created: ${mapping.UUID}`);
DynamoDBストリームトリガーの作成
DynamoDBストリームをLambdaに接続します:
const createDynamoDBEventSource = async (functionName, streamArn, startingPosition = 'LATEST') => {
const response = await lambdaRequest('/event-source-mappings', {
method: 'POST',
body: {
EventSourceArn: streamArn,
FunctionName: functionName,
StartingPosition: startingPosition,
BatchSize: 100,
BisectBatchOnFunctionError: true,
MaximumRetryAttempts: 3
}
});
return response;
};
// 使用例
await createDynamoDBEventSource(
'user-analytics',
'arn:aws:dynamodb:us-east-1:123456789012:table/Users/stream/2026-03-25T00:00:00.000'
);
イベントソースのタイプ
| ソース | ユースケース | バッチサポート |
|---|---|---|
| SQS | メッセージキュー | あり (1-10) |
| Kinesis | リアルタイムストリーム | あり (1-10,000) |
| DynamoDB Streams | データベースの変更 | あり (1-1,000) |
| S3 | オブジェクトイベント | なし (イベントごとに1つ) |
| EventBridge | イベントルーティング | あり |
| API Gateway | HTTP API | なし |
| Schedule | Cronジョブ | なし |
レイヤー管理
レイヤーの作成
共有コード/依存関係をパッケージ化します:
const createLayer = async (layerName, layerConfig) => {
const response = await lambdaRequest('/layers', {
method: 'POST',
body: {
LayerName: layerName,
Description: layerConfig.description,
CompatibleRuntimes: layerConfig.runtimes,
Content: {
S3Bucket: layerConfig.s3Bucket,
S3Key: layerConfig.s3Key
}
}
});
return response;
};
// 使用例
const layer = await createLayer('shared-utils', {
description: 'Shared utilities and dependencies',
runtimes: ['nodejs20.x', 'nodejs18.x'],
s3Bucket: 'my-layers-bucket',
s3Key: 'shared-utils/v1.zip'
});
console.log(`Layer ARN: ${layer.LayerArn}`);
関数でのレイヤーの使用
関数にレイヤーをアタッチします:
const createFunctionWithLayers = async (functionConfig) => {
const response = await lambdaRequest('/functions', {
method: 'POST',
body: {
FunctionName: functionConfig.name,
Runtime: functionConfig.runtime,
Role: functionConfig.roleArn,
Handler: functionConfig.handler,
Code: {
S3Bucket: functionConfig.s3Bucket,
S3Key: functionConfig.s3Key
},
Layers: functionConfig.layers // レイヤーARNの配列
}
});
return response;
};
// 使用例
await createFunctionWithLayers({
name: 'api-handler',
roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
handler: 'index.handler',
runtime: 'nodejs20.x',
s3Bucket: 'my-deployments-bucket',
s3Key: 'api-handler/v1.0.0.zip',
layers: [
'arn:aws:lambda:us-east-1:123456789012:layer:shared-utils:1',
'arn:aws:lambda:us-east-1:123456789012:layer:aws-sdk:3'
]
});
同時実行とスケーリング
予約済み同時実行数の設定
重要な関数に容量を予約します:
const putFunctionConcurrency = async (functionName, reservedConcurrentExecutions) => {
const response = await lambdaRequest(`/functions/${functionName}/concurrency`, {
method: 'PUT',
body: {
ReservedConcurrentExecutions: reservedConcurrentExecutions
}
});
return response;
};
// 使用例 - 100の同時実行を予約
await putFunctionConcurrency('order-processor', 100);
アカウントの同時実行制限
| アカウントタイプ | デフォルト制限 | 増加可能 |
|---|---|---|
| 無料枠 | 1,000 | はい |
| 従量課金制 | 1,000 | はい |
| エンタープライズ | 1,000以上 | カスタム制限 |
本番デプロイチェックリスト
本番環境にデプロイする前に:
- [ ] 自動SigV4署名のためにAWS SDKを使用する
- [ ] エイリアスを使用してバージョン管理を実装する
- [ ] 重要な関数に予約済み同時実行数を設定する
- [ ] 非同期呼び出しのためにデッドレターキュー(DLQ)を設定する
- [ ] デバッグのためにX-Rayトレースを有効にする
- [ ] データベースアクセス用にVPCを設定する
- [ ] 構造化ロギング(JSON形式)を実装する
- [ ] CloudWatchアラームを設定する
- [ ] 共有依存関係にレイヤーを使用する
- [ ] ブルー/グリーンデプロイ戦略を実装する
実際のユースケース
APIバックエンド
SaaS企業がサーバーレスREST APIを構築:
- 課題:変動するトラフィック、予測不可能なスケーリング
- 解決策:Lambda + API Gatewayとオートスケーリング
- 結果:99.99%のアップタイム、EC2と比較して60%のコスト削減
主要な実装:
- リソースごとのLambda関数
- ルーティング/認証のためのAPI Gateway
- データストレージのためのDynamoDB
- 一貫したレイテンシのためのプロビジョニングされた同時実行
イベント処理パイプライン
Eコマースプラットフォームが注文を処理:
- 課題:セールイベント中の注文の急増
- 解決策:SQS + Lambdaとバッチ処理
- 結果:注文の損失ゼロ、10倍のスパイク処理が可能
主要な実装:
- SQSキューが注文をバッファリング
- Lambdaが1バッチあたり10メッセージを処理
- 失敗したメッセージのためのDLQ
- キュー深度に関するCloudWatchアラート
結論
AWS Lambda APIは、包括的なサーバーレスコンピューティング機能を提供します。主なポイント:
- SigV4署名付きのIAM認証(AWS SDKを使用)
- 同期および非同期呼び出しパターン
- デプロイのためのバージョンとエイリアス管理
- サーバーレスアーキテクチャのためのイベントソースマッピング
- 共有コードと依存関係のためのレイヤー
- ApidogはAPIテストとチームコラボレーションを効率化します
FAQセクション
Lambda APIで認証するにはどうすればよいですか?
AWS IAM認証情報を署名バージョン4で署名して使用します。AWS SDKは自動的に署名を処理します。
同期呼び出しと非同期呼び出しの違いは何ですか?
同期(RequestResponse)は関数が完了するまで待機し、結果を返します。非同期(Event)はリクエストをキューに入れ、すぐに返します。
Lambdaのバージョンはどのように機能しますか?
公開された各バージョンは、関数の不変なスナップショットです。エイリアスを使用して特定のバージョンを指し、トラフィックシフトを可能にします。
Lambdaレイヤーとは何ですか?
レイヤーはコードと依存関係を関数コードとは別にパッケージ化し、複数の関数で共有ライブラリを使用できるようにします。
コールドスタートを減らすにはどうすればよいですか?
プロビジョニングされた同時実行数、より小さなデプロイパッケージ、およびコンパイルされた言語(Go、Rust)をレイテンシに敏感な関数に使用します。
予約済み同時実行数とは何ですか?
予約済み同時実行数は、特定の関数の実行スロットを保証し、「騒がしい隣人」問題を防止します。
S3からLambdaをトリガーできますか?
はい、S3イベント通知を設定して、オブジェクトの作成/削除時にLambdaを呼び出すことができます。
