Voiced by Amazon Polly |
Serverless architectures have transformed cloud computing by eliminating infrastructure management while ensuring high scalability and cost efficiency. In this guide, we will deploy a serverless application using Terraform, leveraging AWS Lambda, API Gateway, and S3 to build a fully automated and scalable solution.
Transform Your Career with AWS Certifications
- Advanced Skills
- AWS Official Curriculum
- 10+ Hand-on Labs
Why Serverless?
- No infrastructure management
- Auto-scaling based on demand
- Pay-per-use pricing model
- Faster development and deployment
Steps to Deploy the Serverless Application
We will:
- Set up infrastructure with Terraform.
- Package and deploy a Lambda function.
- Integrate it with API Gateway.
- Test the entire workflow.
Task 1: Create Infrastructure
1. Create a Directory and Configure Terraform
1 |
mkdir serverless && cd serverless |
2. Define AWS Provider and S3 Bucket
Create main.tf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
provider "aws" { region = var.aws_region } resource "random_pet" "lambda_bucket_name" { prefix = "learn-terraform-functions" length = 4 } resource "aws_s3_bucket" "lambda_bucket" { bucket = random_pet.lambda_bucket_name.id } resource "aws_s3_bucket_ownership_controls" "lambda_bucket" { bucket = aws_s3_bucket.lambda_bucket.id rule { object_ownership = "BucketOwnerPreferred" } } resource "aws_s3_bucket_acl" "lambda_bucket" { depends_on = [aws_s3_bucket_ownership_controls.lambda_bucket] bucket = aws_s3_bucket.lambda_bucket.id acl = "private" } |
3. Define Outputs
Create output.tf:
1 2 3 4 |
output "lambda_bucket_name" { description = "Name of the S3 bucket used to store function code." value = aws_s3_bucket.lambda_bucket.id } |
4. Define Variables
Create variables.tf:
1 2 3 4 5 |
variable "aws_region" { description = "AWS region for all resources." type = string default = "us-east-1" } |
5. Initialize and Apply Terraform
1 2 |
terraform init terraform apply --auto-approve |
Task 2: Create and Upload Lambda Function Archive
1. Create a Node.js Lambda Function
1 |
mkdir hello-world && cd hello-world |
Create hello.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
module.exports.handler = async (event) => { console.log('Event: ', event); let responseMessage = 'Hello, World!'; return { statusCode: 200, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ message: responseMessage, }), } } |
2. Package and Upload the Function
Create s3_object.tf:
1 2 3 4 5 6 7 8 9 10 11 12 |
data "archive_file" "lambda_hello_world" { type = "zip" source_dir = "${path.module}/hello-world" output_path = "${path.module}/hello-world.zip" } resource "aws_s3_object" "lambda_hello_world" { bucket = aws_s3_bucket.lambda_bucket.id key = "hello-world.zip" source = data.archive_file.lambda_hello_world.output_path etag = filemd5(data.archive_file.lambda_hello_world.output_path) } |
3. Apply Configuration
1 2 |
terraform init -upgrade terraform apply --auto-approve |
Task 3: Create the Lambda Function
1. Define Lambda Function and IAM Role
Create lambda.tf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
resource "aws_lambda_function" "hello_world" { function_name = "MeharHelloWorld" s3_bucket = aws_s3_bucket.lambda_bucket.id s3_key = aws_s3_object.lambda_hello_world.key runtime = "nodejs20.x" handler = "hello.handler" source_code_hash = data.archive_file.lambda_hello_world.output_base64sha256 role = aws_iam_role.lambda_exec.arn } resource "aws_cloudwatch_log_group" "hello_world" { name = "/aws/lambda/${aws_lambda_function.hello_world.function_name}" retention_in_days = 30 } resource "aws_iam_role" "lambda_exec" { name = "mehar-serverless_lambda" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Sid = "" Principal = { Service = "lambda.amazonaws.com" } }] }) } resource "aws_iam_role_policy_attachment" "lambda_policy" { role = aws_iam_role.lambda_exec.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" } |
2. Add Lambda Output
Create outputs_lambda.tf:
1 2 3 4 |
output "function_name" { description = "Name of the Lambda function." value = aws_lambda_function.hello_world.function_name } |
3. Apply and Test Lambda
1 2 3 |
terraform apply --auto-approve aws lambda invoke --region=us-east-1 --function-name=$(terraform output -raw function_name) response.json cat response.json |
Task 4: Create an HTTP API with API Gateway
1. Define API Gateway Resources
Create api.tf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
resource "aws_apigatewayv2_api" "lambda" { name = "mehar-serverless_lambda_gw" protocol_type = "HTTP" } resource "aws_apigatewayv2_stage" "lambda" { api_id = aws_apigatewayv2_api.lambda.id name = "mehar-serverless_lambda_stage" auto_deploy = true access_log_settings { destination_arn = aws_cloudwatch_log_group.api_gw.arn format = jsonencode({ requestId = "$context.requestId" sourceIp = "$context.identity.sourceIp" requestTime = "$context.requestTime" protocol = "$context.protocol" httpMethod = "$context.httpMethod" resourcePath = "$context.resourcePath" routeKey = "$context.routeKey" status = "$context.status" responseLength = "$context.responseLength" integrationErrorMessage = "$context.integrationErrorMessage" }) } } resource "aws_apigatewayv2_integration" "hello_world" { api_id = aws_apigatewayv2_api.lambda.id integration_uri = aws_lambda_function.hello_world.invoke_arn integration_type = "AWS_PROXY" integration_method = "POST" } resource "aws_apigatewayv2_route" "hello_world" { api_id = aws_apigatewayv2_api.lambda.id route_key = "GET /hello" target = "integrations/${aws_apigatewayv2_integration.hello_world.id}" } resource "aws_cloudwatch_log_group" "api_gw" { name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}" retention_in_days = 30 } resource "aws_lambda_permission" "api_gw" { statement_id = "AllowExecutionFromAPIGateway" action = "lambda:InvokeFunction" function_name = aws_lambda_function.hello_world.function_name principal = "apigateway.amazonaws.com" source_arn = "${aws_apigatewayv2_api.lambda.execution_arn}/*/*" } |
2. Add API Output
Create outputs_api.tf:
output “base_url” {
description = “Base URL for API Gateway stage.”
value = aws_apigatewayv2_stage.lambda.invoke_url
}
3. Apply and Test API Gateway
1 2 |
terraform apply --auto-approve curl "$(terraform output -raw base_url)/hello" |
Task 5: Clean Up Resources
1 2 |
terraform destroy --auto-approve cd ~ && rm -rf serverless |
Conclusion
By following this guide, you have successfully deployed a serverless application using Terraform, integrating AWS Lambda, API Gateway, and S3. This setup ensures scalability, cost efficiency, and ease of management while eliminating the need for manual infrastructure handling.
Earn Multiple AWS Certifications for the Price of Two
- AWS Authorized Instructor led Sessions
- AWS Official Curriculum
About CloudThat
CloudThat is an award-winning company and the first in India to offer cloud training and consulting services worldwide. As a Microsoft Solutions Partner, AWS Advanced Tier Training Partner, and Google Cloud Platform Partner, CloudThat has empowered over 850,000 professionals through 600+ cloud certifications winning global recognition for its training excellence including 20 MCT Trainers in Microsoft’s Global Top 100 and an impressive 12 awards in the last 8 years. CloudThat specializes in Cloud Migration, Data Platforms, DevOps, IoT, and cutting-edge technologies like Gen AI & AI/ML. It has delivered over 500 consulting projects for 250+ organizations in 30+ countries as it continues to empower professionals and enterprises to thrive in the digital-first world.

WRITTEN BY Mehar Nafis
Comments