9

I am using docker compose to create two containers one for dynamodb local and one for nodejs express app.

docker-compose.dev.yml

version: '3'

services:
  dynamodb-local:
    command: "-jar DynamoDBLocal.jar -sharedDb -optimizeDbBeforeStartup -dbPath ./data"
    image: "amazon/dynamodb-local:latest"
    container_name: dynamodb-local
    ports:
      - "8000:8000"
    volumes:
      - "./docker/dynamodb:/home/dynamodblocal/data"
    working_dir: /home/dynamodblocal
    networks:
      - dynamodb-network

  node-app:
    depends_on:
        - dynamodb-local
    container_name: dev-nodejs-backend
    ports:
      - '3000:3000'
    volumes:
      - .:/usr/src/node-app
    environment:
      AWS_ACCESS_KEY_ID: 'DUMMYIDEXAMPLE'
      AWS_SECRET_ACCESS_KEY: 'DUMMYEXAMPLEKEY'
    networks:
      - dynamodb-network
    command: yarn dev -L

networks:
  dynamodb-network:
    driver: bridge

Dockerfile

FROM node:alpine

RUN mkdir -p /usr/src/node-app && chown -R node:node /usr/src/node-app

WORKDIR /usr/src/node-app

COPY package.json yarn.lock ./

USER node

RUN yarn install --pure-lockfile

COPY --chown=node:node . .

EXPOSE 3000

model.js

var AWS = require('aws-sdk');

AWS.config.update({
  accessKeyId: 'YOUR-ACCESSKEYID' ,
  secretAccessKey: 'YOUR-SECRETACCESSKEY' ,
  region: "localhost",
  endpoint: 'http://localhost:8000',
});

const DynamoDB = new AWS.DynamoDB();
var docClient = new AWS.DynamoDB.DocumentClient();

var table = 'URL';

const createTable = async () => {
  var params = {
    TableName : table,
    KeySchema: [
        { AttributeName: "hash", KeyType: "HASH"},  //Partition key
    ],
    AttributeDefinitions: [       
        { AttributeName: "hash", AttributeType: "S" },
    ],
    ProvisionedThroughput: {      
        ReadCapacityUnits: 5, 
        WriteCapacityUnits: 5
    }
};
  const result = await DynamoDB.createTable(params).promise();
  return result;
}

The error on console

UnknownEndpoint: Inaccessible host: `localhost'. This service may not be available in the `localhost' region.
at Request.ENOTFOUND_ERROR (/usr/src/node-app/node_modules/aws-sdk/lib/event_listeners.js:507:46)
at Request.callListeners (/usr/src/node-app/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/usr/src/node-app/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/usr/src/node-app/node_modules/aws-sdk/lib/request.js:688:14)
at ClientRequest.error (/usr/src/node-app/node_modules/aws-sdk/lib/event_listeners.js:339:22)
at ClientRequest.<anonymous> (/usr/src/node-app/node_modules/aws-sdk/lib/http/node.js:96:19)
at ClientRequest.emit (node:events:379:20)
at ClientRequest.EventEmitter.emit (node:domain:470:12)
at Socket.socketErrorListener (node:_http_client:462:9)
at Socket.emit (node:events:379:20)
at Socket.EventEmitter.emit (node:domain:470:12)
at emitErrorNT (node:internal/streams/destroy:188:8)
at emitErrorCloseNT (node:internal/streams/destroy:153:3)
at processTicksAndRejections (node:internal/process/task_queues:81:21) {
code: 'UnknownEndpoint',
region: 'localhost',
hostname: 'localhost',
retryable: true,
originalError: Error: connect ECONNREFUSED 127.0.0.1:8000
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1139:16) {
errno: -111,
code: 'NetworkingError',
syscall: 'connect',
address: '127.0.0.1',
port: 8000,
region: 'localhost',
hostname: 'localhost',
retryable: true,
time: 2021-02-05T14:23:15.559Z
},
time: 2021-02-05T14:23:15.559Z
}

Dynamodb local is running on port 8000, but I am unable to connect it from my express app. Is there anything I can change in compose file or it is some different error?

Maurice
  • 11,482
  • 2
  • 25
  • 45
dhruv mehta
  • 93
  • 1
  • 1
  • 6

3 Answers3

9

I suspect that your problem is in here:

AWS.config.update({
  accessKeyId: 'YOUR-ACCESSKEYID' ,
  secretAccessKey: 'YOUR-SECRETACCESSKEY' ,
  region: "localhost",
  endpoint: 'http://localhost:8000',
});

When you try to connect to localhost from inside of a container, it will try to connect to localhost from the perspective of that container - which is the container itself.

The container thinks it's its own separate machine, thus localhost refers to the container itself. This doesn't work, because DynamoDB is not running inside your node container.

What you want to happen is that the container connects to either port 8000 or the docker host or the dynamodb-local container. Since you're using a bridge network, the latter should be easy to achieve - set the endpoint to http://dynamodb-local:8000/. Docker should provide your container with DNS-resolution for the names of other containers within its network. I suggest you check out the docs for more on bridge networking.

tl;dr: this might do the trick

AWS.config.update({
  accessKeyId: 'YOUR-ACCESSKEYID' ,
  secretAccessKey: 'YOUR-SECRETACCESSKEY' ,
  region: "localhost",
  endpoint: 'http://dynamodb-local:8000',
});
Maurice
  • 11,482
  • 2
  • 25
  • 45
  • I also have ta add the required permissioin to create database file. See this question for more info: https://stackoverflow.com/a/53132375/9858016 – dhruv mehta Feb 08 '21 at 05:27
  • Thanks, i spent hours trying to solve it, and it was actually this simple. – trsp Sep 25 '22 at 19:11
4

You need to set endpoint as “http://host.docker.internal:8000" because AWS SAM is running on docker but DynamoDB is running on localhost:8000.

If you put only “localhost:8000” then SAM will connect to localhost of the container whereas “host.docker.internal” will connect to localhost of the host

Nguyen Duc
  • 41
  • 1
3

I had the same error output while using s3 with localstack. It is important to check their troubleshooting page, in my case it was solved by a s3ForcePathStyle property

const s3 = new SDK.S3({
  endpoint: "http://localhost:4566",
  s3ForcePathStyle: true,
});
Felquis
  • 101
  • 1
  • 4
  • The `s3ForcePathStyle` was exactly my problem when using locally with [form3-s3rver](https://github.com/form3tech-oss/form3-s3rver) – jackofallcode Feb 22 '22 at 09:06