Elysia Tools
Navigation mobile
Cloud Architecture
Exemples d'Architecture Serverless
Exemples de calcul serverless avec AWS Lambda, Azure Functions et Google Cloud Functions
Exemples
Entrées de cette collection
AWS Lambda Hello World
Fonction AWS Lambda de base avec runtime Node.js
Difficulté
3/10
Temps estimé
10 min
Étiquettes
serverless, aws, lambda, nodejs
Prérequis
Basic Node.js knowledge
// AWS Lambda Hello World Example
exports.handler = async (event) => {
console.log('Event: ', JSON.stringify(event, null, 2));
const response = {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
message: 'Hello from AWS Lambda!',
input: event,
timestamp: new Date().toISOString(),
}),
};
return response;
};
// Handler with different HTTP methods
exports.apiHandler = async (event) => {
const httpMethod = event.httpMethod;
const path = event.path;
switch (httpMethod) {
case 'GET':
return {
statusCode: 200,
body: JSON.stringify({
message: 'GET request received',
path: path,
}),
};
case 'POST':
const requestBody = JSON.parse(event.body);
return {
statusCode: 201,
body: JSON.stringify({
message: 'POST request processed',
receivedData: requestBody,
}),
};
default:
return {
statusCode: 405,
body: JSON.stringify({
error: 'Method not allowed',
}),
};
}
};
// Lambda function with environment variables
exports.envHandler = async (event) => {
const environment = process.env.ENVIRONMENT || 'development';
const region = process.env.AWS_REGION || 'us-east-1';
return {
statusCode: 200,
body: JSON.stringify({
environment,
region,
allEnvVars: Object.keys(process.env).filter(key =>
key.startsWith('AWS_') || key.startsWith('LAMBDA_')
),
}),
};
};Configuration Serverless Framework
Configuration Serverless Framework pour déployer plusieurs fonctions
Difficulté
6/10
Temps estimé
20 min
Étiquettes
serverless, configuration, deployment, aws
Prérequis
AWS account, Serverless Framework CLI
# serverless.yml
service: my-serverless-app
frameworkVersion: '3'
provider:
name: aws
runtime: nodejs18.x
region: us-east-1
stage: dev
environment:
NODE_ENV: ${self:custom.currentStage}
TABLE_NAME: ${self:service}-${self:custom.currentStage}
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- "arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.TABLE_NAME}"
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
cors: true
users:
handler: handler.users
events:
- http:
path: users
method: get
cors: true
- http:
path: users
method: post
cors: true
getUser:
handler: handler.getUser
events:
- http:
path: users/{id}
method: get
cors: true
processImage:
handler: handler.processImage
events:
- s3:
bucket: my-image-bucket
event: s3:ObjectCreated:*
existing: true
timeout: 30
memorySize: 1024
scheduledTask:
handler: handler.scheduledTask
events:
- schedule:
rate: rate(5 minutes)
enabled: true
resources:
Resources:
UsersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:provider.environment.TABLE_NAME}
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
SSESpecification:
SSEEnabled: true
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
plugins:
- serverless-offline
- serverless-dotenv-plugin
- serverless-webpack
custom:
currentStage: ${opt:stage, 'dev'}
webpack:
webpackConfig: 'webpack.config.js'
includeModules: true
serverless-offline:
httpPort: 3000
babelOptions:
presets: ["env"]
dotenv:
path: ./.env
include:
- API_KEY
- DATABASE_URL
package:
individually: true
exclude:
- .git/**
- .vscode/**
- node_modules/**
- "*.log"Azure Functions avec C#
Exemples Azure Functions utilisant C# et .NET
Difficulté
7/10
Temps estimé
25 min
Étiquettes
serverless, azure, csharp, dotnet, functions
Prérequis
C# and .NET knowledge, Azure subscription
// Azure Functions with C#
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace MyServerlessApp
{
public static class HttpFunctions
{
[FunctionName("HelloWorld")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
public static class QueueFunctions
{
[FunctionName("ProcessQueueMessage")]
public static void Run(
[QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string myQueueItem,
ILogger log)
{
log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
// Process the queue message
var message = JsonConvert.DeserializeObject<MessageData>(myQueueItem);
// Business logic here
log.LogInformation($"Processing message for user: {message.UserId}");
}
}
public static class TimerFunctions
{
[FunctionName("DailyCleanup")]
public static void Run(
[TimerTrigger("0 0 3 * * *")] TimerInfo myTimer,
ILogger log)
{
log.LogInformation($"Daily cleanup function executed at: {DateTime.Now}");
if (myTimer.IsPastDue)
{
log.LogInformation("Timer is running late!");
}
// Cleanup logic here
PerformDailyCleanup();
}
private static void PerformDailyCleanup()
{
// Implement cleanup logic
// e.g., delete old files, clean up database, etc.
}
}
public static class BlobFunctions
{
[FunctionName("ProcessImageUpload")]
public static void Run(
[BlobTrigger("images/{name}", Connection = "AzureWebJobsStorage")] Stream myBlob,
string name,
ILogger log)
{
log.LogInformation($"C# Blob trigger function processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
// Process uploaded image
ProcessImage(myBlob, name);
}
private static void ProcessImage(Stream imageStream, string fileName)
{
// Implement image processing logic
// e.g., resize, add watermark, generate thumbnails
}
}
public static class CosmosDBFunctions
{
[FunctionName("CreateUser")]
public static async Task<IActionResult> CreateUser(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "users")] HttpRequest req,
[CosmosDB(
databaseName: "MyDatabase",
collectionName: "Users",
ConnectionStringSetting = "CosmosDBConnection")] IAsyncCollector<User> usersOut,
ILogger log)
{
log.LogInformation("Creating a new user");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var user = JsonConvert.DeserializeObject<User>(requestBody);
user.Id = Guid.NewGuid().ToString();
user.CreatedAt = DateTime.UtcNow;
await usersOut.AddAsync(user);
return new CreatedResult($"/users/{user.Id}", user);
}
[FunctionName("GetUser")]
public static IActionResult GetUser(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "users/{id}")] HttpRequest req,
[CosmosDB(
databaseName: "MyDatabase",
collectionName: "Users",
Id = "{id}",
PartitionKey = "{id}",
ConnectionStringSetting = "CosmosDBConnection")] User user,
ILogger log)
{
log.LogInformation($"Getting user with id: {req.RouteValues["id"]}");
if (user == null)
{
return new NotFoundResult();
}
return new OkObjectResult(user);
}
}
// Data models
public class MessageData
{
public string UserId { get; set; }
public string Message { get; set; }
public DateTime Timestamp { get; set; }
}
public class User
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("createdAt")]
public DateTime CreatedAt { get; set; }
}
}Google Cloud Functions avec Python
Exemples Google Cloud Functions utilisant runtime Python
Difficulté
7/10
Temps estimé
25 min
Étiquettes
serverless, gcp, python, cloud functions
Prérequis
Python knowledge, Google Cloud Platform account
# Google Cloud Functions with Python
import functions_framework
from flask import jsonify, request
import json
import logging
import os
from datetime import datetime
from google.cloud import storage
from google.cloud import datastore
# Configure logging
logging.basicConfig(level=logging.INFO)
@functions_framework.http
def hello_world(request):
"""HTTP Cloud Function that returns a JSON greeting."""
request_json = request.get_json(silent=True)
request_args = request.args
if request_json and 'name' in request_json:
name = request_json['name']
elif request_args and 'name' in request_args:
name = request_args['name']
else:
name = 'World'
response_data = {
'message': f'Hello, {name}!',
'timestamp': datetime.utcnow().isoformat(),
'method': request.method,
'headers': dict(request.headers)
}
return jsonify(response_data), 200
@functions_framework.http
def process_data(request):
"""HTTP Cloud Function that processes incoming data."""
if request.method != 'POST':
return jsonify({'error': 'Method not allowed'}), 405
try:
data = request.get_json()
if not data:
return jsonify({'error': 'No data provided'}), 400
# Validate required fields
if 'user_id' not in data or 'event_type' not in data:
return jsonify({'error': 'Missing required fields'}), 400
# Process the data
processed_data = {
'user_id': data['user_id'],
'event_type': data['event_type'],
'processed_at': datetime.utcnow().isoformat(),
'metadata': {
'source_ip': request.remote_addr,
'user_agent': request.headers.get('User-Agent', ''),
}
}
# Add additional processing logic here
if data.get('payload'):
processed_data['payload_size'] = len(json.dumps(data['payload']))
# Save to Datastore (optional)
save_to_datastore(processed_data)
return jsonify({
'status': 'success',
'processed_data': processed_data
}), 200
except Exception as e:
logging.error(f"Error processing data: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
@functions_framework.cloud_event
def process_pubsub_message(cloud_event):
"""Background Cloud Function to handle Pub/Sub messages."""
try:
# Extract message data
message_data = cloud_event.data.get('message', {})
if 'data' in message_data:
# Decode base64 message
import base64
decoded_message = base64.b64decode(message_data['data']).decode('utf-8')
message_json = json.loads(decoded_message)
else:
message_json = message_data
logging.info(f"Received Pub/Sub message: {message_json}")
# Process the message
result = process_message(message_json)
logging.info(f"Message processed successfully: {result}")
except Exception as e:
logging.error(f"Error processing Pub/Sub message: {str(e)}")
raise
@functions_framework.cloud_event
def process_gcs_event(cloud_event):
"""Background Cloud Function to handle GCS object changes."""
try:
# Extract bucket and file information
bucket = cloud_event.data.get('bucket')
name = cloud_event.data.get('name')
generation = cloud_event.data.get('generation')
eventType = cloud_event.type
logging.info(f"GCS Event: {eventType} for gs://{bucket}/{name} (generation: {generation})")
if eventType == 'google.storage.object.finalize':
# Process new file
process_uploaded_file(bucket, name)
elif eventType == 'google.storage.object.delete':
# Handle file deletion
logging.info(f"File deleted: gs://{bucket}/{name}")
except Exception as e:
logging.error(f"Error processing GCS event: {str(e)}")
raise
def save_to_datastore(data):
"""Save data to Google Cloud Datastore."""
try:
client = datastore.Client()
kind = 'ProcessedEvent'
# Create a new entity
key = client.key(kind)
entity = datastore.Entity(key=key)
# Set entity properties
entity.update(data)
# Save the entity
client.put(entity)
logging.info(f"Data saved to Datastore with key: {entity.key}")
except Exception as e:
logging.error(f"Error saving to Datastore: {str(e)}")
def process_message(message):
"""Process incoming Pub/Sub message."""
# Add your business logic here
return {
'processed': True,
'message_type': message.get('type', 'unknown'),
'timestamp': datetime.utcnow().isoformat()
}
def process_uploaded_file(bucket_name, file_name):
"""Process uploaded file in GCS."""
try:
client = storage.Client()
bucket = client.bucket(bucket_name)
blob = bucket.blob(file_name)
# Get file metadata
blob.reload()
file_size = blob.size
content_type = blob.content_type
logging.info(f"Processing file: {file_name} ({file_size} bytes, {content_type})")
# Add file processing logic here
if content_type and content_type.startswith('image/'):
# Process image
process_image_file(bucket_name, file_name)
elif content_type and 'csv' in content_type:
# Process CSV file
process_csv_file(bucket_name, file_name)
except Exception as e:
logging.error(f"Error processing uploaded file: {str(e)}")
def process_image_file(bucket_name, file_name):
"""Process uploaded image file."""
# Add image processing logic
logging.info(f"Processing image: {file_name}")
# e.g., resize, add watermark, generate thumbnails
def process_csv_file(bucket_name, file_name):
"""Process uploaded CSV file."""
# Add CSV processing logic
logging.info(f"Processing CSV: {file_name}")
# e.g., parse data, save to database
# Environment configuration helper
def get_config():
"""Get configuration from environment variables."""
return {
'project_id': os.getenv('GCP_PROJECT'),
'environment': os.getenv('ENVIRONMENT', 'development'),
'log_level': os.getenv('LOG_LEVEL', 'INFO')
}Intégration API Gateway Serverless
Configuration API Gateway pour les fonctions serverless
Difficulté
9/10
Temps estimé
35 min
Étiquettes
serverless, api gateway, cloudformation, sam
Prérequis
AWS CloudFormation knowledge, API Gateway concepts
# AWS API Gateway with Lambda Integration
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Serverless API with API Gateway
Globals:
Function:
Timeout: 30
MemorySize: 256
Runtime: python3.9
Parameters:
Stage:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- prod
Description: Deployment stage
Resources:
# API Gateway REST API
ApiGatewayRestApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub '${AWS::StackName}-api-${Stage}'
StageName: !Ref Stage
DefinitionUri: s3://api-definition-bucket/openapi.yaml
Variables:
LambdaFunctionName: !Ref MyApiFunction
Cors:
AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
AllowOrigin: "'*'"
# Lambda Functions
MyApiFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub '${AWS::StackName}-api-${Stage}'
CodeUri: src/
Handler: app.lambda_handler
Runtime: python3.9
Environment:
Variables:
TABLE_NAME: !Ref DataTable
REGION: !Ref AWS::Region
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref DataTable
Events:
ApiEvents:
Type: Api
Properties:
RestApiId: !Ref ApiGatewayRestApi
Path: /{proxy+}
Method: ANY
# DynamoDB Table
DataTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub '${AWS::StackName}-data-${Stage}'
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: type
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
- AttributeName: type
KeyType: RANGE
BillingMode: PAY_PER_REQUEST
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
# Lambda Authorizer
ApiAuthorizer:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub '${AWS::StackName}-authorizer-${Stage}'
CodeUri: authorizer/
Handler: authorizer.lambda_handler
Runtime: python3.9
Environment:
Variables:
JWT_SECRET: !Ref JwtSecret
Policies:
- Statement:
Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${JwtSecret}*
# Custom Domain
ApiDomainName:
Type: AWS::ApiGateway::DomainName
Properties:
DomainName: !Sub 'api-${Stage}.example.com'
EndpointConfiguration:
Types:
- REGIONAL
RegionalCertificateArn: !Ref SslCertificate
SecurityPolicy: TLS_1_2
# API Gateway Base Path Mapping
BasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
DomainName: !Ref ApiDomainName
RestApiId: !Ref ApiGatewayRestApi
Stage: !Ref Stage
# CloudWatch Log Group
ApiLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/aws/lambda/${MyApiFunction}'
RetentionInDays: 30
# Output values
Outputs:
ApiEndpoint:
Description: API Gateway endpoint URL
Value: !Sub 'https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/${Stage}'
ApiFunction:
Description: Lambda function ARN
Value: !GetAtt MyApiFunction.Arn
TableName:
Description: DynamoDB table name
Value: !Ref DataTable
# OpenAPI Specification for API Gateway
# openapi.yaml
openapi: 3.0.0
info:
title: Serverless API
version: 1.0.0
description: Serverless API with Lambda backend
servers:
- url: https://{domain}/prod
variables:
domain:
default: api.example.com
paths:
/health:
get:
summary: Health check endpoint
responses:
'200':
description: API is healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
timestamp:
type: string
/users:
get:
summary: Get all users
security:
- ApiKeyAuth: []
responses:
'200':
description: List of users
post:
summary: Create new user
security:
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/User'
responses:
'201':
description: User created
'400':
description: Invalid input
/users/{userId}:
get:
summary: Get user by ID
security:
- ApiKeyAuth: []
parameters:
- name: userId
in: path
required: true
schema:
type: string
responses:
'200':
description: User details
'404':
description: User not found
put:
summary: Update user
security:
- ApiKeyAuth: []
parameters:
- name: userId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/User'
responses:
'200':
description: User updated
'404':
description: User not found
delete:
summary: Delete user
security:
- ApiKeyAuth: []
parameters:
- name: userId
in: path
required: true
schema:
type: string
responses:
'204':
description: User deleted
'404':
description: User not found
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
User:
type: object
required:
- name
- email
properties:
id:
type: string
readOnly: true
name:
type: string
email:
type: string
format: email
role:
type: string
enum: [user, admin]
default: userOutils
Outils souvent utilisés avec cet exemple
Associé