Create and deploy AWS Lambda function in GOlang

Creating and deploying AWS Lambda function made easy in GO - sounds interesting? But what exactly are lambda functions in context of AWS? How do they help solve problems, and how can you create and deploy them effortlessly? This article aims to find the answers to these questions.

AWS Lambda is a highly available and scalable compute service. It runs function code written in many programming languages like GO, Java, NodeJS, etc, without managing and provisioning the servers. This makes the developers focus more on business logic of the application/system rather than platform complexities.

But writing and automating the deployment of the AWS Lambda function is not quite straightforward. There are several moving parts that are tricky to grasp in the beginning.

This article serves as your go-to resource, offering a detailed, step-by-step guide on creating, packaging, deploying, and running AWS Lambda functions seamlessly using Cloudformation, CLI, and GO language. It covers the steps to,

  • Create and initialize a Go module
  • Create an AWS Lambda function in that module
  • Build the module on different platforms
  • Package the Lambda function code into an archive file (.zip)
  • Create an AWS S3 bucket to host the Lambda function archive file
  • Import the archive file to the S3 bucket
  • Create CloudFormation template and automatically creating necessary AWS resources
  • Test the lambda function
  • Check logs in AWS CloudWatch
  • Delete the CloudFormation stack to clean up the resources

Prerequisites:

Having all prerequisites, let’s have some hands-on experience of Lambda function.

Create a GO module

First of all, create a directory for the module code, and then initialize a GO module by following command on the console,

go mod init <your-namespacel>/aws-lambda-demo-go

Provide any preferred namespace in place of <your-namespacel>/aws-lambda-demo-go

If you are not sure how to setup Go working environment then this blog will really help you.

This should create a go.mod file in your project, where we define all the dependencies required by the module. We require aws-lambda-go library to import in to go.mod file, add a line

require github.com/aws/aws-lambda-go v1.36.0

module <your-namespacel>/aws-lambda-demo-go

go 1.19

require github.com/aws/aws-lambda-go v1.36.0

Resolve the dependencies by running,

go mod tidy
go mod vendor

Now create an event handler lambda function HandleRequest and start it inside main(). AWS Lambda will trigger the HandleRequest function on an external event.

package main

import (
"context"
"fmt"

"github.com/aws/aws-lambda-go/lambda"
)

type MyBook struct {
ID string `json:"id,omitempty"`
Title string `json:"title,omitempty"`
}

func HandleRequest(ctx context.Context, book MyBook) (string, error) {
msg := fmt.Sprintf("ID: %s, Title: %s", book.ID, book.Title)
fmt.Println(msg)

return msg, nil
}

func main() {
lambda.Start(HandleRequest)
}

We defined a struct named MyBook, which the Lambda function uses to unmarshal JSON events.

HandleRequest function receives two input parameters; the first is Context which holds request information, and the second is MyBook object. It does not do much fancy stuff — just prints out concatenated JSON string fields and returns them. Of course, you can add more flesh to this based on your business logic.

Building GO Module

We are done with writing our function code, now time to build it,

GOOS=linux go build main.go

Setting GOOS to Linux ensures that the compiled executable is compatible with the Go runtime, even if you compile it in a non-Linux environment[1].

Creating a .zip file

On Windows:

# Download the lambda library from GitHub,
go get github.com/aws/aws-lambda-go/lambda

# Download the build-lambda-zip tool from GitHub, it is used to zip the lambda package,
go install github.com/aws/aws-lambda-go/cmd/build-lambda-zip@latest

# Set environment variable
set GOOS=linux
set GOARCH=amd64
set CGO_ENABLED=0

# Add build-lambda-zip path (%USERPROFILE%\Go\bin) to GOPATH environment variable
# Create a deployment package (.zip file) by build-lambda-zip,
build-lambda-zip.exe -o aws-lambda-demo-go.zip main

On Linux and Mac OSX:

# Download the lambda library from GitHub,
go get github.com/aws/aws-lambda-go/lambda

# Compile executables:
GOOS=linux GOARCH=amd64 go build -o main main.go

# ZIP the package
Zip main.zip main

Deploy lambda function

There are several methods to deploy function code to AWS Lambda. You can utilize the Lambda code editor within the AWS Management Console, or you can upload a code archive file to an S3 bucket and direct Lambda to retrieve the code from that location.

In this example we will import an archive (.zip) of the lambda function code to s3 bucket.

If you do not already have a S3 bucket, then create a new one by AWS CLI command,

aws s3api create-bucket - bucket my-demo-s3-bucket --create-bucket-configuration LocationConstraint=eu-west-1

Upload zip file to aws S3 bucket using AWS CLI

aws s3 cp aws-lambda-demo-go.zip s3://my-demo-s3-bucket/demo-lambda/aws-lambda-demo-go.zip

Deploy Lambda using Cloudformation:

