Introduction
A common issue people experience when transitioning to serverless infrastructure is finding where to configure a cron.
During this article we will look at using EventBridge to trigger a lambda on a schedule. We will implement this using Terraform.
Setup Golang Lambda
I will gloss over the section of creating a lambda, as this is something I have covered in Golang and Python already.
For this example we will use a simple Golang Hello World example.
Create main.go, then add this golang snippet:
package main
import (
"log"
"context"
"github.com/aws/aws-lambda-go/lambda"
)
func handler(ctx context.Context) error {
log.Println("Golang Lambda executed via Eventbridge Cron")
return nil
}
func main() {
lambda.Start(handler)
}
Then we will run these CLI commands to create our .zip file:
# Initialise our golang project
go mod init example.com/demo
go get github.com/aws/aws-lambda-go/lambda
# If you are on a mac, let Go know you want linux
export GOOS=linux
export GOARCH=amd64
export CGO_ENABLED=0
# Build our lambda
go build -o hello
# Zip up our binary ready for terraform
zip -r function.zip hello
Setup Terraform
Create main.tf, then add this terraform snippet:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "eu-west-1"
}
This just lets terraform know that we want to use the AWS provider, and that we'll be working in the eu-west-1 region.
You can now run this from the CLI to initialise terraform:
terraform init
Create a Lambda in Terraform
Create lambda.tf, then add this terraform snippet:
# Create out lambda, using a locally sourced zip file
resource "aws_lambda_function" "demo_lambda_hello_world" {
function_name = "demo-lambda-hello-world"
role = aws_iam_role.demo_lambda_role.arn
package_type = "Zip"
handler = "hello"
runtime = "go1.x"
filename = "function.zip"
source_code_hash = filebase64sha256("function.zip")
depends_on = [
aws_iam_role.demo_lambda_role
]
tags = {
Name = "Demo Lambda Hello World"
}
}
Create IAM Role for Lambda
Our lambda will need some basic permissions to work, these might look jarring at first but they are fairly straight forward once you read through them.
Essentially, this role will be assumed by our Lambda and give it access to write to Cloudwatch Logs.
Create iam.tf, then add this terraform snippet:
# Store the AWS account_id in a variable so we can reference it in our IAM policy
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
locals {
account_id = data.aws_caller_identity.current.account_id
}
# Lambda IAM Role
resource "aws_iam_role" "demo_lambda_role" {
name = "demo-lambda-role"
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Action" : "sts:AssumeRole",
"Principal" : {
"Service" : "lambda.amazonaws.com"
},
"Effect" : "Allow"
}
]
})
inline_policy {
name = "demo-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/*:*"
]
}
]
})
}
}
Setup our Cron
Now that we have our lambda setup, we can set up the cron.
- You can either use a cron, for example: cron(*/5 * * * ? *)
- Or; you can use a rate, for example: rate(5 minutes)
Create eventbridge.tf, then add this terraform snippet:
# Create our schedule
resource "aws_cloudwatch_event_rule" "demo_lambda_every_5_minutes" {
name = "demo-lambda-every-5-minutes"
description = "Fires every 5 minutes"
schedule_expression = "rate(5 minutes)"
}
# Trigger our lambda based on the schedule
resource "aws_cloudwatch_event_target" "trigger_lambda_on_schedule" {
rule = aws_cloudwatch_event_rule.demo_lambda_every_5_minutes.name
target_id = "lambda"
arn = aws_lambda_function.demo_lambda_hello_world.arn
}
Add Lambda Permission
In order for our cron to work, we need to let our Lambda know that EventBridge is allowed to Invoke it.
Inside lambda.tf, add this terraform snippet:
resource "aws_lambda_permission" "allow_cloudwatch_to_call_split_lambda" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.demo_lambda_hello_world.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.demo_lambda_every_5_minutes.arn
}
Deploy Terraform
First, run
terraform plan
Now, once we're confident we can run:
terraform apply
This will now create the resources from the terraform files.
Confirm it's running
After it has been running for 5 minutes you can check the Cloudwatch Logs group to confirm it has been triggered.
To confirm it is working find your Lambda in the console, then select "Monitoring". You should now see your lambda running under "Recent invocations":
Cleanup
If you were just experimenting, remember you can destroy the resources when you're done by running:
terraform destroy
While Lambda's are cheap to invoke, it is always good to keep your account clean to avoid any unnecessary billing.
And that's it! You have now configured a Lambda cronjob using EventBridge.
Top comments (0)