DEV Community

Cover image for Lambda Cron Example (Terraform)
Rhuaridh
Rhuaridh

Posted on • Originally published at rhuaridh.co.uk

Lambda Cron Example (Terraform)

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)
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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/*:*"
          ]
        }
      ]
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

Deploy Terraform

First, run

terraform plan
Enter fullscreen mode Exit fullscreen mode

Now, once we're confident we can run:

terraform apply
Enter fullscreen mode Exit fullscreen mode

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":

Cron Lambda Output

Cleanup

If you were just experimenting, remember you can destroy the resources when you're done by running:

terraform destroy
Enter fullscreen mode Exit fullscreen mode

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)