Setting up Lambda functions and configuring roles and policies for execution can be tricky. Manual deployment increases the risk of errors. AWS CloudFormation automates resource stack creation, reducing mistakes. It speeds up repeatable cloud resource deployment and provisioning by Infrastructure as Code.

CloudFormation lets us create an AWS resource template as a JSON or YAML file. This file contains details of all the resources needed for our application or backend stack, such as Lambda functions, API Gateway, SNS, SQS, EC2 instances, VPC, DynamoDB, security groups, roles, and policies.

We create following cloudformation template:

{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "A CF template to create a lambda function",
"Parameters": {
"pLambdaCodeBucket": {
"Type": "String"
},
"pLambdaCodeS3KeyPath": {
"Type": "String"
}
},
"Resources": {
"lfnLambdaRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Policies": [
{
"PolicyName": "observability",
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
}
]
}
},
"lfnMyDemoLambda": {
"Type": "AWS::Lambda::Function",
"DependsOn": [
"lfnLambdaRole"
],
"Properties": {
"Architectures": [
"x86_64"
],
"Runtime": "go1.x",
"Handler": "main",
"Code": {
"S3Bucket": {
"Ref": "pLambdaCodeBucket"
},
"S3Key": {
"Ref": "pLambdaCodeS3KeyPath"
}
},
"Description": "This is my demo lambda function",
"FunctionName": "my-demo-lambda",
"Role": {
"Fn::GetAtt": [
"lfnLambdaRole",
"Arn"
]
},
"Timeout": "120"
}
}
}
}

In this CloudFormation template, we define a Lambda function (Type: AWS::Lambda::Function) named my-demo-lambda in the lfnMyDemoLambda section (logical name). The function's code is stored in an archive file located in an S3 bucket ("Ref": "pLambdaCodeBucket") and identified by a file key ("Ref": "pLambdaCodeS3KeyPath").

We also define an IAM role, lfnLambdaRole (“Type”: “AWS::IAM::Role”), which is required by the lambda function to execute in the AWS environment (“Service”: “lambda.amazonaws.com”).

In the IAM role lfnLambdaRole we also define a Policy (“PolicyName”: “observability”) to create Cloudwatch logs. This is very handy to troubleshoot lambda functions.

We are ready to deploy this cloudformation stack,

aws cloudformation deploy \
--template-file ./deploy/cf.json \
--stack-name my-demo-lambda-stack \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
pLambdaCodeBucket=azam-demo-s3-bucket \
pLambdaCodeS3KeyPath=demo-lambda/aws-lambda-demo-go.zip

Note: pLambdaCodeBucket and pLambdaCodeS3KeyPath are parameter names, passed to Cloudformation deploy command, which is a way to pass dynamic values to CF template. Parameters can be read by the special function Ref as written below.

This should trigger a Cloudformation stack deploy, which may take few minutes depending on how many resources we are going to deploy,

Creating and deploying AWS Lambda function made easy in GOlang

After the deployment is complete, you should be able to find the newly created Lambda function. Navigate to the Lambda service in the AWS Management Console and search for the function using its name, in this instance, my-demo-lambda

Test Lambda Function

AWS Management Console provides built-in functionality to Test lambda function by pushing an input event. In this case, we pass JSON event to the function HandleRequest which will be unmarshalled to MyBook struct,

If you follow all the above steps correctly, your Test should successfully trigger the lambda function.

Cloudwatch logs:

In the previous section, we assigned an IAM role to the Lambda function to enable CloudWatch logging. After testing the function, we can view its logs in CloudWatch. To do this, navigate to CloudWatch in the AWS Management Console, click on 'Log groups' in the left menu, and filter log groups by the Lambda function name, such as /aws/lambda/my-demo-lambda. Choose one of the log streams to view the logged items.

Delete stack:

If you wish to remove all resources deployed as part of the CloudFormation stack, AWS CloudFormation offers the 'delete-stack' command for this purpose:

aws cloudformation delete-stack - stack-name my-demo-lambda-stack

Note: In this example, if an S3 bucket was created outside of the CloudFormation stack using the AWS CLI, the 'delete-stack' command will not clean up the S3 bucket. You will need to manually remove it if it's no longer needed."

Final Words:

If you have followed all the above steps correctly, you should be able to create, package and deploy your first AWS Lambda function.

I would recommend building the knowledge obtained in this article and reading my next article, Adding CRUD operations in AWS Lambda and DynamoDB using GOlang

I trust that you've successfully completed the steps outlined above and have created, packaged, and deployed your first AWS Lambda function. Building upon the knowledge gained from this article, I encourage you to go deeper into serverless architecture by exploring my next article, which covers the implementation of CRUD operations in AWS Lambda and DynamoDB using Go Language. This will further enhance your understanding and proficiency in developing serverless applications on the AWS platform

