Operational Serverless
Vicenç García Altés
@vgaltes
info@vgaltes.com
https://vgaltes.com
What's serverless?
Title Text
BIASES
MORE BIASES
The three ways
- Principles of flow
- Principles of feedback
- Principles of continuous learning and investigation
TECHNICAL PRACTICES OF FLOW
FAST AND RELIABLE TESTING
ENABLE AND PRACTICE CONTINUOUS INTEGRATION
CREATE THE FOUNDATIONS OF OUR DEPLOYMENT PIPELINE
FOUNDATIONS OF THE DEPLOYMENT PIPELINE
- Enable on-demand creation of Dev, Test and Prod environments.
- Create our single repository of truth for the entire system.
- Make our infrastructure easier to rebuild than to repair.
- Modify our definition of development done to include running in production-like environments.
CLOUDFORMATION
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application",
"Resources": {
"ServerlessDeploymentBucket": {
"Type": "AWS::S3::Bucket"
},
"ServiceDashaLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-a"
}
},
"ServiceDashbLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-b"
}
},
"ServiceDashcLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-c"
}
},
"ServiceDashreadDashsnsLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-read-sns"
}
},
"ServiceDashreadDashdynamoLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-read-dynamo"
}
},
"ServiceDashreadDashs3LogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-read-s3"
}
},
"TimeoutLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-timeout"
}
},
"ErrorLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-error"
}
},
"SnsLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-sns"
}
},
"IamRoleLambdaExecution": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Policies": [
{
"PolicyName": {
"Fn::Join": [
"-",
[
"dev",
"serverless-observability",
"lambda"
]
]
},
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream"
],
"Resource": [
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-a:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-b:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-c:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-sns:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-dynamo:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-s3:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-timeout:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-error:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-sns:*"
}
]
},
{
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": [
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-a:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-b:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-c:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-sns:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-dynamo:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-s3:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-timeout:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-error:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-sns:*:*"
}
]
},
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:DescribeStream",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:ListStreams"
],
"Resource": [
{
"Fn::Sub": "arn:aws:dynamodb:${AWS::Region}:*:table/serverless-observability-dev"
}
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject*",
"s3:PutObject*",
"s3:ListBucket*",
"s3:PutBucketNotification"
],
"Resource": [
{
"Fn::Sub": "arn:aws:s3:::serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
},
{
"Fn::Sub": "arn:aws:s3:::serverless-observability-dev-${AWS::Region}-${AWS::AccountId}/*"
}
]
},
{
"Effect": "Allow",
"Action": [
"sns:Publish",
"sns:Subscribe"
],
"Resource": [
{
"Fn::Sub": "arn:aws:sns:${AWS::Region}:*:serverless-observability-dev"
}
]
},
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": [
{
"Fn::Sub": "arn:aws:lambda:${AWS::Region}:*:function:serverless-observability-dev-*"
}
]
},
{
"Effect": "Allow",
"Action": [
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:DescribeStream",
"dynamodb:ListStreams"
],
"Resource": [
{
"Fn::GetAtt": [
"DynamoDB",
"StreamArn"
]
}
]
}
]
}
}
],
"Path": "/",
"RoleName": {
"Fn::Join": [
"-",
[
"serverless-observability",
"dev",
{
"Fn::Sub": "${AWS::Region}"
},
"lambdaRole"
]
]
}
}
},
"ServiceDashaLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-a",
"Handler": "functions/service-a.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 10,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab",
"BUCKET_NAME": {
"Fn::Sub": "serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
}
}
}
},
"DependsOn": [
"ServiceDashaLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashbLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-b",
"Handler": "functions/service-b.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashbLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashcLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-c",
"Handler": "functions/service-c.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashcLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashreadDashsnsLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-read-sns",
"Handler": "functions/service-read-sns.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashreadDashsnsLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashreadDashdynamoLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-read-dynamo",
"Handler": "functions/service-read-dynamo.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashreadDashdynamoLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashreadDashs3LambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-read-s3",
"Handler": "functions/service-read-s3.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashreadDashs3LogGroup",
"IamRoleLambdaExecution"
]
},
"TimeoutLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-timeout",
"Handler": "functions/timeout.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 1,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"TimeoutLogGroup",
"IamRoleLambdaExecution"
]
},
"ErrorLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-error",
"Handler": "functions/error.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ErrorLogGroup",
"IamRoleLambdaExecution"
]
},
"SnsLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-sns",
"Handler": "functions/sns.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"SnsLogGroup",
"IamRoleLambdaExecution"
]
},
"S3BucketServerlessobservabilitydevAWSRegionAWSAccountId": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": {
"Fn::Sub": "serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
},
"NotificationConfiguration": {
"LambdaConfigurations": [
{
"Event": "s3:ObjectCreated:*",
"Function": {
"Fn::GetAtt": [
"ServiceDashreadDashs3LambdaFunction",
"Arn"
]
}
}
]
}
},
"DependsOn": [
"ServiceDashreadDashs3LambdaPermissionServerlessobservabilitydevAWSRegionAWSAccountIdS3"
]
},
"ServiceDashreadDashs3LambdaPermissionServerlessobservabilitydevAWSRegionAWSAccountIdS3": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashreadDashs3LambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"s3.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
{
"Fn::Sub": ":s3:::serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
}
]
]
}
}
},
"ApiGatewayRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "dev-serverless-observability",
"EndpointConfiguration": {
"Types": [
"EDGE"
]
}
}
},
"ApiGatewayResourceDemo": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"ApiGatewayRestApi",
"RootResourceId"
]
},
"PathPart": "demo",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoServiceDasha": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "service-a",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoServiceDashb": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "service-b",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoTimeout": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "timeout",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoError": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "error",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayMethodDemoServiceDashaGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {
"method.request.querystring.n": true
},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoServiceDasha"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"ServiceDashaLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayMethodDemoServiceDashbGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoServiceDashb"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"ServiceDashbLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayMethodDemoTimeoutGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoTimeout"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"TimeoutLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayMethodDemoErrorGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoError"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"ErrorLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayDeployment1536766421374": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"StageName": "dev"
},
"DependsOn": [
"ApiGatewayMethodDemoServiceDashaGet",
"ApiGatewayMethodDemoServiceDashbGet",
"ApiGatewayMethodDemoTimeoutGet",
"ApiGatewayMethodDemoErrorGet"
]
},
"ServiceDashaLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashaLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"ServiceDashbLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashbLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"TimeoutLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"TimeoutLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"ErrorLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ErrorLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"SNSTopicServerlessobservabilitydev": {
"Type": "AWS::SNS::Topic",
"Properties": {
"TopicName": "serverless-observability-dev",
"DisplayName": "serverless-observability-dev",
"Subscription": [
{
"Endpoint": {
"Fn::GetAtt": [
"ServiceDashreadDashsnsLambdaFunction",
"Arn"
]
},
"Protocol": "lambda"
},
{
"Endpoint": {
"Fn::GetAtt": [
"SnsLambdaFunction",
"Arn"
]
},
"Protocol": "lambda"
}
]
}
},
"ServiceDashreadDashsnsLambdaPermissionServerlessobservabilitydevSNS": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashreadDashsnsLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"sns.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":sns:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
"serverless-observability-dev"
]
]
}
}
},
"SnsLambdaPermissionServerlessobservabilitydevSNS": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"SnsLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"sns.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":sns:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
"serverless-observability-dev"
]
]
}
}
},
"ServiceDashreadDashdynamoEventSourceMappingDynamodbDynamoDB": {
"Type": "AWS::Lambda::EventSourceMapping",
"DependsOn": "IamRoleLambdaExecution",
"Properties": {
"BatchSize": 10,
"EventSourceArn": {
"Fn::GetAtt": [
"DynamoDB",
"StreamArn"
]
},
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashreadDashdynamoLambdaFunction",
"Arn"
]
},
"StartingPosition": "TRIM_HORIZON",
"Enabled": "True"
}
},
"DynamoDB": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "serverless-observability-dev",
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 1,
"WriteCapacityUnits": 1
},
"StreamSpecification": {
"StreamViewType": "NEW_AND_OLD_IMAGES"
}
}
}
},
"Outputs": {
"ServerlessDeploymentBucketName": {
"Value": {
"Ref": "ServerlessDeploymentBucket"
}
},
"ServiceEndpoint": {
"Description": "URL of the service endpoint",
"Value": {
"Fn::Join": [
"",
[
"https://",
{
"Ref": "ApiGatewayRestApi"
},
{
"Fn::Sub": ".execute-api.${AWS::Region}."
},
{
"Ref": "AWS::URLSuffix"
},
"/dev"
]
]
}
}
}
}
Terraform
data "aws_iam_role" "role" {
name = "example-role"
}
resource "aws_api_gateway_rest_api" "api" {
name = "example-api"
}
resource "aws_api_gateway_resource" "resource" {
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
parent_id = "${aws_api_gateway_rest_api.api.root_resource_id}"
path_part = "example-resource"
}
resource "aws_lambda_function" "function" {
filename = "example-zip-file-name.zip"
function_name = "example-function-name"
role = "${aws_iam_role.role.arn}"
handler = "src/example-file-name.handler"
source_code_hash = "${base64sha256(file("example-zip-file-name.zip"))}"
runtime = "nodejs6.10"
environment {
variables {
some_variable = "some_value"
}
}
}
module "serverless" {
source = "salte-io/serverless/aws"
version = "1.0.0"
api_id = "${aws_api_gateway_rest_api.api.id}"
resource_id = "${aws_api_gateway_resource.resource.id}"
http_method = "GET"
function_name = "${aws_lambda_function.function.function_name}"
invoke_arn = "${aws_lambda_function.function.invoke_arn}"
}
AWS SERVERless application model
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: 'SAM template for Serverless framework service: '
Resources:
DynamoDB:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: serverless-observability-dev
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
ServiceA:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-a.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 10
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
BUCKET_NAME: 'serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}'
Events:
Event1:
Type: Api
Properties:
Path: /demo/service-a
Method: get
RestApiId:
Ref: ServerlessObservability
ServerlessObservability:
Type: 'AWS::Serverless::Api'
Properties:
StageName: dev
DefinitionBody:
swagger: '2.0'
info:
title:
Ref: 'AWS::StackName'
paths:
/demo/service-a:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ServiceA.Arn}/invocations
responses: {}
/demo/service-b:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ServiceB.Arn}/invocations
responses: {}
/demo/timeout:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Timeout.Arn}/invocations
responses: {}
/demo/error:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Error.Arn}/invocations
responses: {}
ServiceALambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- ServiceA
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: ServiceA
Principal: apigateway.amazonaws.com
ServiceB:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-b.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Api
Properties:
Path: /demo/service-b
Method: get
RestApiId:
Ref: ServerlessObservability
ServiceBLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- ServiceB
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: ServiceB
Principal: apigateway.amazonaws.com
ServiceC:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-c.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
ServiceReadSns:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-read-sns.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: SNS
Properties:
Topic: ''
ServerlessObservabilitySnsTopicQVJUw:
Type: 'AWS::SNS::Topic'
Properties:
TopicName:
topicName: serverless-observability-dev
displayName: serverless-observability-dev
DisplayName: serverless-observability-dev
ServiceReadDynamo:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-read-dynamo.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Dynamodb
Properties:
Stream:
'Fn::GetAtt':
- DynamoDB
- StreamArn
ServiceReadS3:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-read-s3.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: S3
Properties:
Bucket: 'serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}'
Events: '*'
Timeout:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/timeout.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 1
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Api
Properties:
Path: /demo/timeout
Method: get
RestApiId:
Ref: ServerlessObservability
TimeoutLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- Timeout
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: Timeout
Principal: apigateway.amazonaws.com
Error:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/error.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Api
Properties:
Path: /demo/error
Method: get
RestApiId:
Ref: ServerlessObservability
ErrorLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- Error
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: Error
Principal: apigateway.amazonaws.com
Sns:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/sns.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: SNS
Properties:
Topic: ''
ServerlessObservabilitySnsTopicOJtJm:
Type: 'AWS::SNS::Topic'
Properties:
TopicName:
topicName: serverless-observability-dev
displayName: serverless-observability-dev
DisplayName: serverless-observability-dev
SERVERLESS FRAMEWORK
service: serverless-observability
plugins:
- serverless-pseudo-parameters
- serverless-plugin-existing-s3
custom:
bucketName: serverless-observability-${self:provider.stage}-#{AWS::Region}-#{AWS::AccountId}
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1
versionFunctions: false
environment:
stage: ${self:provider.stage}
service: ${self:service}
accountId:
Ref: AWS::AccountId
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:PutItem"
- "dynamodb:GetItem"
- "dynamodb:DescribeStream"
- "dynamodb:GetRecords"
- "dynamodb:GetShardIterator"
- "dynamodb:ListStreams"
Resource:
- "arn:aws:dynamodb:${self:provider.region}:*:table/serverless-observability-${self:provider.stage}"
- Effect: "Allow"
Action:
- "s3:GetObject*"
- "s3:PutObject*"
- "s3:ListBucket*"
- "s3:PutBucketNotification"
Resource:
- "arn:aws:s3:::${self:custom.bucketName}"
- "arn:aws:s3:::${self:custom.bucketName}/*"
- Effect: "Allow"
Action:
- "sns:Publish"
- "sns:Subscribe"
Resource:
- "arn:aws:sns:${self:provider.region}:*:serverless-observability-${self:provider.stage}"
- Effect: "Allow"
Action:
- "lambda:InvokeFunction"
Resource:
- "arn:aws:lambda:${self:provider.region}:*:function:serverless-observability-${self:provider.stage}-*"
functions:
service-a:
handler: functions/service-a.handler
timeout: 10
events:
- http:
path: demo/service-a
method: get
request:
parameters:
querystrings:
n: true
environment:
BUCKET_NAME: ${self:custom.bucketName}
service-b:
handler: functions/service-b.handler
events:
- http:
path: demo/service-b
method: get
service-c:
handler: functions/service-c.handler
service-read-sns:
handler: functions/service-read-sns.handler
events:
- sns:
topicName: "serverless-observability-${self:provider.stage}"
displayName: "serverless-observability-${self:provider.stage}"
service-read-dynamo:
handler: functions/service-read-dynamo.handler
events:
- stream:
type: dynamodb
arn:
Fn::GetAtt:
- DynamoDB
- StreamArn
service-read-s3:
handler: functions/service-read-s3.handler
events:
- s3:
bucket: ${self:custom.bucketName}
timeout:
handler: functions/timeout.handler
timeout: 1
events:
- http:
path: demo/timeout
method: get
error:
handler: functions/error.handler
events:
- http:
path: demo/error
method: get
sns:
handler: functions/sns.handler
events:
- sns:
topicName: ${self:service}-${self:provider.stage}
displayName: ${self:service}-${self:provider.stage}
# you can add CloudFormation resource templates here
resources:
Resources:
# S3Bucket:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: ${self:custom.bucketName}
DynamoDB:
Type: AWS::DynamoDB::Table
Properties:
TableName: serverless-observability-${self:provider.stage}
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
PULUMI
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
const cloud = require("@pulumi/cloud-aws");
// A bucket to store videos and thumbnails.
const bucket = new cloud.Bucket("bucket");
const bucketName = bucket.bucket.id;
// A task which runs a containerized FFMPEG job to extract a thumbnail image.
const ffmpegThumbnailTask = new cloud.Task("ffmpegThumbTask", {
build: "./docker-ffmpeg-thumb",
memoryReservation: 512,
});
// When a new video is uploaded, run the FFMPEG task on the video file.
// Use the time index specified in the filename (e.g. cat_00-01.mp4 uses timestamp 00:01)
bucket.onPut("onNewVideo", bucketArgs => {
console.log(`*** New video: file ${bucketArgs.key} was uploaded at ${bucketArgs.eventTime}.`);
const file = bucketArgs.key;
const thumbnailFile = file.substring(0, file.indexOf('_')) + '.jpg';
const framePos = file.substring(file.indexOf('_')+1, file.indexOf('.')).replace('-',':');
ffmpegThumbnailTask.run({
environment: {
"S3_BUCKET": bucketName.get(),
"INPUT_VIDEO": file,
"TIME_OFFSET": framePos,
"OUTPUT_FILE": thumbnailFile,
},
}).then(() => {
console.log(`Running thumbnailer task.`);
});
}, { keySuffix: ".mp4" });
// When a new thumbnail is created, log a message.
bucket.onPut("onNewThumbnail", bucketArgs => {
console.log(`*** New thumbnail: file ${bucketArgs.key} was saved at ${bucketArgs.eventTime}.`);
return Promise.resolve();
}, { keySuffix: ".jpg" });
// Export the bucket name.
exports.bucketName = bucketName;
STACKERY
OTHER TOOLS
- Claudia JS
- Apex
- Sparta
- A million more...
AWS CLOUD DEVELOPMENT KIT
APP SYNC
SHARING RESOURCES
automate and enable low risk releases
TECHNICAL PRACTICES OF FEEDBACK
OBSERVABILITY
- Monitoring
- Alerting and visualization
- Distributed systems tracing infrastructure
- Log aggregation
CHALLENGES
- No access to the underlying infrastructure
- Timing
- Concurrency
- Platform limitations
WHAT AWS OFFERS
GENERAL PURPOSE SOLUTIONS
SERVERLESS SPECIFIC SOLUTIONS
TECHNICAL PRACTICES OF CONTINUAL LEARNING AND EXPERIMENTATION
chaos engineering
"Limited scope, continuous, disaster recovery"
CHAOS MONKEY & SERVERLESS
actionable failure modes
- Improperly tuned timeouts
- Missing error handling
- Missing fallbacks for when a downstream service is unavailable
SECURITY
SUMMARY
TESTING | |
CONTINUOUS INTEGRATION | |
DEPLOYMENT PIPELINE | |
LOW-RISK RELEASES | |
OBSERVABILITY | |
CHAOS ENGINEERING |
MORE INFO
Donostia 9 y 10 de Mayo
theserverelesscourse.com
info@vgaltes.com
THANK YOU!
Vicenç García Altés
@vgaltes
theserverlesscourse.com
info@vgaltes.com
Operational Serverles
By Vicenç Garcia
Operational Serverles
- 719