top of page

Hands-on serverless with AWS Lambda, Go and CDK

Updated: Apr 25

AWS Lambda is a service from Amazon Web Services that used to build a highly scalable event-driven application. It is designed to enable developers to run code without provisioning or managing servers.

Go, often referred to as Golang, is a programming language designed by Google, well-suited for building scalable and reliable software systems, including web servers, APIs, and distributed systems.

In this post, I will show you how we built a Go Lambda with CDK- an open-source software development framework that allows developers to define AWS infrastructure in code using familiar programming languages like TypeScript, Python, Java, and C#.

Create a simple lambda funtion with a Go and Init cdk

First, create a Go function in main.go.

package main

import (
	"context"
	"github.com/aws/aws-lambda-go/lambda"
	"log"
)

type Event struct {
	FirstKey string `json:"key1"`
	SecondKey  string `json:"key2"`
}

func main() {
	handler := func(ctx context.Context, event *Event) (interface{}, error) {
		return event, nil
	handler := func(ctx context.Context, event *Event) () {
		log.Printf("First Key: %s\n", event.FirstKey)
		log.Printf("Second Key: %s\n", event.SecondKey)
	}

	lambda.Start(handler)
}

About initializing AWS CDK, please follow the instruction in AWS guideline, please note that we can keep the structure like this.

lambda-app/
    ├── src/
    │   ├── functions/
    │   │   └── cmd/
    │   │       └── main.go
    │   ├── go.mod
    │   └── go.sum
    ├── cdk/
    │   ├── lib/
    │   │   └── stack.ts
    │   └── package.json
    └── Dockerfile

Lastly, we will need Docker available in our machine to build the image that serves the Lambda bundling later.

FROM golang:1.19-alpine

WORKDIR /app

COPY ./src/go.mod /
COPY ./src/go.sum /
RUN apk update
RUN apk upgrade
RUN apk add bash
RUN go mod download

After the image is completely built, you can put it on any repository like Gitlab Registry or Amazon ECR.

Construct Lambda build in CDK

First, we need to update out package.json

{
  ...
  "devDependencies": {
    "@types/node": "10.17.27",
    "aws-cdk": "2.50.0",
    "aws-cdk-lib": "2.50.0",
    "constructs": "^10.0.0",
    "source-map-support": "^0.5.21",
    "ts-node": "^10.9.1",
    "typescript": "~3.9.7"
  },
}

Then dont forget to run npm install

Next, we will construct Lambda in our CDK stack

import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { DockerImage, Duration } from 'aws-cdk-lib';
import * as path from 'path';

export class InfraStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const handler = new Function(this.scope, 'cmd-function, {
      functionName: 'simple-lambda-cmd',
      runtime: Runtime.PROVIDED_AL2,
      handler: 'bootstrap',
      code: Code.fromAsset(path.join(__dirname, '../../../src'), {
        bundling: {
          image: DockerImage.fromRegistry(
            <docker image location>,
          ),
          user: 'root',
          environment: {
            CGO_ENABLED: '0',
            GOOS: 'linux',
            GOARCH: 'amd64',
            GO111MODULE: 'auto',
          },
          command: [
            'bash',
            '-c',
            ['go build -tags lambda.norpc -o /asset-output/bootstrap functions/cmd/main.go'].join(
              ' && ',
            ),
          ],
        },
      }),
    });
  }
}

Things that we need to keep an eye on while doing code bundle

  • Go is implemented differently than other managed runtimes. Because Go compiles natively to an executable binary (meant that Go dependencies are inside the compiled binary), it doesn't require a dedicated language runtime. We will use the PROVIDED_AL2 runtime since the GO_1_X runtime does not support things like Lambda Extensions.

  • As you can see, we used Code.fromAsset that located the src directory contains go.mod and go.sum.

  • For bundling option, the image that we built from Dockerfile above will be used and you can see the command that helps building the Go excutable to be uploaded on S3 later (you won't see that upload part because that's CDK mechanism).

  • Lambda requires CGO_ENABLED=0 during the build step.

And that's all for what we need to create a serverless function with Go and AWS Lambda, now you need to have Docker running and try cdk diff/deploy to see what will happen ;)

Conclusion

Since Go is known for its simplicity, efficiency, and robustness, but in my opinion, it not well-suited to build a lambda using Go.

The most reasonable reason is the Go compiler itself, bundling all the things into an executable file including the dependencies, making the Lambda layers useless, leading to bigger size of the function.

Besides, I can not debug/edit the code directly on AWS console :p...

Additional Resources and Further Reading

29 views0 comments
bottom of page