Create a GO Lambda Function (2024/al2)

To create a GO app the see Chapter Simple programm.

Let`s look at the source in /lambda-go/simple-lambda-al2

  • go.mod
  • go.sum
  • main.go
  • Taskfile.yml
  • testdata / event.json

Main

 1: package main
 2: 
 3: import (
 4: 	"context"
 5: 	"fmt"
 6: 	"github.com/aws/aws-lambda-go/lambda"
 7: )
 8: 
 9: type MyEvent struct {
10: 	Name string `json:"name"`
11: }
12: 
13: func HandleRequest(ctx context.Context, name MyEvent) (string, error) {
14: 	return fmt.Sprintf("Hiho %s!", name.Name), nil
15: }
16: 
17: func main() {
18: 	lambda.Start(HandleRequest)
19: }
20: 
 1: package main
 2: 
 3: import (
 4: 	"context"
 5: 	"fmt"
 6: 	"github.com/aws/aws-lambda-go/lambda"
 7: )
 8: 
 9: type MyEvent struct {
10: 	Name string `json:"name"`
11: }
12: 
13: func HandleRequest(ctx context.Context, name MyEvent) (string, error) {
14: 	return fmt.Sprintf("Hiho %s!", name.Name), nil
15: }
16: 
17: func main() {
18: 	lambda.Start(HandleRequest)
19: }
20: 

The handler

In line 18 the main function calls the lambda handler. This function is imported in line 6 from “github.com/aws/aws-lambda-go/lambda”.

This handler, here in line 13 is then called with a context and a JSON event.

Lambda call

The input for HandleRequest is a context, from which we can get the lambdacontext. The context stores things like the FunctionName, the AwsRequestID and other things.

The input, which is the payload of the invocation has to be defined in a struct, here MyEvent in line 9.

The event

If you invoke Lambda with an AWS event, all the events are defined in AWS Event definitions.

Working with own events, you define the struct.

So with:

9 type MyEvent struct {
10         Name string `json:"name"`
11 }

the input event could be:

{
  "name": "megaproaktiv"
}

Build & package the app

  1. Download dependencies

    In the directory with main go do:

    go mod init simplelambda
    go mod tidy
    

    This downloads the dependencies.

  2. Build

    mkdir -p dist
    env GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -tags lambda.norpc -ldflags="-s -w" -o ./dist/bootstrap main.go
    
  3. change file execution permission

    chmod +x ./dist/bootstrap
    
  4. package the file in a zip

    Lambda upload only accept zipped files, so zip it:

    cd ./dist && zip bootstrap.zip bootstrap && cd ..
    

    Output:

    updating: bootstrap (deflated 59%)
    
Part meaning
env GOOS=linux  build for linux operation system
GOARCH=arm64  build for arm. You need this e.g. if you are working with an intel mac, which is intel based
go build  build call
-ldflags="-s -w"  See go help build, omit the symbol table, debug information to get a smaller binary
-o ./dist/bootstrap  ouput in directory “dist” (short for distribution), file bootstrap
main.go  the go file to build

You may need to compile packages with CGO_ENABLED=0 set on Linux.

The bootstrap file ist the first file Lambda is calling. You will see the bootstrap binary also in the Lambda web console.

The build target

With go you can build the binary for different operations systems (os). Without any GOOS/GOARCH GO will take the current os and architecture, so that the app runs on your machine.

With AWS Lambda, the GOOS is always linux. The GOARCH can be amd64 for intel or arm for Gravition.

Deploy the function code

We deploy the code directly from the AWS CLI with:

  1. Deploy with AWS CLI

    aws lambda update-function-code --function-name  gosimple --zip-file fileb://./dist/bootstrap.zip
    

    The name gosimple has to be exactly the name you set on the creation of the lambda function.

    Output:

{
    "FunctionName": "gosimple",
    "FunctionArn": "arn:aws:lambda:eu-central-1:123456789012:function:gosimple",
    "Runtime": "provided.al2",
    "Role": "arn:aws:iam::123456789012:role/service-role/gosimple-role-s84ouowk",
    "Handler": "main",
    "CodeSize": 1950171,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2023-08-13T17:22:33.000+0000",
    "CodeSha256": "04S8R+trBPigZXxquMTaYIs8kQK3lwqaZar+871UBkA=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "5b3bbea4-5e10-4d76-b3ae-a79a2d14a5e7",
    "State": "Active",
    "LastUpdateStatus": "InProgress",
    "LastUpdateStatusReason": "The function is being created.",
    "LastUpdateStatusReasonCode": "Creating",
    "PackageType": "Zip",
    "Architectures": [
        "arm64"
    ],
    "EphemeralStorage": {
        "Size": 512
    },
    "SnapStart": {
        "ApplyOn": "None",
        "OptimizationStatus": "Off"
    },
    "RuntimeVersionConfig": {
        "RuntimeVersionArn": "arn:aws:lambda:eu-central-1::runtime:904c897d14442788d50f990427bbbf4e8df27838f33ffdc86013c6c1389b2bd4"
    }
}

The direct deployment has limits on the file size. Deploy from S3 or with Container images for larger files. See AWS Lambda limits for size limits.

If you prefer the console, you find the upload button in the “code” tab:

Console upload

Call the function

In the source code, there is a json file in testdata/event.json. We give the AWS CLI Lambda invoke call the payload event.json as input parameter. Because we use the fileb: function, it does not have to be base64 encoded.

So this call invokes the lambda from the AWS CLI:

aws lambda invoke --function-name gosimple --payload fileb://testdata/event.json testdata/lambda.out

You get the output from the AWS Lambda invoke call as on output:

{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

This is not the answer from the Lambda function, but the answer from the Lambda services, which tells you, that the invocation succeeded.

The output from the Lambda function is in `testdata/lambda.out``

cat testdata/lambda.out
"Hiho megaproaktiv!"%

Automating with task

In the source dir there ist the Taskfile.yml.

The calls are included there, so you can:

  1. Deploy

    task deploy
    

For deploy i define a variable NAME, because the function name is often used in the task file. And you can also get this name from AWS Systems Manager Parameter Store or CloudFormation output.

 1: vars:
 2:   NAME: gosimple
 3: 
 4:   deploy:
 5:     desc: Deploy only Lambda function
 6:     deps: [build]
 7:     cmds:
 8:       - aws lambda update-function-code --function-name  gosimple --zip-file fileb://./dist/bootstrap.zip

This depends on the build task:

 1:   build:
 2:     desc: build go
 3:     cmds:
 4:       - mkdir -p dist
 5:       - env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./dist/bootstrap main.go
 6:       - chmod +x ./dist/main
 7:       - cd ./dist && zip bootstrap.zip bootstrap
  1. Invoke

    task invoke
    

The creation and deployment with the CDK, see the Chapter Lambda with CDK overview is much better suited for complex deployments. But as you have seen here, the setup for single functions is faster.

See also

Source

See the full source on github.

Sources