Trigger Lambda Function When New Image is Uploaded to S3 - (Let's Build 🏗️ Series)
awedis
Posted on October 24, 2023
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.
Posted on October 24, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 12, 2023
October 24, 2023