Let's build a simple architecture where a Lambda function is triggered whenever a user uploads a new image to an S3 bucket.
📋 Note: This article is preparation for a more advanced one which will be published inside the same series.
The main parts of this article:
1- Architecture Overview (Terraform)
2- About AWS Services (Info)
3- Technical Part (Code)
4- Result
5- Conclusion
Architecture Overview
variable "region" {
default = "eu-west-1"
description = "AWS Region to deploy to"
}
terraform {
required_version = "1.5.1"
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.22.0"
}
}
}
provider "aws" {
region = var.region
}
resource "aws_s3_bucket" "image_bucket" {
bucket = "lets-build-1"
}
resource "aws_iam_role" "lambda_execution_role" {
name = "lets-build-lambda-role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
}
resource "aws_iam_policy_attachment" "lambda_basic_execution" {
name = "lets-build-lambda-attachment"
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
roles = [aws_iam_role.lambda_execution_role.name]
}
resource "aws_lambda_function" "image_analysis_lambda" {
filename = "./main.zip"
function_name = "lets-build-function"
handler = "main"
runtime = "go1.x"
role = aws_iam_role.lambda_execution_role.arn
memory_size = "128"
timeout = "3"
source_code_hash = filebase64sha256("./main.zip")
environment {
variables = {
REGION = "${var.region}"
}
}
}
resource "aws_lambda_permission" "allow_bucket" {
statement_id = "AllowExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.image_analysis_lambda.function_name
principal = "s3.amazonaws.com"
source_arn = aws_s3_bucket.image_bucket.arn
}
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = aws_s3_bucket.image_bucket.id
lambda_function {
lambda_function_arn = aws_lambda_function.image_analysis_lambda.arn
events = ["s3:ObjectCreated:*"]
filter_prefix = "images/"
filter_suffix = ".png"
}
depends_on = [aws_lambda_permission.allow_bucket]
}
Hint: always run terraform fmt
and terraform validate
to clean the syntax and validate that all is good, after you can run terraform plan
to see the resources that will be created and finally terraform apply
About AWS Services
1- Amazon S3: To store the image.
2- AWS Lambda: To trigger our function and execute the code.
3- Identity and Access Management (IAM): To give permissions for the S3 and Lambda events.
Technical Part
Our fancy go code 😜 does simple logging.
package main
import (
"context"
"fmt"
"github.com/aws/aws-lambda-go/lambda"
)
func handler(ctx context.Context) (string, error) {
fmt.Println("Lambda function executed.")
return "Lambda function executed successfully.", nil
}
func main() {
lambda.Start(handler)
}
Since we are not using any frameworks, we need to build and create our own .zip file in order to be able to upload the code to our Lambda function. Inside the Terraform configuration file already you can notice that I'm pointing to main.zip
file which holds our built code.
Build your Go binary for the appropriate target platform:
GOARCH=amd64 GOOS=linux go build -o main
Create a ZIP file containing your main binary and any other dependencies:
zip main.zip main
Result
That's it, let's try to upload a new image to our S3 bucket, and we can see the logs being printed out when we check Amazon CloudWatch.
Here is a simple screenshot from Amazon CloudWatch after I uploaded an image to my S3 Bucket, also remember we are using prefixes for certain folders which in our case it's /images
, and the file type should be .png
Sweet, now it's your turn to become more creative and build on top of this. And a small reminder that the techniques and skills that are used in this article will be also used for my next one, which will hold more advanced services and skills.
Conclusion
I wanted to write this article a separate one since there are many use cases in this simple architecture that can be really handy. Hope you guys enjoyed it.
If you'd like more content like this, feel free to connect with me on LinkedIn.
Top comments (3)
A great example - thanks!
Do we need to do anything or maybe upload the .zip file generated to aws? Sorry for noob questions
yes for sure, if you can notice inside the terraform I'm pointing my .zip file.