Creating and deploying AWS Lambda function made easy in GO – sounds interesting? But what exactly are lambda functions in context of AWS? How do they help solve problems, and how can you create and deploy them effortlessly? This article aims to find the answers to these questions.

AWS Lambda is a highly available and scalable compute service. It runs function code written in many programming languages like GO, Java, NodeJS, etc, without managing and provisioning the servers. This makes the developers focus more on business logic of the application/system rather than platform complexities.

But writing and automating the deployment of the AWS Lambda function is not quite straightforward. There are several moving parts that are tricky to grasp in the beginning.

This article serves as your go-to resource, offering a detailed, step-by-step guide on creating, packaging, deploying, and running AWS Lambda functions seamlessly using Cloudformation, CLI, and GO language. It covers the steps to,

  • Create and initialize a Go module
  • Create an AWS Lambda function in that module
  • Build the module on different platforms
  • Package the Lambda function code into an archive file (.zip)
  • Create an AWS S3 bucket to host the Lambda function archive file
  • Import the archive file to the S3 bucket
  • Create CloudFormation template and automatically creating necessary AWS resources
  • Test the lambda function
  • Check logs in AWS CloudWatch
  • Delete the CloudFormation stack to clean up the resources

Prerequisites:

Having all prerequisites, let’s have some hands-on experience of Lambda function.

Create a GO module

First of all, create a directory for the module code, and then initialize a GO module by following command on the console,

go mod init <your-namespacel>/aws-lambda-demo-go

Provide any preferred namespace in place of <your-namespacel>/aws-lambda-demo-go

If you are not sure how to setup Go working environment then this blog will really help you.

This should create a go.mod file in your project, where we define all the dependencies required by the module. We require aws-lambda-go library to import in to go.mod file, add a line

require github.com/aws/aws-lambda-go v1.36.0

module <your-namespacel>/aws-lambda-demo-go

go 1.19

require github.com/aws/aws-lambda-go v1.36.0

Resolve the dependencies by running,

go mod tidy
go mod vendor

Now create an event handler lambda function HandleRequest and start it inside main(). AWS Lambda will trigger the HandleRequest function on an external event.

package main

import (
"context"
"fmt"

"github.com/aws/aws-lambda-go/lambda"
)

type MyBook struct {
ID string `json:"id,omitempty"`
Title string `json:"title,omitempty"`
}

func HandleRequest(ctx context.Context, book MyBook) (string, error) {
msg := fmt.Sprintf("ID: %s, Title: %s", book.ID, book.Title)
fmt.Println(msg)

return msg, nil
}

func main() {
lambda.Start(HandleRequest)
}

We defined a struct named MyBook, which the Lambda function uses to unmarshal JSON events.

HandleRequest function receives two input parameters; the first is Context which holds request information, and the second is MyBook object. It does not do much fancy stuff — just prints out concatenated JSON string fields and returns them. Of course, you can add more flesh to this based on your business logic.

Building GO Module

We are done with writing our function code, now time to build it,

GOOS=linux go build main.go

Setting GOOS to Linux ensures that the compiled executable is compatible with the Go runtime, even if you compile it in a non-Linux environment[1].

Creating a .zip file

On Windows:

# Download the lambda library from GitHub,
go get github.com/aws/aws-lambda-go/lambda

# Download the build-lambda-zip tool from GitHub, it is used to zip the lambda package,
go install github.com/aws/aws-lambda-go/cmd/build-lambda-zip@latest

# Set environment variable
set GOOS=linux
set GOARCH=amd64
set CGO_ENABLED=0

# Add build-lambda-zip path (%USERPROFILE%\Go\bin) to GOPATH environment variable
# Create a deployment package (.zip file) by build-lambda-zip,
build-lambda-zip.exe -o aws-lambda-demo-go.zip main

On Linux and Mac OSX:

# Download the lambda library from GitHub,
go get github.com/aws/aws-lambda-go/lambda

# Compile executables:
GOOS=linux GOARCH=amd64 go build -o main main.go

# ZIP the package
Zip main.zip main

Deploy lambda function

There are several methods to deploy function code to AWS Lambda. You can utilize the Lambda code editor within the AWS Management Console, or you can upload a code archive file to an S3 bucket and direct Lambda to retrieve the code from that location.

In this example we will import an archive (.zip) of the lambda function code to s3 bucket.

If you do not already have a S3 bucket, then create a new one by AWS CLI command,

aws s3api create-bucket - bucket my-demo-s3-bucket --create-bucket-configuration LocationConstraint=eu-west-1

Upload zip file to aws S3 bucket using AWS CLI

aws s3 cp aws-lambda-demo-go.zip s3://my-demo-s3-bucket/demo-lambda/aws-lambda-demo-go.zip

Deploy Lambda using Cloudformation:

