44

我已经使用 AWS sam local 设置了一个 api gateway/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":"connect","address":"0.0.0.0","port":8000,"region":"eu-west-2","hostname":"0.0 .0.0","re​​tryable":true,"time":"2018-02-22T11:13:16.165Z"} 从命令写入事件:{"name":"test","geolocation":"xyz"," type":"createDestination"} END 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 交互

CLI 上的 dynamo db

dynamodb 网页外壳

4

7 回答 7

39

非常感谢Heitor Lessa 在 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 容器起一个名字

于 2018-02-28T08:50:16.653 回答
31

如果您像很多开发人员一样在 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"

而不是像上面显示的 Paul 那样执行多个命令(但这可能与平台无关?)。

于 2018-06-15T18:30:06.397 回答
11

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

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

码头工人-compose.yml

请注意网络名称abp-sam-backend、服务名称dynamo以及该dynamo服务正在使用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。这个别名是由网络内的 docker 为我自动创建的abp-sam-backend。别名只是服务名称。

第 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找到

于 2019-08-01T12:49:15.173 回答
8

SAMlambci/lambda在引擎盖下启动一个 docker 容器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 代码现在应该具有 dynamo 的端点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

或者调用一个函数:(Go 示例,与 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 的更多信息

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

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

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

或者,您也可以使用http://host.docker.internal:8000而无需使用 docker,此 URL 在内部保留,让您可以访问主机,但请确保在启动 dynamodb 容器时公开端口 8000。虽然这很容易,但它并不适用于所有操作系统。有关此功能的更多详细信息,请查看docker 文档

于 2019-05-16T02:17:50.427 回答
2

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

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

码头工人撰写:

version: '2.1'

services:
  db:
    image: ...
    ports:
      - "3306:3306"
    networks:
      - my_network
    environment:
      ...
    volumes:
      ...

networks:
  my_network:

然后,之后docker-compose up,运行docker network ls将显示:

NETWORK ID          NAME                        DRIVER              SCOPE
7eb440d5c0e6        dev_my_network              bridge              local

我的 docker 容器名称是dev_db_1.

我的js代码是:

const connection = mysql.createConnection({
    host: "dev_db_1",
    port: 3306,
    ...
});

然后,运行sam命令:

sam local invoke --docker-network dev_my_network -e my.json

堆:

  • 码头工人:18.03.1-ce
  • 码头工人组成:1.21.1
  • MacOS HighSierra 10.13.6
于 2018-07-30T19:00:32.963 回答
1

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

sam local start-api --env-vars env.json --docker-network localstack_default

在您的代码中,LocalStack 主机名应该是localstack_localstack_1

const dynamoDbDocumentClient = new AWS.DynamoDB.DocumentClient({
  endpoint: process.env.AWS_SAM_LOCAL ?
    'http://localstack_localstack_1:4569' :
    undefined,
});

但是,我使用docker-compose up. 使用pipCLI 工具启动 LocalStack 可能会导致不同的标识符。

于 2019-04-29T20:20:25.000 回答
0

这可能对仍然面临相同问题的人有所帮助:

我最近也面临同样的问题。我遵循了rynop提到的所有步骤(感谢@rynop)

我通过在以下代码中将端点 (http://localhost:8000) 替换为我的(私有)IP 地址(即http://192.168.8.101:8000 )解决了这个问题(在我的 Windows 上):

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');
}
于 2021-11-04T09:36:11.110 回答