How to Speedrun Setting Up a Go Lambda Function with Terraform
Go seems like the perfect language for Lambdas; simple, concise, and compiled. In this we will:
- Create our go lambda function.
- Use terraform to spin up our resources.
- Use the event bridge to create a cron of our lambda being called every minute.
- Be able to view our lambda being triggered in cloudwatch.
I don’t offer money-back guarantees around here, but getting this up and running is as quick as removing the open-source license from software that people have built companies on.
Let’s get into it.
Step 0: Prerequisties #
- You will need to have Terraform setup
- A working AWS account
go
installed locally
Step 1: Prep Your Go Code #
First things first, let’s get your Go function ready. Create a new file named main.go
in your project directory.
main.go:
package main
import (
"github.com/aws/aws-lambda-go/lambda"
"log"
)
func handler() error {
log.Println("Hello from Lambda!")
return nil
}
func main() {
lambda.Start(handler)
}
This function does nothing more than log a message, but it’s a good start. Next steps:
# mac skill issue inbound
GOOS=linux
# compile
go build -o bootstrap main.go
zip function.zip bootstrap
Step 2: Set the Stage with Terraform #
Personally I like to create a directory in my project called .terraform/
but feel free to use your base directory in the project. You’ll want a few files to manage this setup properly: main.tf, variables.tf, lambda.tf, eventbridge.tf.
main.tf Setup of generic terraform information for the project.
terraform {
required_version = ">= 0.14"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 3.0"
}
}
}
provider "aws" {
region = var.region
}
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
variables.tf Declare your essentials here.
variable "region" {
description = "AWS region to deploy resources"
type = string
default = "eu-west-2"
}
variable "function_name" {
description = "Name of our lambda function"
type = string
default = "getting-started-with-lambda"
}
variable "lambda_role_name" {
description = "IAM role name for our Lambda function"
type = string
default = "go-lambda-role"
}
variable "event_rule_name" {
description = "Name for the EventBridge rule"
type = string
default = "go-lambda-every-minute"
}
variable "event_description" {
description = "Description of what the EventBridge rule does"
type = string
default = "Fires every minute"
}
variable "event_schedule_expression" {
description = "Schedule expression for the EventBridge rule"
type = string
default = "rate(1 minute)"
}
iam.tf Define your IAM role that the Lambda will use.
locals {
account_id = data.aws_caller_identity.current.account_id
}
resource "aws_iam_role" "go_lambda_role" {
name = var.lambda_role_name
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Action" : "sts:AssumeRole",
"Principal" : {
"Service" : "lambda.amazonaws.com"
},
"Effect" : "Allow"
}
]
})
inline_policy {
name = "go-lambda-policies"
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : "logs:CreateLogGroup",
"Resource" : "arn:aws:logs:${data.aws_region.current.name}:${local.account_id}:*"
},
{
"Effect" : "Allow",
"Action" : [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource" : [
"arn:aws:logs:${data.aws_region.current.name}:${local.account_id}:log-group:/aws/lambda/*:*"
]
}
]
})
}
}
lambda.tf Here’s where the magic happens. Define your Lambda function resource.
resource "aws_lambda_function" "go_lambda_function" {
function_name = var.function_name
role = aws_iam_role.go_lambda_role.arn
package_type = "Zip"
handler = "bootstrap"
runtime = "provided.al2023"
# This will need changing if you don't create a subdirectory for terraform
filename = "../function.zip"
source_code_hash = filebase64sha256("../function.zip")
depends_on = [
aws_iam_role.go_lambda_role
]
tags = {
Name = "Go Lambda Example"
}
}
resource "aws_lambda_permission" "allow_cloudwatch_to_call_split_lambda" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.go_lambda_function.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.go_lambda_every_minute.arn
}
eventbridge.tf Set up the event bridge to run your lambda function on a one minute schedule.
resource "aws_cloudwatch_event_rule" "go_lambda_every_minute" {
name = var.event_rule_name
description = var.event_description
schedule_expression = var.event_schedule_expression
}
resource "aws_cloudwatch_event_target" "trigger_lambda_on_schedule" {
rule = aws_cloudwatch_event_rule.go_lambda_every_minute.name
target_id = "lambda"
arn = aws_lambda_function.go_lambda_function.arn
}
Step 3: Deploy #
Firstly you will need to initalize your terraform in the repository.
terraform init
and you will then need to plan and apply
terraform plan # review the above after running
terraform apply # select yes when happy to apply & deploy
Step 4: Check the logs! #
You should now be able to view the lambda function being triggered under the cloud watch log group we created.
Step 5: Destroy #
Although this is all using the free tier, make sure to tear always destroy your aws resources when they’re not in use.
terraform destory #select yes
Hope you enjoyed.