Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run golang lambda function locally

I'm trying to develop a lambda that has to work with S3 and dynamoDB. The thing is that because I am not familiar with the SDK of aws for go I will have lots of tests and tries. Each time I will change the code is another time I have to compile the project and upload it to aws. Is there any way to do it locally? pass some kind of configuration that lets me call the services of aws locally, from my computer? Thanks!

This has to do mostly with golang, other languages like python can run directly on the aws lambda function page, and node has cloud9 support.

like image 974
Max Avatar asked Sep 06 '25 03:09

Max


2 Answers

You can use the lambci docker image(s) to execute your code locally using the same Lambda runtimes that are used on AWS.

https://github.com/lambci/docker-lambda

You can also run dynamo DB locally in another container as well

https://hub.docker.com/r/amazon/dynamodb-local/

To simulate credentials/roles that would be available on Lambda, just pass in your Api creds VIA environment variables. ( for s3 access )

Cheers -JH

like image 131
John Avatar answered Sep 07 '25 19:09

John


I like the newish AWSLabs Go API Proxy for this: https://github.com/awslabs/aws-lambda-go-api-proxy

It allows you to write a standard HTTP server using your tools of choice (plain old go, Gin, Gorilla, etc), then run that server on Lambda. It has several benefits:

  • Removes almost all Lambda specific code/conventions from your codebase for more idiomatic go
  • Easily covert existing golang HTTP server to lambda execution mode
  • Support parallel execution modes. I use a ENV variable to switch between them in example below. I use straight HTTP for local dev, and Lambda for deployment.

Example app with 1 function

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "os"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/awslabs/aws-lambda-go-api-proxy/httpadapter"
)

// map of our functions, which can be handled as HTTP or Lambda
var functions = map[string]http.HandlerFunc{
    "ping": PingHandler,
}

func main() {
    for name, handler := range functions {
        path := fmt.Sprintf("/%s", name)
        http.HandleFunc(path, handler)
    }

    httpPort := os.Getenv("HTTP_PORT")
    if httpPort == "" {
        log.Println("Starting Lambda Handler")
        lambda.Start(httpadapter.New(http.DefaultServeMux).ProxyWithContext)
    } else {
        log.Printf("Starting HTTP server on port %s\n", httpPort)
        formattedPort := fmt.Sprintf(":%s", httpPort)
        log.Fatal(http.ListenAndServe(formattedPort, nil))
    }
}

// Sample Func
func PingHandler(w http.ResponseWriter, r *http.Request) {
    io.WriteString(w, "pong")
}

Running as HTTP is easy: go build -out main && HTTP_PORT=7575 ./main. This is super fast, making it easy to rebuilt and test.

You can still build and run in a docker container to test Lambda mapping before deploying using the steps others have mentioned.

like image 38
scosman Avatar answered Sep 07 '25 20:09

scosman