How to develop a Lambda Function in the local environment with GO using Localstack?
Most developers who use AWS stack have the same problem in their local development environment. The problem is we couldn't use the AWS Services in the local environment, so we couldn't develop comfortably. At this point, I want you to meet Localstack.
Before starting, I'm using macOS Silicon(M1) right now. And the examples and commands I will use are suitable for M1.
What is Localstack?
Localstack is a fully functional local cloud stack that has the most popular services that we need. That has enterprise and community editions. But don't worry; the community edition includes the most important APIs for mocking the cloud services.
How do I use Localstack?
Most users use Docker. Also, you could install it in your system if you want. In this post, I'll use Docker.
So, What do we need?
- Docker Desktop
- NodeJS
- Go
- AWS CLI
If you don't have Docker Desktop still, please follow this link.
You could install NodeJS to your macOS system with the following brew command.
$ brew install node
Now, we need the following things.
$ brew install awscli
$ brew install go
Okay, Let's create a scenario.
We will make a basic integration between Lambda and SQS. We'll send a message to SQS, and then SQS'll trigger Lambda. Here's the schema;
Let's make a Golang environment
$ mkdir golang-localstack
$ cd golang-localstack
$ go mod init golang-localstack
$ touch main.go
Install the AWS Lambda Package
$ go get github.com/aws/aws-lambda-go/lambdacontext@v1.27.0
The "go.mod" file would be like the following;
module golang-localstack
go 1.17
require github.com/aws/aws-lambda-go v1.27.0 // indirect
Finally, make a basic Go function.
package main
import (
"context"
"encoding/json"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-lambda-go/lambdacontext"
"log"
)
func handler(ctx context.Context, event events.SQSEvent) {
lc, _ := lambdacontext.FromContext(ctx)
log.Print(lc.Identity.CognitoIdentityPoolID)
eventJson, _ := json.MarshalIndent(event, "", " ")
log.Printf("EVENT: %s", eventJson)
}
func main() {
lambda.Start(handler)
}
After all, there is only one thing left. It's a deployment Go function to Localstack.
To deployment, We'll use Serverless Framework in the project.
Let's create a simple serverless.yml file. First, we have to install the following packages.
$ npm install -g serverless
$ npm install --save serverless-deployment-bucket
$ npm install --save serverless-localstack
The serverless.yml file must be like the following thing.
service: localstack
plugins:
- serverless-localstack
- serverless-deployment-bucket
provider:
name: aws
runtime: go1.x
stage: ${opt:stage, 'local'}
region: us-east-1
deploymentBucket:
name: ${self:service}-${opt:stage}-deployment-bucket
custom:
localstack:
debug: true
stages:
- local
package:
exclude:
- ./**
include:
- ./bin/**
resources:
Resources:
QueueName:
Type: "AWS::SQS::Queue"
Properties:
QueueName: "QueueName"
functions:
consumer:
handler: bin/app
events:
- sqs:
arn:
Fn::GetAtt:
- QueueName
- Arn
Here's what we've done so far
- Install tools
- Create a Go function
- Install Serverless File
Next up, we'll create a Localstack environment
We need a docker-compose.yml file to build a Localstack. Here's a simple docker-compose.yml file.
version: "3.8"
services:
localstack:
image: localstack/localstack:latest
network_mode: bridge
privileged: true
ports:
- "127.0.0.1:53:53"
- "127.0.0.1:53:53/udp"
- "127.0.0.1:443:443"
- "127.0.0.1:4510-4530:4510-4530"
- "127.0.0.1:4566:4566"
- "127.0.0.1:4571:4571"
environment:
- LOCALSTACK_HOSTNAME=localhost
- HOST_TMP_FOLDER=/tmp/localstack
- DOCKER_HOST=unix:///var/run/docker.sock
- DEFAULT_REGION=us-east-1
- LAMBDA_EXECUTOR=docker
- DEBUG=0
volumes:
- "${TMPDIR:-/tmp}/localstack:/tmp/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
And, run.
$ docker-compose up -d
Now, We build a Go App. GOOS must be linux and GOARCH must be amd64. Because Localstack doesn't support the others.
$ GOOS=linux GOARCH=amd64 go build -o bin/app .
Now, We can deploy the app to Localstack.
$ serverless deploy --stage local
And, here we are...
Well, How could we send a message to the SQS service?
There are many ways to send a message to SQS. You could use AWS SDK in any language if you want. I'll use AWS-CLI at the moment.
First, We need an SQS Queue in Localstack. Let's list the queues.
$ aws --endpoint-url=http://localhost:4566 sqs list-queues
And output;
{
"QueueUrls": [
"http://localhost:4566/000000000000/QueueName"
]
}
Perfect, We have a queue. Now We can send a message.
$ aws --endpoint-url=http://localhost:4566 sqs send-message --queue-url http://localhost:4566/000000000000/QueueName --message-body 'Localstack & Golang !!'
And output;
{
"MD5OfMessageBody": "972f9fcb6f04fa1d1376584503edbe32",
"MessageId": "5f5b56c0-5d12-45ad-df6d-4b7e467760dc"
}
Let's take a look at the log groups;
The following code will list the log groups;
$ aws --endpoint-url http://localhost:4566 logs describe-log-groups
Here we are. Our log group name is "/aws/lambda/localstack-local consumer"
{
"logGroups": [
{
"logGroupName": "/aws/lambda/localstack-local-consumer",
"creationTime": 1638126446317,
"metricFilterCount": 0,
"arn": "arn:aws:logs:us-east-1:000000000000:log-group:/aws/lambda/localstack-local-consumer",
"storedBytes": 43626
}
]
}
Let's tail the logs.
$ aws --endpoint-url http://localhost:4566 logs tail /aws/lambda/localstack-local-consumer
Cheers!