Introduction#

GitHub this note shows

  • Build executable on Amazon Linux 2023 then deploy
  • Buindling in CDK
  • CDK golang lambda alpha

Build Executable#

For Amazon Linux 2023 local and runtime on x86_64, let build an executable file

GOOS=linux GOARCH=amd64 go build -tags lambda.norpc -o bootstrap main.go

Then deploy it using zip or CDK stack. Please pay attention to naming convetion for handler, and the executable named bootstrap should be in lambda directory. Since local machine is Amazon Linux 2023, then run time should be the same.

export class LambdaDemoStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props)
new cdk.aws_lambda.Function(this, 'LambdaGoDemo', {
functionName: 'LambdaGoDemo',
handler: 'bootstrap',
code: cdk.aws_lambda.Code.fromAsset(path.join(__dirname, './../lambda/')),
memorySize: 521,
timeout: cdk.Duration.seconds(15),
runtime: cdk.aws_lambda.Runtime.PROVIDED_AL2023,
architecture: Architecture.X86_64
})
}
}

Lambda logic

package main
import (
"context"
"fmt"
"github.com/aws/aws-lambda-go/lambda"
)
type MyEvent struct {
Name string `json:"name"`
}
func HandleRequest(ctx context.Context, event *MyEvent) (*string, error) {
if event == nil {
return nil, fmt.Errorf("received nil event")
}
message := fmt.Sprintf("Hello %s!", event.Name)
return &message, nil
}
func main() {
lambda.Start(HandleRequest)
}

ECR Image#

Let create a stack

new cdk.aws_lambda.Function(this, 'LambdaGoEcr', {
functionName: 'LamdbaGoEcr',
code: cdk.aws_lambda.EcrImageCode.fromAssetImage(
path.join(__dirname, './../lambda')
),
memorySize: 521,
timeout: cdk.Duration.seconds(15),
runtime: cdk.aws_lambda.Runtime.FROM_IMAGE,
handler: cdk.aws_lambda.Handler.FROM_IMAGE,
architecture: Architecture.X86_64
})

Dockerfile

FROM golang:1.21.5 as build
WORKDIR /helloworld
# Copy dependencies list
COPY go.mod go.sum ./
# Build with optional lambda.norpc tag
COPY main.go .
RUN go build -tags lambda.norpc -o main main.go
# Copy artifacts to a clean image
FROM public.ecr.aws/lambda/provided:al2023
COPY --from=build /helloworld/main ./main
ENTRYPOINT [ "./main" ]

Lambda logic

package main
import (
"context"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func handler(ctx context.Context, event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
response := events.APIGatewayProxyResponse{
StatusCode: 200,
Body: "\"Hello from Lambda!\"",
}
return response, nil
}
func main() {
lambda.Start(handler)
}

CDK Bundling#

Let create a lambda stack with bundling which means CDK will use an Docker image to bundle the go application

new cdk.aws_lambda.Function(this, 'LambdaGoBundling', {
functionName: 'LambdaGoBundling',
handler: 'bootstrap',
code: cdk.aws_lambda.Code.fromAsset(path.join(__dirname, './../lambda/'), {
bundling: {
// image: cdk.aws_lambda.Runtime.PROVIDED_AL2023.bundlingImage,
image: cdk.DockerImage.fromRegistry('golang:1.21.5'),
command: [
'bash',
'-c',
'GOCACHE=/tmp go mod tidy && GOCACHE=/tmp GOOS=linux GOARCH=amd64 go build -tags lambda.norpc -o /asset-output/bootstrap'
]
}
}),
memorySize: 512,
timeout: cdk.Duration.seconds(15),
runtime: cdk.aws_lambda.Runtime.PROVIDED_AL2023,
architecture: Architecture.X86_64
})

Full lambda stack here

lambda-golang-stack.ts
import * as cdk from 'aws-cdk-lib'
import { Architecture } from 'aws-cdk-lib/aws-lambda'
import { Construct } from 'constructs'
import * as path from 'path'
export class LambdaDemoStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props)
// deploy bin executable
new cdk.aws_lambda.Function(this, 'LambdaGoDemo', {
functionName: 'LambdaGoDemo',
handler: 'bootstrap',
code: cdk.aws_lambda.Code.fromAsset(path.join(__dirname, './../lambda/')),
memorySize: 521,
timeout: cdk.Duration.seconds(15),
runtime: cdk.aws_lambda.Runtime.PROVIDED_AL2023,
architecture: Architecture.X86_64
})
// deploy via ecr
new cdk.aws_lambda.Function(this, 'LambdaGoEcr', {
functionName: 'LamdbaGoEcr',
code: cdk.aws_lambda.EcrImageCode.fromAssetImage(
path.join(__dirname, './../lambda')
),
memorySize: 521,
timeout: cdk.Duration.seconds(15),
runtime: cdk.aws_lambda.Runtime.FROM_IMAGE,
handler: cdk.aws_lambda.Handler.FROM_IMAGE,
architecture: Architecture.X86_64
})
// cdk local bundling
new cdk.aws_lambda.Function(this, 'LambdaGoBundling', {
functionName: 'LambdaGoBundling',
handler: 'bootstrap',
code: cdk.aws_lambda.Code.fromAsset(
path.join(__dirname, './../lambda/'),
{
bundling: {
// image: cdk.aws_lambda.Runtime.PROVIDED_AL2023.bundlingImage,
image: cdk.DockerImage.fromRegistry('golang:1.21.5'),
command: [
'bash',
'-c',
'GOCACHE=/tmp go mod tidy && GOCACHE=/tmp GOOS=linux GOARCH=amd64 go build -tags lambda.norpc -o /asset-output/bootstrap'
]
}
}
),
memorySize: 512,
timeout: cdk.Duration.seconds(15),
runtime: cdk.aws_lambda.Runtime.PROVIDED_AL2023,
architecture: Architecture.X86_64
})
}
}

And the main.go

main.go
package main
import (
"context"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func handler(ctx context.Context, event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
response := events.APIGatewayProxyResponse{
StatusCode: 200,
Body: "\"Hello from Lambda!\"",
}
return response, nil
}
func main() {
lambda.Start(handler)
}

Reference#