Serverless-offline: Connecting to local DynamoDB Local gives different results

Created on 7 Feb 2020  ยท  4Comments  ยท  Source: dherault/serverless-offline

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

question

All 4 comments

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!!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Ali-Dalal picture Ali-Dalal  ยท  4Comments

Dong9769 picture Dong9769  ยท  4Comments

dnalborczyk picture dnalborczyk  ยท  3Comments

stunningpixels picture stunningpixels  ยท  3Comments

adambiggs picture adambiggs  ยท  4Comments