He configurado un par de puerta de enlace api / aws lambda usando AWS sam local y he confirmado que puedo llamarlo con éxito después de ejecutar

sam local start-api

Luego agregué una instancia local de dynamodb en un contenedor docker y creé una tabla con el aws cli

Pero, después de haber agregado el código a la lambda para escribir en la instancia de dynamodb que recibo:

2018-02-22T11: 13: 16.172Z ed9ab38e-fb54-18a4-0852-db7e5b56c8cd error: no se pudo escribir en la tabla: {"mensaje": "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 "," recuperable ": verdadero," tiempo ":" 2018-02-22T11: 13: 16.165Z "} escribiendo evento desde el comando: {" nombre ":" prueba "," geolocalización ":" xyz "," escriba ":" createDestination "} END RequestId: ed9ab38e-fb54-18a4-0852-db7e5b56c8cd

Vi en línea que podría necesitar conectarse a la misma red acoplable, así que creé una red docker network create lambda-local y cambié mis comandos de inicio a:

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

Y

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

Pero aún recibe el mismo error

Sam local está imprimiendo 2018/02/22 11:12:51 Connecting container 98b19370ab92f3378ce380e9c840177905a49fc986597fef9ef589e624b4eac3 to network lambda-local

Estoy creando el dynamodbclient usando:

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()
}

E inspeccionando el cliente dynamodbclient mi código está creando espectáculos

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' }

¿Debería funcionar esta configuración? ¿Cómo hago para que hablen entre ellos?

---- editar ----

Según una conversación de Twitter, vale la pena mencionar (tal vez) que puedo interactuar con dynamodb en la CLI y en el shell web

dynamo db at the CLI

dynamodb web shell

26
Paul D'Ambra 22 feb. 2018 a las 14:25

6 respuestas

La mejor respuesta

Muchas gracias a Heitor Lessa que me respondió en Twitter con un ejemplo de repositorio

Lo que me señaló la respuesta ...

  • el contenedor docker de dynamodb está en 127.0.0.1 desde el contexto de mi máquina (por eso podría interactuar con ella)

  • El contenedor acoplable de SAM local está en 127.0.0.1 desde el contexto de mi máquina

  • Pero no están en 127.0.0.1 del contexto del otro

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

Me señaló al cambiar mi código de conexión a:

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()
}

Siendo las líneas importantes:

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

desde el contexto del contenedor acoplable local SAM, el contenedor dynamodb se expone a través de su nombre

Mis dos comandos de inicio terminaron como:

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

Y

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

Con el único cambio aquí para darle un nombre al contenedor dynamodb

23
Paul D'Ambra 28 feb. 2018 a las 08:50

Si estás usando sam-local en una Mac como muchos desarrolladores, deberías poder usar

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

O en las nuevas instalaciones de 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"

En lugar de tener que hacer múltiples comandos como Paul mostró anteriormente (¿pero eso podría ser más independiente de la plataforma?).

17
Ellery 20 nov. 2018 a las 05:31

Las otras respuestas fueron demasiado complicadas / poco claras para mí. Esto es lo que se me ocurrió.

Paso 1: use docker-compose para que DynamoDB se ejecute localmente en una red personalizada

docker-compose.yml

Tenga en cuenta el nombre de la red abp-sam-backend, el nombre del servicio dynamo y ese servicio dynamo está utilizando la red 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: {}

Inicie el contenedor local DynamoDB a través de:

docker-compose up -d dynamo

Paso 2: escriba su código para manejar el punto final local de 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');
}

Tenga en cuenta que estoy usando el alias del nombre de host dynamo. Este alias es creado automáticamente por Docker dentro de la red abp-sam-backend. El nombre del alias es solo el nombre del servicio.

Paso 3: Inicie el código a través de 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' 

Tenga en cuenta que le digo a sam local que use la red existente abp-sam-backend que estaba definida en mi docker-compose.yml

Ejemplo de extremo a extremo

Hice un ejemplo de trabajo (además de muchas otras características) que se puede encontrar en https: // github.com/rynop/abp-sam-nestjs

3
rynop 1 ago. 2019 a las 12:49

Como @Paul mencionó, se trata de configurar su red entre los contenedores docker: lambda y base de datos.

Otro enfoque que funcionó para mí (usando docker-compose).

Docker-compose:

version: '2.1'

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

networks:
  my_network:

Luego, después de docker-compose up, al ejecutar docker network ls se mostrará:

NETWORK ID          NAME                        DRIVER              SCOPE
7eb440d5c0e6        dev_my_network              bridge              local

El nombre de mi contenedor acoplable es dev_db_1.

Mi código js es:

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

Luego, ejecutando el comando sam:

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

Apilar:

  • Docker: 18.03.1-ce
  • Docker-compose: 1.21.1
  • MacOS HighSierra 10.13.6
2
Yair Segal 30 jul. 2018 a las 20:01

Si está utilizando LocalStack para ejecutar DynamoDB, creo que el comando correcto para usar la red LocalStack para SAM es :

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

Y en su código, el nombre de host LocalStack debe ser localstack_localstack_1

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

Sin embargo, lancé LocalStack usando docker-compose up. El uso de la herramienta CLI pip para iniciar LocalStack puede generar diferentes identificadores.

1
thirdender 29 abr. 2019 a las 20:20

SAM inicia un contenedor acoplable lambci/lambda debajo del capó, si tiene otro contenedor que aloja dynamodb, por ejemplo, o cualquier otro servicio al que desea conectar su lambda, por lo que debe tener ambos en la misma red

Supongamos que dynamodb (aviso --name, este es el punto final ahora)

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

Esto resultará en algo como esto

0e35b1c90cf0....

Para saber en qué red se creó esto:

docker inspect 0e35b1c90cf0

Debería darte algo como

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

....

Si conoce sus redes y desea colocar el contenedor de Docker dentro de una red específica, puede guardar los pasos anteriores y hacerlo en un comando al iniciar el contenedor con la opción --network

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

Importante: su código lambda ahora debería tener un punto final para dynamo a DynamoDBEndpoint

Decir por ejemplo:

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

Probar todo:

Uso de lambci:lambda

Esto solo debe enumerar todas las tablas dentro de su otro contenedor 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

O para invocar una función: (Ejemplo de Go, igual que 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

Se puede encontrar más información sobre lambci / lambda aquí

Uso de SAM (que usa el mismo contenedor lmabci/lambda):

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

Siempre puede usar la opción --debug en caso de que quiera ver más detalles.

Alternativamente , también puede usar http://host.docker.internal:8000 sin la molestia de jugar con Docker, esta URL está reservada internamente y le da acceso a su máquina host, pero asegúrese de exponer el puerto 8000 cuando comience contenedor dynamodb. Aunque es bastante fácil, no funciona en todos los sistemas operativos. Para obtener más detalles sobre esta función, consulte documentación del acoplador

4
Muhammad Soliman 17 may. 2019 a las 02:24