One of the functions I want to test locally connects to DynamoDB, which I'm running inside a Docker container locally.
I've installed the serverless-offline plugin, as suggested: npm install serverless-offline@next --save-dev
I've created the table using the command
aws dynamodb create-table --table-name Cart \
--attribute-definitions \
AttributeName=UserID,AttributeType=S \
--key-schema \
AttributeName=UserID,KeyType=HASH \
--provisioned-throughput \
ReadCapacityUnits=10,WriteCapacityUnits=5 \
--endpoint-url http://<my-ip>:8000 --region us-west-2
The code that runs inside my function, which lists the tables is
awsSession := session.Must(session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
Endpoint: aws.String("http://<my ip>:8000"),
}))
log.Printf("%+v\n", *awsSession.Config.Endpoint)
log.Printf("%+v\n", *awsSession.Config.Region)
dbs := dynamodb.New(awsSession)
lsi := &dynamodb.ListTablesInput{
Limit: aws.Int64(10),
}
lso, err := dbs.ListTables(lsi)
if err != nil {
log.Println(err.Error())
}
for _, val := range lso.TableNames {
log.Printf("Table: %s", *val)
}
When I run my Lambda functions with serverless-offline, the response doesn't list any tables
$ sls offline --useDocker
offline: Starting Offline: dev/us-west-2.
offline: Offline [http for lambda] listening on http://localhost:3002
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ GET | http://localhost:3000/dev/hello โ
โ GET | http://localhost:3000/dev/world โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
offline:
offline: [HTTP] server ready: http://localhost:3000 ๐
offline:
offline: Enter "rp" to replay the last request
offline:
offline: GET /dev/hello (ฮป: hello)
Lambda API listening on port 9001...
START RequestId: e41b7edd-7097-1cbc-c252-bf2870e80557 Version: $LATEST
2020/02/06 23:03:18 http://<my ip>:8000
2020/02/06 23:03:18 us-west-2
END RequestId: e41b7edd-7097-1cbc-c252-bf2870e80557
REPORT RequestId: e41b7edd-7097-1cbc-c252-bf2870e80557 Init Duration: 201.70 ms Duration: 22.54 ms Billed Duration: 100 ms Memory Size: 1024 MB Max Memory Used: 25 MB
When I run the exact same function with the AWS SAM CLI, the response has the table I expect:
sam local start-api -t template.yaml --region us-west-2
Mounting hello at http://127.0.0.1:3000/hello [GET]
Mounting world at http://127.0.0.1:3000/world [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2020-02-06 15:03:37 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
Invoking hello (go1.x)
Fetching lambci/lambda:go1.x Docker container image......
Mounting /Users/lstigter/repos/github.com/retgits/playgrounds/go/bin as /var/task:ro,delegated inside runtime container
START RequestId: 390b1ca2-41b5-1444-d405-c46f39ca88a1 Version: $LATEST
2020/02/06 23:03:42 http://<my ip>:8000
2020/02/06 23:03:42 us-west-2
2020/02/06 23:03:42 Table: Cart
END RequestId: 390b1ca2-41b5-1444-d405-c46f39ca88a1
REPORT RequestId: 390b1ca2-41b5-1444-d405-c46f39ca88a1 Init Duration: 201.67 ms Duration: 16.63 ms Billed Duration: 100 ms Memory Size: 256 MB Max Memory Used: 25 MB
I can't figure out why the exact same code reacts differently when I run it with serverless-offline as opposed to using the SAM CLI.
My template.yaml file (for the SAM CLI) is
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
hello:
Type: AWS::Serverless::Function
Properties:
Handler: hello
Runtime: go1.x
CodeUri: bin/
FunctionName: hello
MemorySize: 256
Timeout: 10
Tracing: Active
Policies:
- AWSLambdaRole
Events:
HelloAPI:
Type: Api
Properties:
Path: /hello
Method: GET
world:
Type: AWS::Serverless::Function
Properties:
Handler: world
Runtime: go1.x
CodeUri: bin/
FunctionName: world
MemorySize: 256
Timeout: 10
Tracing: Active
Policies:
- AWSLambdaRole
Events:
WorldAPI:
Type: Api
Properties:
Path: /world
Method: GET
with my serverless.yaml being:
service: go
frameworkVersion: '>=1.28.0 <2.0.0'
provider:
name: aws
runtime: go1.x
region: us-west-2
package:
exclude:
- ./**
include:
- ./bin/**
functions:
hello:
handler: bin/hello
events:
- http:
path: hello
method: get
world:
handler: bin/world
events:
- http:
path: world
method: get
plugins:
- serverless-offline
Any thoughts are appreciated
Isn't <my-ip> inaccessible from the container?
Please try to use host.docker.internal (is special DNS name which resolves to the internal IP address used by the host) instead of <my-ip>.
awsSession := session.Must(session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
Endpoint: aws.String("http://host.docker.internal:8000"),
}))
With host.docker.internal I get the exact same response. The code works with AWS SAM CLI, but not with serverless-offline. I'm really wondering where the issue comes from as both seem to get their offline functionality from the container lambci/lambda:go1.x
@retgits Thank you for your report.
OK, I think it is due to the DynamoDB specification. DynamoDB Local separates database files for each credentail and region.
AWS SAM CLI can load a local credential file as well as AWS CLI, but serverless-offline docker handler does not yet support it.
Please try to run DynamoDB Local with -sharedDb option.
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.UsageNotes.html#DynamoDBLocal.CommandLineOptions
@frozenbonito that was indeed the issue! Thanks a lot for the help and patience!!