Serverless computing is a cloud-native development model that allows developers to build and run applications without having to manage the underlying infrastructure.
This model still requires servers, but their management is decoupled from application development. A cloud provider takes care of the routine work of provisioning the server infrastructure, keeping it running smoothly, and scaling it up. Developers then only need to package their code into functions or containers to deploy their applications.
It gives more freedom to developers, who are no longer responsible for maintaining the infrastructure and can therefore concentrate on their core business, development. This quickly accelerates the development of applications.
It guarantees high availability & high resilience of resources, thanks to auto-scaling, by automatically adjusting the allocation of resources necessary for the operation of applications and replicating resources over multiple DC.
The third and equally important advantage is cost savings, thanks to pay-per-use billing, based on the real-time code execution and resource consumption, with the millisecond as the payment unit. This eliminates the cost of purchasing servers and operating them, especially since they are often underused. Moreover, this encourages developers to optimize the performance of their code. Your costs are then proportional to the use of your business and the traffic you generate, which eventually means proportional to your profits.
For this article, I will deploy a simple serverless solution using several frameworks / IaC tools on the cloud provider AWS and compare them. Why AWS? Simply because it is the most used cloud provider nowadays and the most advanced on serverless technologies.
This very simple serverless architecture aims to implement an API that will trigger a lambda that will interact with a NoSQL database (DynamoDB). All the components used here are serverless (API Gateway, Lambda & DynamoDB), and can be deployed in several ways, which we will detail below. Moreover, this infrastructure is free when the stack is not used, you only pay for the amount of data stored in DynamoDB.
Although in practice this mode of deployment is rarely used, it is the first view that we have of the components with AWS. And it seems to be the easiest way to achieve it without bothering with a development environment or a configuration/programming language.
Moreover, deploying with the console allows you to be aware of all the resources necessary for the proper functioning of the example you wish to deploy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1428341300017",
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Sid": "",
"Resource": "*",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow"
}
]
}
Once the role is created, we can start the creation of the Lambda function which will write in the dynamoDB table.
In AWS Lambda Management console > Create Function
Name the function
For the runtime, select Nodejs 12.x
.
For the architecture, select x86_64
.
For permissions, select Use an existing role
and use the previously created role
Click on “Create function”
Once the function is created, copy the code below in the "Source Code" tab.
console.log('Loading function');
var AWS = require('aws-sdk');
var dynamo = new AWS.DynamoDB.DocumentClient();
/**
* Provide an event that contains the following keys:
*
* - operation: one of the operations in the switch statement below
* - tableName: required for operations that interact with DynamoDB
* - payload: a parameter to pass to the operation being performed
*/
exports.handler = function(event, context, callback) {
//console.log('Received event:', JSON.stringify(event, null, 2));
var operation = event.operation;
if (event.tableName) {
event.payload.TableName = event.tableName;
}
switch (operation) {
case 'create':
dynamo.put(event.payload, callback);
break;
case 'read':
dynamo.get(event.payload, callback);
break;
case 'update':
dynamo.update(event.payload, callback);
break;
case 'delete':
dynamo.delete(event.payload, callback);
break;
case 'list':
dynamo.scan(event.payload, callback);
break;
case 'echo':
callback(null, "Success");
break;
case 'ping':
callback(null, "pong");
break;
default:
callback(`Unknown operation: ${operation}`);
}
};
To make it simple, this code will act in a different way according to the event received in input, it will either create, read, update, delete or list elements of the dynamoDB table.
Now that our function is created, we have to create a resource that allows our user to call it so that it can be used! This is where API Gateway, the AWS service for creating APIs, comes into play.
Open the API Gateway console.
Choose Create API.
In the REST API box, choose Build.
Under Create new API, choose New API.
Under Settings, do the following:
DynamoDBOperations
.Choose Create API.
In the following steps, you create a resource named DynamoDBManager
in your REST API.
To create the resource:
In the API Gateway console, in the Resources tree of your API, make sure that the root (/
) level is highlighted. Then, choose Actions, Create Resource.
Under New child resource, do the following:
DynamoDBManager
./dynamodbmanager
.Choose Create Resource.
In the following steps, you create a POST
method on the DynamoDBManager
resource that you created in the previous section.
To create the method:
In the API Gateway console, in the Resources tree of your API, make sure that /dynamodbmanager
is highlighted. Then, choose Actions, Create Method.
In the small dropdown menu that appears under /dynamodbmanager
, choose POST
, and then choose the checkmark icon.
In the method's Setup pane, do the following:
LambdaFunctionOverHttps
).In the Add Permission to Lambda Function dialog box, choose OK.
Once all these steps are done, your post
method should look like this:
Create the DynamoDB table that your Lambda function uses.
To create the DynamoDB table:
Open the Tables page of the DynamoDB console.
Choose Create table.
Under Table details, do the following:
lambda-apigateway
.id
, and keep the data type set as String.Under Settings, keep the Default settings.
Choose Create table.
Once all the elements of our example are created, we have to test that everything works well (to be sure that our example is viable). To do so, we just have to go to the post
method created earlier in the API, and click on "Test".
In the body of the request, copy one of the following payloads and click on "Test".
{
"operation": "create",
"tableName": "lambda-apigateway",
"payload": {
"Item": {
"id": "1234ABCD",
"number": 5
}
}
}
{
"operation": "update",
"tableName": "lambda-apigateway",
"payload": {
"Key": {
"id": "1234ABCD"
},
"AttributeUpdates": {
"number": {
"Value": 10
}
}
}
}
Our standard to avoid the above-mentioned problems is to use IAC. Only several solutions are available to us to realize a serverless infrastructure, and we are entitled to ask ourselves which solution is the most adapted to our needs when we deal with serverless. If you want to learn more, I invite you to read the next article of the series on IaC technologies 🙂