Setting up Lambda functions and configuring roles and policies for execution can be tricky. Manual deployment increases the risk of errors. AWS CloudFormation automates resource stack creation, reducing mistakes. It speeds up repeatable cloud resource deployment and provisioning by Infrastructure as Code.

CloudFormation lets us create an AWS resource template as a JSON or YAML file. This file contains details of all the resources needed for our application or backend stack, such as Lambda functions, API Gateway, SNS, SQS, EC2 instances, VPC, DynamoDB, security groups, roles, and policies.

We create following cloudformation template:

{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "A CF template to create a lambda function",
"Parameters": {
"pLambdaCodeBucket": {
"Type": "String"
},
"pLambdaCodeS3KeyPath": {
"Type": "String"
}
},
"Resources": {
"lfnLambdaRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Policies": [
{
"PolicyName": "observability",
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
}
]
}
},
"lfnMyDemoLambda": {
"Type": "AWS::Lambda::Function",
"DependsOn": [
"lfnLambdaRole"
],
"Properties": {
"Architectures": [
"x86_64"
],
"Runtime": "go1.x",
"Handler": "main",
"Code": {
"S3Bucket": {
"Ref": "pLambdaCodeBucket"
},
"S3Key": {
"Ref": "pLambdaCodeS3KeyPath"
}
},
"Description": "This is my demo lambda function",
"FunctionName": "my-demo-lambda",
"Role": {
"Fn::GetAtt": [
"lfnLambdaRole",
"Arn"
]
},
"Timeout": "120"
}
}
}
}

In this CloudFormation template, we define a Lambda function (Type: AWS::Lambda::Function) named my-demo-lambda in the lfnMyDemoLambda section (logical name). The function’s code is stored in an archive file located in an S3 bucket ("Ref": "pLambdaCodeBucket") and identified by a file key ("Ref": "pLambdaCodeS3KeyPath").

We also define an IAM role, lfnLambdaRole (“Type”: “AWS::IAM::Role”), which is required by the lambda function to execute in the AWS environment (“Service”: “lambda.amazonaws.com”).

In the IAM role lfnLambdaRole we also define a Policy (“PolicyName”: “observability”) to create Cloudwatch logs. This is very handy to troubleshoot lambda functions.

We are ready to deploy this cloudformation stack,

aws cloudformation deploy \
--template-file ./deploy/cf.json \
--stack-name my-demo-lambda-stack \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
pLambdaCodeBucket=azam-demo-s3-bucket \
pLambdaCodeS3KeyPath=demo-lambda/aws-lambda-demo-go.zip

Note: pLambdaCodeBucket and pLambdaCodeS3KeyPath are parameter names, passed to Cloudformation deploy command, which is a way to pass dynamic values to CF template. Parameters can be read by the special function Ref as written below.

This should trigger a Cloudformation stack deploy, which may take few minutes depending on how many resources we are going to deploy,

Creating and deploying AWS Lambda function made easy in GOlang

After the deployment is complete, you should be able to find the newly created Lambda function. Navigate to the Lambda service in the AWS Management Console and search for the function using its name, in this instance, my-demo-lambda

Test Lambda Function

AWS Management Console provides built-in functionality to Test lambda function by pushing an input event. In this case, we pass JSON event to the function HandleRequest which will be unmarshalled to MyBook struct,

If you follow all the above steps correctly, your Test should successfully trigger the lambda function.

Cloudwatch logs:

In the previous section, we assigned an IAM role to the Lambda function to enable CloudWatch logging. After testing the function, we can view its logs in CloudWatch. To do this, navigate to CloudWatch in the AWS Management Console, click on ‘Log groups’ in the left menu, and filter log groups by the Lambda function name, such as /aws/lambda/my-demo-lambda. Choose one of the log streams to view the logged items.

Delete stack:

If you wish to remove all resources deployed as part of the CloudFormation stack, AWS CloudFormation offers the ‘delete-stack’ command for this purpose:

aws cloudformation delete-stack - stack-name my-demo-lambda-stack

Note: In this example, if an S3 bucket was created outside of the CloudFormation stack using the AWS CLI, the ‘delete-stack‘ command will not clean up the S3 bucket. You will need to manually remove it if it’s no longer needed.”

Final Words:

If you have followed all the above steps correctly, you should be able to create, package and deploy your first AWS Lambda function.

I would recommend building the knowledge obtained in this article and reading my next article, Adding CRUD operations in AWS Lambda and DynamoDB using GOlang

I trust that you’ve successfully completed the steps outlined above and have created, packaged, and deployed your first AWS Lambda function. Building upon the knowledge gained from this article, I encourage you to go deeper into serverless architecture by exploring my next article, which covers the implementation of CRUD operations in AWS Lambda and DynamoDB using Go Language. This will further enhance your understanding and proficiency in developing serverless applications on the AWS platform

© 2024 Solution Toolkit . All rights reserved.