Deploying AWS Lambda in GoLang with Serverless framework

Deploying AWS Lambda in GoLang with Serverless framework

What is AWS Lambda?

AWS Lambda is a serverless computing service provided by Amazon Web Services (AWS) AWS Lambda lets you run code without provisioning or managing servers.

lambda

How does this work?

You may think, how you make your code work without provisioning a server. Well, you write Lambda functions in one of the languages and runtime supported by AWS lambda. Your code is uploaded to AWS lambda which runs your code only when needed and scales automatically. Not having to provision or manage a server and still having your code run is what makes this a part of the Serverless architecture.

Are there no servers involved?

No, the concept of serverless means not needed to maintain your own server. AWS Lambda service takes care of the servers, the operating systems, the network layer and the rest of the infrastructure, so you just need to focus on writing application code.

What does "run your code only when needed" mean?

Your lambda function runs the code when it is triggered by an event. Some common ways to trigger your lambda function are :

  • API Gateway
  • S3
  • DynamoDB Table Streams

Let's code

The best way to learn is to implement.

What are we building?

We are going to make a simple lambda function in golang. Every developer's favourite: Hello world :)

Pre-Requisites

  • Basic knowledge of golang
  • Basic understanding of handlers

Project setup

From the local machine, create a directory named aws-lambda and change the directory to it.

mkdir aws-lambda-go && cd aws-lambda-go

Initialize the Go project with a module file.

go mod init

The next part in writing the code in main.go

func hello() (events.APIGatewayProxyResponse, error) {
    body := "Hello World"

    return events.APIGatewayProxyResponse{
        StatusCode: 200,
        Body:       body,
    }, nil
}

We have created a handler named hello which returns "Hello World". One thing to note is, this handler returns events.APIGatewayProxyResponse This is because we will be using AWS API Gateway to trigger our lambda and AWS API Gateway expects a response in the mentioned format. It contains our StatusCode which will be 200 for the successful response and our Body which is the "Hello World" string.

To add the dependencies use the following commands:

go get github.com/aws/aws-lambda-go/lambda

go get github.com/aws/aws-lambda-go/events

Our main function calls the handler with Lambda.Start function. Here is how are main.go looks:

package main

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

func hello() (events.APIGatewayProxyResponse, error) {
    body := "Hello World"

    return events.APIGatewayProxyResponse{
        StatusCode: 200,
        Body:       body,
    }, nil
}
func main() {
lambda.Start(hello)
}

Creating the executable file and zip file

Use the following command to build your executable file

GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o bootstrap cmd/main.go

Now zip the executable file

zip -9 -j bootstrap.zip bootstrap

The next section covers how we deploy our lambda function.

Serverless Framework

The Serverless Framework is a command-line tool that uses YAML syntax to deploy both your code and cloud infrastructure needed. It supports Node.js, Typescript, Python, Go, Java, and more.

serverless

Advantages of serverless framework

  • Cost: You pay only for what you use. There is no need to reserve extra space for your services.
  • Flexibility: Instances are automatically scaled.
  • Accuracy and Speed: Developers can simply deploy their code without having to manage any servers, which helps accelerate delivery cycles and rapidly scale company operations.

Challenges of serverless framework

  • Loss of Control: You’re dependent on a cloud provider for functioning of servers
  • Security: If the shared server isn’t configured properly, your application data could be exposed.
  • Testing: Developers can run unit tests on function code, but integration tests, which evaluate how frontend and backend components interact, are difficult to perform in a serverless environment.
  • Performance Impact: Cold starts are common in serverless environments, adding several seconds of latency to code execution when functions are invoked after a period of inactivity.
  • Complexity: If something isn't working as it should, spotting the issue could be difficult. You'll have multiple spaces in which to look.

Serverless Architecture Use Cases

  • Trigger-based tasks: Trigger-based or event-driven tasks are commonly used with serverless framework.

  • Building RESTful APIs You can build RESTful APIs using Amazon API Gateway with serverless functions with high scalability.

  • Security checks When you spin up a new container, a function can be invoked to scan the instance for misconfigurations or vulnerabilities. Functions can also be used as a more secure option for SSH verification and two-factor authentication.

  • Continuous Integration (CI) and Continuous Delivery (CD) Serverless architectures can automate many of the stages in your CI/CD pipelines. For example, code commits can trigger a function to create a build, and pull requests can trigger automated tests.

Install serverless

Set up a new npm package with the following command:

npm init

You will see the following, enter the details as per your wish.

npm init

Install the serverless CLI via NPM:

npm install -g serverless

Getting started with serverless

The following command will guide you to create a new serverless project

serverless

Moving ahead we will be using the alias "sls" for the serverless commands

Configure your aws credentials

sls config credentials --provider aws --key <aws access key> --secret <aws secret key>

( You need to create an AWS IAM user and access key first if you don't have one already )

The serverless YAML file

service: aws-lambda-1

provider:
    name: aws
    runtime: go1.x
    region: ap-south-1

functions:
    blogExample:
    handler: bootstrap
    events:
     - http:
        method: get
        path: blogExample
        cors:
            origin: "*"
            headers: "*"
    package:
        individually: true
        artifact: bootstrap.zip

Let us understand the yaml file

  • Declare the name of your service

service: aws-lambda-1

  • Configure the provider you are using : Here we are using aws with runtime go1.x as we have written our code in Go.
provider:
    name: aws
    runtime: go1.x
    region: ap-south-1
  • Declare the functions : We have named our function "blogExample", the handler is the executable file which will run your code when this function is invoked.
functions:
    blogExample:
    handler: bootstrap
  • Events is what can trigger our function. We will be using an http event, The path to our function will be blogExample. Configure the cors settings.

    events:
      -http:
      method: get
      path: blogExample
      cors:
          origin: "*"
          headers: "*"
    
  • Configuration for your package, here we have a zip file named bootstrap.zip which we will be uploading to our lambda function. The individually ture property enables you to package your functions individually.

package:
    individually: true
    artifact: bootstrap.zip
  • We named our file bootstrap because if there's a file named bootstrap in your deployment package, Lambda runs that file. If not, Lambda looks for a runtime in the function's layers. If the bootstrap file isn't found or isn't executable, your function returns an error upon invocation. So, using bootstrap file is a safe and general practice.

Deploy your service

sls deploy
  • You should see the following output with your function url:

deploy output

  • You can see your function on the AWS Lambda dashboard

dashboard output

We have successfully deployed our lambda function, the serverless deploy takes care creating the required AWS stack.

Hope this blog was helpful in understanding AWS Lambda and the serverless framework.