AWS Lambda
プラットフォーム
AWS Lambda
概要
AWS Lambdaは、Amazonが提供するサーバーレスコンピューティングサービスの先駆者として、イベント駆動型のコード実行、自動スケーリング、従量課金により、サーバー管理不要でアプリケーションを構築できる革新的なプラットフォームです。2014年のリリース以来、サーバーレス市場のリーダーシップを維持し、API Gateway、DynamoDB、S3、EventBridge等との深い統合により、完全サーバーレスアーキテクチャの構築を可能にしています。Node.js、Python、Java、C#、Go、Ruby、PowerShellなど15以上のランタイムをサポートし、ミリ秒単位の課金により、真の使用分のみの支払いを実現しています。
詳細
AWS Lambda 2025年版は、エンタープライズグレードのサーバーレスコンピューティングプラットフォームとして、毎日数十億回の実行をサポートしています。最新のArm Graviton3プロセッサーにより最大34%のパフォーマンス向上を実現し、プロビジョニング済み同時実行により一貫したレスポンス時間を保証します。Lambda Layersによる依存関係の管理、Lambda Extensionsによる観測性とセキュリティツールの統合、コンテナイメージサポートによる既存ワークロードの移行など、エンタープライズ要件に対応した豊富な機能を提供します。また、Lambda Snapstartにより、Javaアプリケーションの起動時間を最大90%短縮し、高性能な実行環境を実現しています。
主な特徴
- イベント駆動実行: 250以上のAWSサービスとの統合
- 自動スケーリング: ゼロから1000同時実行まで自動対応
- 多言語ランタイム: 15以上のプログラミング言語サポート
- 従量課金: 100ms単位の実行時間のみ課金
- 高可用性: 99.95%のSLAと複数AZ冗長
- セキュリティ: VPCサポート、IAM統合、暗号化
メリット・デメリット
メリット
- サーバーレス市場のパイオニアとして最も成熟したエコシステム
- 250以上のAWSサービスとのネイティブ統合による強力なイベント駆動アーキテクチャ
- プロビジョニング済み同時実行による一貫したパフォーマンス保証
- Lambda Snapstartによる大幅なコールドスタート時間短縮
- 豊富なモニタリング・ログ機能(CloudWatch、X-Ray統合)
- エンタープライズグレードのセキュリティとコンプライアンス対応
デメリット
- 15分の実行時間制限により長時間処理には不適
- 10GBのメモリ制限とEphemeral storageの制約
- コールドスタートによる初回実行遅延(Snapstart対応言語以外)
- AWSエコシステムへのベンダーロックインリスク
- 複雑な権限管理(IAM)による学習コストの高さ
- 大量同時実行時の課金額増大によるコスト予測困難性
参考ページ
書き方の例
セットアップと関数作成
# AWS CLIのインストールと設定
pip install awscli
aws configure
# AWS SAM CLIのインストール
pip install aws-sam-cli
# 新しいLambda関数プロジェクトの作成
sam init --runtime nodejs18.x --name my-lambda-function
cd my-lambda-function
# ローカルでの実行とテスト
sam local start-api --port 3000
sam local invoke HelloWorldFunction --event events/event.json
// Node.js関数の基本構造
exports.handler = async (event, context) => {
console.log('Event:', JSON.stringify(event, null, 2));
console.log('Context:', JSON.stringify(context, null, 2));
try {
// メイン処理
const result = await processEvent(event);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
message: 'Function executed successfully',
result: result,
timestamp: new Date().toISOString()
})
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
error: 'Internal server error',
message: error.message
})
};
}
};
async function processEvent(event) {
// ビジネスロジックの実装
return {
eventType: event.Records ? 'S3/SQS Event' : 'API Gateway',
eventSource: event.source || 'unknown',
processed: true
};
}
HTTP APIとリクエスト処理
// API Gateway統合のLambda関数
exports.apiHandler = async (event, context) => {
const httpMethod = event.httpMethod || event.requestContext?.http?.method;
const path = event.path || event.rawPath;
const pathParameters = event.pathParameters || {};
const queryParameters = event.queryStringParameters || {};
const headers = event.headers || {};
const body = event.body ? JSON.parse(event.body) : null;
console.log(`${httpMethod} ${path}`);
console.log('Path Parameters:', pathParameters);
console.log('Query Parameters:', queryParameters);
try {
let response;
switch (httpMethod) {
case 'GET':
response = await handleGet(pathParameters, queryParameters);
break;
case 'POST':
response = await handlePost(body, headers);
break;
case 'PUT':
response = await handlePut(pathParameters.id, body);
break;
case 'DELETE':
response = await handleDelete(pathParameters.id);
break;
default:
throw new Error(`Unsupported method: ${httpMethod}`);
}
return createApiResponse(200, response);
} catch (error) {
console.error('API Error:', error);
return createApiResponse(500, { error: error.message });
}
};
function createApiResponse(statusCode, body, headers = {}) {
return {
statusCode,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
...headers
},
body: JSON.stringify(body)
};
}
async function handleGet(pathParams, queryParams) {
if (pathParams.id) {
return { message: `Getting item ${pathParams.id}` };
}
const limit = parseInt(queryParams.limit) || 10;
const offset = parseInt(queryParams.offset) || 0;
return {
items: Array.from({ length: limit }, (_, i) => ({
id: offset + i + 1,
name: `Item ${offset + i + 1}`,
created: new Date().toISOString()
})),
pagination: { limit, offset, total: 1000 }
};
}
async function handlePost(body, headers) {
const userAgent = headers['User-Agent'] || 'Unknown';
const contentType = headers['Content-Type'] || 'application/json';
return {
message: 'Item created successfully',
data: body,
metadata: {
userAgent,
contentType,
createdAt: new Date().toISOString()
}
};
}
データベース統合とデータ処理
// DynamoDB統合のLambda関数
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();
const TABLE_NAME = process.env.TABLE_NAME || 'MyTable';
exports.databaseHandler = async (event, context) => {
try {
// S3イベントの処理例
if (event.Records && event.Records[0].eventSource === 'aws:s3') {
return await processS3Event(event.Records);
}
// SQSメッセージの処理例
if (event.Records && event.Records[0].eventSource === 'aws:sqs') {
return await processSQSMessages(event.Records);
}
// Direct DynamoDB操作
return await processDatabaseOperation(event);
} catch (error) {
console.error('Database error:', error);
throw error;
}
};
async function processS3Event(records) {
const results = [];
for (const record of records) {
const bucket = record.s3.bucket.name;
const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' '));
const eventName = record.eventName;
console.log(`Processing S3 event: ${eventName} for ${bucket}/${key}`);
const item = {
id: `s3-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
type: 'S3_EVENT',
bucket: bucket,
objectKey: key,
eventName: eventName,
timestamp: new Date().toISOString(),
processed: true
};
// DynamoDBに記録
await dynamodb.put({
TableName: TABLE_NAME,
Item: item
}).promise();
results.push(item);
}
return { processed: results.length, items: results };
}
async function processSQSMessages(records) {
const batchResults = [];
for (const record of records) {
try {
const messageBody = JSON.parse(record.body);
const messageId = record.messageId;
console.log(`Processing SQS message: ${messageId}`);
// メッセージの処理とDynamoDBへの保存
const processedItem = await processMessage(messageBody, messageId);
batchResults.push(processedItem);
} catch (error) {
console.error(`Failed to process message ${record.messageId}:`, error);
batchResults.push({ messageId: record.messageId, error: error.message });
}
}
return { batchResults };
}
async function processMessage(messageBody, messageId) {
const item = {
id: messageId,
type: 'SQS_MESSAGE',
data: messageBody,
processedAt: new Date().toISOString(),
status: 'COMPLETED'
};
await dynamodb.put({
TableName: TABLE_NAME,
Item: item
}).promise();
return item;
}
async function processDatabaseOperation(event) {
const operation = event.operation || 'query';
switch (operation) {
case 'query':
return await queryItems(event.queryParams || {});
case 'scan':
return await scanTable(event.scanParams || {});
case 'batchWrite':
return await batchWriteItems(event.items || []);
default:
throw new Error(`Unsupported operation: ${operation}`);
}
}
async function queryItems(params) {
const queryParams = {
TableName: TABLE_NAME,
KeyConditionExpression: params.keyCondition || 'id = :id',
ExpressionAttributeValues: params.attributeValues || { ':id': 'example' },
Limit: params.limit || 10
};
const result = await dynamodb.query(queryParams).promise();
return {
items: result.Items,
count: result.Count,
lastEvaluatedKey: result.LastEvaluatedKey
};
}
認証とセキュリティ
// Cognito JWT認証とLambda Authorizer
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');
const client = jwksClient({
jwksUri: `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.USER_POOL_ID}/.well-known/jwks.json`
});
exports.authorizerHandler = async (event, context) => {
try {
const token = extractToken(event);
const decodedToken = await verifyToken(token);
const principalId = decodedToken.sub;
// 認証成功 - IAMポリシーを生成
const policy = generatePolicy(principalId, 'Allow', event.methodArn, decodedToken);
console.log('Authorization successful for user:', principalId);
return policy;
} catch (error) {
console.error('Authorization failed:', error);
throw new Error('Unauthorized');
}
};
function extractToken(event) {
const authorizationHeader = event.headers?.Authorization || event.headers?.authorization;
if (!authorizationHeader) {
throw new Error('Missing Authorization header');
}
const tokenMatch = authorizationHeader.match(/^Bearer\s+(.+)$/);
if (!tokenMatch) {
throw new Error('Invalid Authorization header format');
}
return tokenMatch[1];
}
async function verifyToken(token) {
const decodedHeader = jwt.decode(token, { complete: true });
if (!decodedHeader || !decodedHeader.header.kid) {
throw new Error('Invalid token header');
}
const signingKey = await getSigningKey(decodedHeader.header.kid);
return jwt.verify(token, signingKey, {
audience: process.env.CLIENT_ID,
issuer: `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.USER_POOL_ID}`,
algorithms: ['RS256']
});
}
function getSigningKey(kid) {
return new Promise((resolve, reject) => {
client.getSigningKey(kid, (err, key) => {
if (err) {
reject(err);
} else {
resolve(key.getPublicKey());
}
});
});
}
function generatePolicy(principalId, effect, resource, decodedToken) {
return {
principalId,
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: effect,
Resource: resource
}
]
},
context: {
userId: principalId,
email: decodedToken.email,
groups: JSON.stringify(decodedToken['cognito:groups'] || []),
tokenExpiry: decodedToken.exp.toString()
}
};
}
// セキュアなLambda関数の実装例
exports.secureHandler = async (event, context) => {
// API Gateway Authorizerからのコンテキスト取得
const userId = event.requestContext?.authorizer?.userId;
const userEmail = event.requestContext?.authorizer?.email;
const userGroups = JSON.parse(event.requestContext?.authorizer?.groups || '[]');
if (!userId) {
return createApiResponse(401, { error: 'Unauthorized' });
}
try {
// リクエストの暗号化検証
const encryptedData = event.body;
const decryptedData = await decryptRequestData(encryptedData);
// ユーザー権限の検証
if (!hasRequiredPermissions(userGroups, 'READ_DATA')) {
return createApiResponse(403, { error: 'Insufficient permissions' });
}
// セキュアなデータ処理
const result = await processSecureData(decryptedData, userId);
// レスポンスの暗号化
const encryptedResponse = await encryptResponseData(result);
return createApiResponse(200, { data: encryptedResponse });
} catch (error) {
console.error('Security error:', error);
return createApiResponse(500, { error: 'Security validation failed' });
}
};
async function decryptRequestData(encryptedData) {
const AWS = require('aws-sdk');
const kms = new AWS.KMS();
const decryptParams = {
CiphertextBlob: Buffer.from(encryptedData, 'base64')
};
const result = await kms.decrypt(decryptParams).promise();
return JSON.parse(result.Plaintext.toString());
}
function hasRequiredPermissions(userGroups, requiredPermission) {
const permissionMap = {
'admin': ['READ_DATA', 'WRITE_DATA', 'DELETE_DATA'],
'editor': ['READ_DATA', 'WRITE_DATA'],
'viewer': ['READ_DATA']
};
return userGroups.some(group =>
permissionMap[group]?.includes(requiredPermission)
);
}
イベント駆動アーキテクチャ
// EventBridge統合のイベント処理
const AWS = require('aws-sdk');
const eventbridge = new AWS.EventBridge();
const sns = new AWS.SNS();
exports.eventDrivenHandler = async (event, context) => {
try {
// カスタムEventBridgeイベントの処理
if (event.source && event['detail-type']) {
return await processCustomEvent(event);
}
// CloudWatch Eventsからのスケジュール実行
if (event.source === 'aws.events') {
return await processScheduledEvent(event);
}
// Step Functions状態変更イベント
if (event.source === 'aws.states') {
return await processStepFunctionEvent(event);
}
return { message: 'Event processed successfully' };
} catch (error) {
console.error('Event processing error:', error);
// エラー通知の送信
await sendErrorNotification(error, event);
throw error;
}
};
async function processCustomEvent(event) {
console.log('Processing custom event:', event['detail-type']);
console.log('Event source:', event.source);
console.log('Event detail:', JSON.stringify(event.detail, null, 2));
const eventType = event['detail-type'];
const eventData = event.detail;
switch (eventType) {
case 'User Registration':
return await handleUserRegistration(eventData);
case 'Order Placed':
return await handleOrderPlaced(eventData);
case 'Payment Processed':
return await handlePaymentProcessed(eventData);
default:
console.log(`Unhandled event type: ${eventType}`);
return { processed: false, reason: 'Unknown event type' };
}
}
async function handleUserRegistration(userData) {
console.log('New user registration:', userData.userId);
// Welcome emailイベントの発行
await publishEvent('user.welcome-email', {
userId: userData.userId,
email: userData.email,
registrationTimestamp: new Date().toISOString()
});
// User profileイベントの発行
await publishEvent('user.profile-setup', {
userId: userData.userId,
defaultSettings: {
notifications: true,
newsletter: false
}
});
return { processed: true, eventType: 'User Registration' };
}
async function handleOrderPlaced(orderData) {
console.log('New order placed:', orderData.orderId);
// Inventory checkイベントの発行
await publishEvent('inventory.check', {
orderId: orderData.orderId,
items: orderData.items,
requestedBy: orderData.customerId
});
// Payment processingイベントの発行
await publishEvent('payment.process', {
orderId: orderData.orderId,
amount: orderData.totalAmount,
customerId: orderData.customerId,
paymentMethod: orderData.paymentMethod
});
return { processed: true, eventType: 'Order Placed' };
}
async function publishEvent(eventType, eventData) {
const params = {
Entries: [
{
Source: 'my-application',
DetailType: eventType,
Detail: JSON.stringify(eventData),
EventBusName: process.env.EVENT_BUS_NAME || 'default'
}
]
};
const result = await eventbridge.putEvents(params).promise();
console.log('Event published:', eventType, result.Entries[0].EventId);
}
async function processScheduledEvent(event) {
console.log('Processing scheduled event');
const ruleName = event.resources[0].split('/').pop();
console.log('Triggered by rule:', ruleName);
switch (ruleName) {
case 'daily-backup':
return await performDailyBackup();
case 'weekly-report':
return await generateWeeklyReport();
case 'monthly-cleanup':
return await performMonthlyCleanup();
default:
console.log(`Unknown scheduled rule: ${ruleName}`);
return { processed: false };
}
}
async function performDailyBackup() {
console.log('Performing daily backup...');
// データベースバックアップの実行
const backupResult = await createDatabaseBackup();
// バックアップ完了通知
await publishEvent('backup.completed', {
backupId: backupResult.backupId,
timestamp: new Date().toISOString(),
status: 'success'
});
return {
processed: true,
action: 'daily-backup',
backupId: backupResult.backupId
};
}
async function createDatabaseBackup() {
// 実際のバックアップロジックを実装
const backupId = `backup-${Date.now()}`;
console.log('Creating backup:', backupId);
// バックアップ処理をシミュレート
return { backupId, status: 'completed' };
}
async function sendErrorNotification(error, originalEvent) {
const message = {
error: error.message,
stack: error.stack,
originalEvent: originalEvent,
timestamp: new Date().toISOString(),
functionName: process.env.AWS_LAMBDA_FUNCTION_NAME
};
const params = {
TopicArn: process.env.ERROR_NOTIFICATION_TOPIC_ARN,
Subject: 'Lambda Function Error Alert',
Message: JSON.stringify(message, null, 2)
};
if (process.env.ERROR_NOTIFICATION_TOPIC_ARN) {
await sns.publish(params).promise();
console.log('Error notification sent');
}
}
監視とパフォーマンス最適化
// CloudWatch Metrics & X-Ray統合の監視機能
const AWS = require('aws-sdk');
const AWSXRay = require('aws-xray-sdk-core');
const aws = AWSXRay.captureAWS(AWS);
const cloudwatch = new aws.CloudWatch();
exports.monitoringHandler = async (event, context) => {
const segment = AWSXRay.getSegment();
const subsegment = segment.addNewSubsegment('business-logic');
try {
// カスタムメトリクスの記録
await recordCustomMetrics('FunctionInvocation', 1);
// パフォーマンス測定の開始
const startTime = Date.now();
// メイン処理の実行
const result = await performBusinessLogic(event);
// 処理時間の記録
const executionTime = Date.now() - startTime;
await recordCustomMetrics('ExecutionTime', executionTime, 'Milliseconds');
// 成功メトリクスの記録
await recordCustomMetrics('SuccessfulExecution', 1);
// X-Rayアノテーションの追加
subsegment.addAnnotation('executionTime', executionTime);
subsegment.addAnnotation('resultCount', result.items?.length || 0);
subsegment.addMetadata('result', result);
subsegment.close();
return {
statusCode: 200,
body: JSON.stringify({
result,
metrics: {
executionTime,
timestamp: new Date().toISOString()
}
})
};
} catch (error) {
// エラーメトリクスの記録
await recordCustomMetrics('ErrorCount', 1);
await recordCustomMetrics('ErrorRate', 1);
// X-Rayエラー情報の追加
subsegment.addError(error);
subsegment.close(error);
console.error('Function error:', error);
throw error;
}
};
async function recordCustomMetrics(metricName, value, unit = 'Count') {
const params = {
Namespace: 'MyApplication/Lambda',
MetricData: [
{
MetricName: metricName,
Value: value,
Unit: unit,
Timestamp: new Date(),
Dimensions: [
{
Name: 'FunctionName',
Value: process.env.AWS_LAMBDA_FUNCTION_NAME
},
{
Name: 'Environment',
Value: process.env.ENVIRONMENT || 'production'
}
]
}
]
};
try {
await cloudwatch.putMetricData(params).promise();
} catch (error) {
console.error('Failed to record metric:', error);
}
}
async function performBusinessLogic(event) {
// X-Rayサブセグメントでの詳細トレーシング
const subsegment = AWSXRay.getSegment().addNewSubsegment('data-processing');
try {
// データベースアクセスのトレーシング
const dbSubsegment = subsegment.addNewSubsegment('database-query');
const dbResults = await queryDatabase(event.query);
dbSubsegment.addMetadata('queryResult', { count: dbResults.length });
dbSubsegment.close();
// 外部API呼び出しのトレーシング
const apiSubsegment = subsegment.addNewSubsegment('external-api');
const apiResults = await callExternalAPI(event.apiParams);
apiSubsegment.addMetadata('apiResponse', apiResults);
apiSubsegment.close();
// データ処理のトレーシング
const processSubsegment = subsegment.addNewSubsegment('data-transformation');
const processedData = await processData(dbResults, apiResults);
processSubsegment.addMetadata('processedItems', processedData.length);
processSubsegment.close();
subsegment.close();
return {
items: processedData,
summary: {
dbResultCount: dbResults.length,
apiResultCount: apiResults.length,
processedCount: processedData.length
}
};
} catch (error) {
subsegment.addError(error);
subsegment.close(error);
throw error;
}
}
// パフォーマンス最適化の実装例
exports.optimizedHandler = async (event, context) => {
// プロビジョニング済み同時実行での一貫性確保
console.log('Function version:', context.functionVersion);
console.log('Allocated memory:', context.memoryLimitInMB);
// Lambda Layersからの依存関係使用
const sharedUtils = require('/opt/nodejs/shared-utils');
// 接続プールの再利用(コンテナの再利用時)
if (!global.dbConnectionPool) {
global.dbConnectionPool = await createDatabasePool();
console.log('Database connection pool created');
}
// 環境変数キャッシュの活用
const config = {
tableName: process.env.TABLE_NAME,
region: process.env.AWS_REGION,
maxRetries: parseInt(process.env.MAX_RETRIES) || 3
};
try {
// 非同期処理の並列実行による最適化
const [userData, configData, metricsData] = await Promise.all([
fetchUserData(event.userId),
fetchConfiguration(config.tableName),
fetchMetrics(event.timeRange)
]);
// CPUバウンドな処理の最適化
const processedResult = await optimizedDataProcessing(userData, configData);
// メモリ使用量の監視
const memoryUsage = process.memoryUsage();
console.log('Memory usage:', {
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024) + ' MB',
heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024) + ' MB'
});
return {
statusCode: 200,
body: JSON.stringify({
result: processedResult,
performance: {
memoryUsage: memoryUsage,
timestamp: new Date().toISOString()
}
})
};
} catch (error) {
console.error('Optimized handler error:', error);
throw error;
}
};
async function createDatabasePool() {
// データベース接続プールの作成(コンテナレベルでの再利用)
const pool = {
connections: new Map(),
maxConnections: 10,
created: new Date().toISOString()
};
console.log('Database pool initialized');
return pool;
}
async function optimizedDataProcessing(userData, configData) {
// ストリーミング処理による大量データの効率的処理
const results = [];
const batchSize = 100;
for (let i = 0; i < userData.length; i += batchSize) {
const batch = userData.slice(i, i + batchSize);
const batchResults = await processBatch(batch, configData);
results.push(...batchResults);
// ガベージコレクションの促進
if (i % 500 === 0) {
global.gc && global.gc();
}
}
return results;
}
async function processBatch(batch, config) {
return batch.map(item => ({
id: item.id,
processed: true,
timestamp: new Date().toISOString(),
config: config.version
}));
}
デプロイメントと本番運用
# SAM Template (template.yaml)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'AWS Lambda サーバーレスアプリケーション'
Globals:
Function:
Timeout: 30
MemorySize: 1024
Runtime: nodejs18.x
Environment:
Variables:
ENVIRONMENT: !Ref Environment
LOG_LEVEL: !Ref LogLevel
Parameters:
Environment:
Type: String
Default: dev
AllowedValues: [dev, staging, prod]
LogLevel:
Type: String
Default: INFO
AllowedValues: [DEBUG, INFO, WARN, ERROR]
Resources:
# Lambda関数の定義
MyLambdaFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub 'my-lambda-${Environment}'
CodeUri: src/
Handler: index.handler
Runtime: nodejs18.x
MemorySize: 1024
Timeout: 30
ReservedConcurrencyLimit: 100
ProvisionedConcurrencyConfig:
ProvisionedConcurrencyScaling:
ProvisionedConcurrencyManagement: Manual
ProvisionedConcurrencyCount: 10
Environment:
Variables:
TABLE_NAME: !Ref DynamoDBTable
BUCKET_NAME: !Ref S3Bucket
Events:
ApiEvent:
Type: Api
Properties:
Path: /api/{proxy+}
Method: any
RestApiId: !Ref MyApi
ScheduleEvent:
Type: Schedule
Properties:
Schedule: 'rate(5 minutes)'
Input: '{"source": "scheduled"}'
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref DynamoDBTable
- S3ReadPolicy:
BucketName: !Ref S3Bucket
- CloudWatchPutMetricPolicy: {}
# API Gateway
MyApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub 'my-api-${Environment}'
StageName: !Ref Environment
TracingEnabled: true
Cors:
AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
AllowOrigin: "'*'"
Auth:
DefaultAuthorizer: CognitoAuthorizer
Authorizers:
CognitoAuthorizer:
UserPoolArn: !GetAtt CognitoUserPool.Arn
# DynamoDB Table
DynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub 'my-table-${Environment}'
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
# S3 Bucket
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub 'my-bucket-${Environment}-${AWS::AccountId}'
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# Cognito User Pool
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: !Sub 'my-pool-${Environment}'
AutoVerifiedAttributes:
- email
Policies:
PasswordPolicy:
MinimumLength: 8
RequireUppercase: true
RequireLowercase: true
RequireNumbers: true
RequireSymbols: true
Outputs:
ApiEndpoint:
Description: 'API Gateway endpoint URL'
Value: !Sub 'https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/${Environment}'
FunctionName:
Description: 'Lambda Function Name'
Value: !Ref MyLambdaFunction
TableName:
Description: 'DynamoDB Table Name'
Value: !Ref DynamoDBTable
#!/bin/bash
# deploy.sh - デプロイメントスクリプト
set -e
ENVIRONMENT=${1:-dev}
REGION=${2:-us-east-1}
STACK_NAME="my-lambda-app-${ENVIRONMENT}"
echo "Deploying to environment: ${ENVIRONMENT}"
echo "Region: ${REGION}"
echo "Stack name: ${STACK_NAME}"
# SAMビルド
echo "Building SAM application..."
sam build --use-container
# SAMデプロイ
echo "Deploying SAM application..."
sam deploy \
--stack-name ${STACK_NAME} \
--region ${REGION} \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
Environment=${ENVIRONMENT} \
LogLevel=INFO \
--confirm-changeset \
--resolve-s3
# CloudFormationスタックの出力を取得
echo "Getting stack outputs..."
aws cloudformation describe-stacks \
--stack-name ${STACK_NAME} \
--region ${REGION} \
--query 'Stacks[0].Outputs'
# 関数の動作確認
echo "Testing deployed function..."
FUNCTION_NAME=$(aws cloudformation describe-stacks \
--stack-name ${STACK_NAME} \
--region ${REGION} \
--query 'Stacks[0].Outputs[?OutputKey==`FunctionName`].OutputValue' \
--output text)
aws lambda invoke \
--function-name ${FUNCTION_NAME} \
--region ${REGION} \
--payload '{"test": true}' \
response.json
echo "Deployment completed successfully!"
echo "Function response:"
cat response.json
# monitoring.sh - 監視とログ確認
#!/bin/bash
FUNCTION_NAME=${1:-my-lambda-function}
ENVIRONMENT=${2:-dev}
echo "Monitoring Lambda function: ${FUNCTION_NAME}"
# CloudWatch Logsの確認
echo "Fetching recent logs..."
aws logs describe-log-groups \
--log-group-name-prefix "/aws/lambda/${FUNCTION_NAME}" \
--query 'logGroups[0].logGroupName' \
--output text | \
xargs -I {} aws logs tail {} --follow
# CloudWatch Metricsの確認
echo "Fetching metrics..."
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Duration \
--dimensions Name=FunctionName,Value=${FUNCTION_NAME} \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Average,Maximum
# 関数の設定確認
echo "Function configuration:"
aws lambda get-function-configuration \
--function-name ${FUNCTION_NAME} \
--query '{
Runtime: Runtime,
MemorySize: MemorySize,
Timeout: Timeout,
LastModified: LastModified,
Version: Version
}'
echo "Monitoring complete!"