将AWS SAM Local与docker中的dynamodb连接起来

时间:2018-02-22 11:25:05

标签: amazon-web-services docker amazon-dynamodb aws-sam-cli

我已经使用AWS sam本地设置了api网关/ aws lambda对,并确认我可以在运行后成功调用它

sam local start-api

然后我在docker容器中添加了一个本地dynamodb实例,并使用aws cli在其上创建了一个表

但是,将代码添加到lambda以写入我收到的dynamodb实例:

  

2018-02-22T11:13:16.172Z ed9ab38e-fb54-18a4-0852-db7e5b56c8cd错误:   无法写入表:{" message":" connect ECONNREFUSED   0.0.0.0:8000","code":"NetworkingError","errno":"ECONNREFUSED","syscall& #34;:"连接""地址":" 0.0.0.0""端口":8000,"区域& #34;:" EU-西-2""主机名":" 0.0.0.0""重试":真,& #34;时间":" 2018-02-22T11:13:16.165Z"}   从命令编写事件:   {"名称":"测试""地理位置":" XYZ""类型":" createDestination"}结束   RequestId:ed9ab38e-fb54-18a4-0852-db7e5b56c8cd

我在网上看到您可能需要连接到同一个docker网络,因此我创建了一个网络docker network create lambda-local并将我的启动命令更改为:

sam local start-api --docker-network lambda-local

docker run -v "$PWD":/dynamodb_local_db -p 8000:8000 --network=lambda-local cnadiminti/dynamodb-local:latest

但仍然收到相同的错误

sam local正在打印2018/02/22 11:12:51 Connecting container 98b19370ab92f3378ce380e9c840177905a49fc986597fef9ef589e624b4eac3 to network lambda-local

我使用以下方法创建dynamodbclient:

const AWS = require('aws-sdk')
const dynamodbURL = process.env.dynamodbURL || 'http://0.0.0.0:8000'
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID || '1234567'
const awsAccessKey = process.env.AWS_SECRET_ACCESS_KEY || '7654321'
const awsRegion = process.env.AWS_REGION || 'eu-west-2'

console.log(awsRegion, 'initialising dynamodb in region: ')

let dynamoDbClient
const makeClient = () => {
  dynamoDbClient = new AWS.DynamoDB.DocumentClient({
    endpoint: dynamodbURL,
    accessKeyId: awsAccessKeyId,
    secretAccessKey: awsAccessKey,
    region: awsRegion
  })
  return dynamoDbClient
}

module.exports = {
  connect: () => dynamoDbClient || makeClient()
}

并检查dynamodbclient,我的代码正在创建节目

DocumentClient {
  options:
   { endpoint: 'http://0.0.0.0:8000',
     accessKeyId: 'my-key',
     secretAccessKey: 'my-secret',
     region: 'eu-west-2',
     attrValue: 'S8' },
  service:
   Service {
     config:
      Config {
        credentials: [Object],
        credentialProvider: [Object],
        region: 'eu-west-2',
        logger: null,
        apiVersions: {},
        apiVersion: null,
        endpoint: 'http://0.0.0.0:8000',
        httpOptions: [Object],
        maxRetries: undefined,
        maxRedirects: 10,
        paramValidation: true,
        sslEnabled: true,
        s3ForcePathStyle: false,
        s3BucketEndpoint: false,
        s3DisableBodySigning: true,
        computeChecksums: true,
        convertResponseTypes: true,
        correctClockSkew: false,
        customUserAgent: null,
        dynamoDbCrc32: true,
        systemClockOffset: 0,
        signatureVersion: null,
        signatureCache: true,
        retryDelayOptions: {},
        useAccelerateEndpoint: false,
        accessKeyId: 'my-key',
        secretAccessKey: 'my-secret' },
     endpoint:
      Endpoint {
        protocol: 'http:',
        host: '0.0.0.0:8000',
        port: 8000,
        hostname: '0.0.0.0',
        pathname: '/',
        path: '/',
        href: 'http://0.0.0.0:8000/' },
     _clientId: 1 },
  attrValue: 'S8' }

此设置是否有效?我如何让他们互相交谈?

----编辑----

基于Twitter对话,值得一提(也许)我可以在CLI和Web shell中与dynamodb进行交互

dynamo db at the CLI

dynamodb web shell

6 个答案:

答案 0 :(得分:11)

非常感谢Heitor Lessa who answered me on Twitter使用示例repo

这指向了我的答案......

  • dynamodb的docker容器在我的上下文中是127.0.0.1 机器(这就是我可以与它互动的原因)

  • SAM local的docker容器在我的上下文中的127.0.0.1上 机

  • 但他们并非在127.0.0.1彼此的背景

所以:https://github.com/heitorlessa/sam-local-python-hot-reloading/blob/master/users/users.py#L14

指示我将我的连接代码更改为:

const AWS = require('aws-sdk')
const awsRegion = process.env.AWS_REGION || 'eu-west-2'

let dynamoDbClient
const makeClient = () => {
  const options = {
    region: awsRegion
  }
  if(process.env.AWS_SAM_LOCAL) {
    options.endpoint = 'http://dynamodb:8000'
  }
  dynamoDbClient = new AWS.DynamoDB.DocumentClient(options)
  return dynamoDbClient
}

module.exports = {
  connect: () => dynamoDbClient || makeClient()
}

重要的一行是:

if(process.env.AWS_SAM_LOCAL) {
  options.endpoint = 'http://dynamodb:8000'
}

从SAM本地docker容器的上下文中,dynamodb容器通过其名称公开

我的两个启动命令最终为:

docker run -d -v "$PWD":/dynamodb_local_db -p 8000:8000 --network lambda-local --name dynamodb cnadiminti/dynamodb-local

AWS_REGION=eu-west-2 sam local start-api --docker-network lambda-local

唯一的变化就是给dynamodb容器命名

答案 1 :(得分:9)

如果你在很多开发者的mac上使用sam-local,你应该可以使用

options.endpoint = "http://docker.for.mac.localhost:8000"

或者在较新的docker https://docs.docker.com/docker-for-mac/release-notes/#docker-community-edition-18030-ce-mac59-2018-03-26

上安装

options.endpoint = "http://host.docker.internal:8000"

而不是像上面保罗所做的那样做多个命令(但这可能更加平台无关?)。

答案 2 :(得分:2)

正如@Paul所提到的,这是关于在docker容器-lambda和数据库之间配置网络。

另一种对我有用的方法(使用docker-compose)。

docker-compose:

list1=[0,1,6,4,2,8]
list2=[10,20,30,40]
j=0
ans=[0]*len(list1)
for i in range(len(list1)):
    if list1[i] <= 4:
        ans[list1.index(list1[i])]+=list2[j]
        if(j<len(list2)):
            j+=1
    else:
        ans[i]+=list1[i]

print(ans)

然后,在version: '2.1' services: db: image: ... ports: - "3306:3306" networks: - my_network environment: ... volumes: ... networks: my_network: 之后运行docker-compose up将显示:

docker network ls

我的Docker容器名称为NETWORK ID NAME DRIVER SCOPE 7eb440d5c0e6 dev_my_network bridge local

我的js代码是:

dev_db_1

然后,运行const connection = mysql.createConnection({ host: "dev_db_1", port: 3306, ... }); 命令:

sam

堆栈:

  • Docker:18.03.1-ce
  • Docker撰写:1.21.1
  • MacOS HighSierra 10.13.6

答案 3 :(得分:1)

如果您使用LocalStack运行DynamoDB,我相信将LocalStack网络用于SAM的正确命令是:

printf("%d\n",1234567890123456789)

在您的代码中,LocalStack主机名应为sam local start-api --env-vars env.json --docker-network localstack_default

localstack_localstack_1

但是,我使用const dynamoDbDocumentClient = new AWS.DynamoDB.DocumentClient({ endpoint: process.env.AWS_SAM_LOCAL ? 'http://localstack_localstack_1:4569' : undefined, }); 启动了LocalStack。使用docker-compose up CLI工具启动LocalStack可能会导致标识符不同。

答案 4 :(得分:1)

SAM在后​​台启动一个docker容器lambci/lambda,例如,如果您有另一个容器托管dynamodb或您要将lambda连接到的任何其他服务,那么您应该两者都在同一网络

假设dynamodb(注意--name,现在是端点)

docker run -d -p 8000:8000 --name DynamoDBEndpoint amazon/dynamodb-local

这将导致类似

0e35b1c90cf0....

要知道在哪个网络内创建该网络:

docker inspect 0e35b1c90cf0

它应该给您类似

...
Networks: {
     "services_default": {//this is the <<myNetworkName>>

....

如果您了解自己的网络,并希望将Docker容器放入特定网络中,则可以保存上述步骤,并在使用--network选项启动容器时在一个命令中执行此操作

docker run -d -p 8000:8000 --network myNetworkName --name DynamoDBEndpoint amazon/dynamodb-local

重要提示:您的lambda代码现在应该具有到DynamoDBEndpoint的发电机端点了。

例如:

if(process.env.AWS_SAM_LOCAL) {
  options.endpoint = 'http://DynamoDBEndpoint:8000'
}

测试所有内容:

使用lambci:lambda

这应该只列出其他dynamodb容器内的所有表

docker run -ti --rm --network myNetworkName lambci/lambda:build-go1.x \
   aws configure set aws_access_key_id "xxx" && \
   aws configure set aws_secret_access_key "yyy" &&  \
   aws --endpoint-url=http://DynamoDBEndpoint:4569 --region=us-east-1 dynamodb list-tables

或调用一个函数:(转到示例,与NodeJS相同)

#Golang
docker run --rm -v "$PWD":/var/task lambci/lambda:go1.x handlerName '{"some": "event"}'
#Same for NodeJS 
docker run --rm -v "$PWD":/var/task lambci/lambda:nodejs10.x index.handler

有关lambci / lambda的更多信息,请参见here

使用SAM(使用相同的容器lmabci/lambda):

sam local invoke --event myEventData.json --docker-network myNetworkName MyFuncName

如果您想查看更多详细信息,可以随时使用--debug选项。

或者,您也可以使用http://host.docker.internal:8000来轻松使用docker,该URL在内部保留,可让您访问主机,但请确保暴露端口8000当您启动dynamodb容器时。尽管这很容易,但并非在所有操作系统中都可以使用。有关此功能的更多详细信息,请检查docker documentation

答案 5 :(得分:1)

其他答案对我来说过于复杂/不清楚。以下是我想出了。

步骤1:使用docker-compose使DynamoDB本地在自定义网络上运行

docker-compose.yml

请注意,网络名称abp-sam-backend,服务名称dynamodynamo服务正在使用backend网络。

version: '3.5'

services:
  dynamo:
    container_name: abp-sam-nestjs-dynamodb
    image: amazon/dynamodb-local
    networks:
      - backend
    ports:
      - '8000:8000'
    volumes:
      - dynamodata:/home/dynamodblocal
    working_dir: /home/dynamodblocal
    command: '-jar DynamoDBLocal.jar -sharedDb -dbPath .'

networks:
  backend:
    name: abp-sam-backend

volumes:
  dynamodata: {}

通过以下方式启动DyanmoDB本地容器:

docker-compose up -d dynamo

步骤2:编写代码以处理本地DynamoDB端点

import { DynamoDB, Endpoint } from 'aws-sdk';

const ddb = new DynamoDB({ apiVersion: '2012-08-10' });

if (process.env['AWS_SAM_LOCAL']) {
  ddb.endpoint = new Endpoint('http://dynamo:8000');
} else if ('local' == process.env['APP_STAGE']) {
  // Use this when running code directly via node. Much faster iterations than using sam local
  ddb.endpoint = new Endpoint('http://localhost:8000');
}

注意,我使用的是主机名别名dynamo。这个别名是abp-sam-backend网络中的docker为我自动创建的。别名就是服务名称。

第3步:通过sam local启动代码

sam local start-api -t sam-template.yml --docker-network abp-sam-backend --skip-pull-image --profile default --parameter-overrides 'ParameterKey=StageName,ParameterValue=local ParameterKey=DDBTableName,ParameterValue=local-SingleTable' 

请注意,我告诉sam local使用在我的abp-sam-backend中定义的现有网络docker-compose.yml

端到端示例

我制作了一个可行的示例(加上其他功能),可以在https://github.com/rynop/abp-sam-nestjs

找到