web-dev-qa-db-ja.com

DockerでAWS SAM Localをdynamodbと接続する

AWS sam localを使用してAPIゲートウェイ/ AWSラムダペアを設定し、実行後に正常に呼び出すことができることを確認しました

sam local start-api

次に、Dockerコンテナーにローカルdynamodbインスタンスを追加し、aws cliを使用してその上にテーブルを作成しました

しかし、受信した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 "、" retryable ":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シェルでdynamodbとやり取りできることを(おそらく)言及する価値があります。

dynamo db at the CLI

dynamodb web Shell

17
Paul D'Ambra

ツイッターで私に答えてくれたHeitor Lessa の例のレポに感謝します

答えを教えてくれました...

  • dynamodbのdockerコンテナーは、マシンのコンテキストから127.0.0.1にあります(これが、対話できる理由です)

  • SAMローカルの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コンテナはその名前を介して公開されます

私の2つの起動コマンドは次のようになりました:

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コンテナに名前を付けることです

15
Paul D'Ambra

多くの開発者のような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が上記で示したような複数のコマンドを実行する代わりに(しかし、それはプラットフォームにとらわれないのでしょうか?)。

12
Ellery

SAMは、たとえばdynamodbをホストする別のコンテナーまたはラムダを接続する他のサービスがある場合、フードの下でドッカーコンテナー_lambci/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>>

....
_

ネットワークを知っていて、特定のネットワーク内にドッカーコンテナーを配置する場合は、上記の手順を保存し、_--network_オプションを使用してコンテナーを起動するときに1つのコマンドでこれを実行できます

_docker run -d -p 8000:8000 --network myNetworkName --name DynamoDBEndpoint Amazon/dynamodb-local
_

重要:ラムダコードには、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の詳細については、こちらをご覧ください こちら

SAMの使用(同じコンテナ_lmabci/lambda_を使用):

_sam local invoke --event myEventData.json --docker-network myNetworkName MyFuncName
_

詳細を表示する場合は、常に_--debug_オプションを使用できます。

代わりに、_http://Host.docker.internal:8000_も使用できます。Dockerで遊ぶ手間はありません。このURLは内部的に予約されており、ホストにアクセスできますただし、dynamodbコンテナを起動するときにポート8000​​を公開するようにしてください。非常に簡単ですが、すべてのオペレーティングシステムで機能するわけではありません。この機能の詳細については、 docker documentation を確認してください

2

@Paulが述べたように、それは、ドッカーコンテナー-ラムダとデータベース間のネットワークの構成に関するものです。

私のために働いた別のアプローチ(docker-composeを使用)。

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

スタック:

  • Docker:18.03.1-ce
  • Docker-compose:1.21.1
  • MacOS HighSierra 10.13.6
2
Yair Segal

LocalStack を使用してDynamoDBを実行している場合、SAMにLocalStackネットワークを使用する正しいコマンドは次のとおりです。

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を使用してLocalStackを起動しました。 pip CLIツールを使用してLocalStackを起動すると、異なる識別子が生成される場合があります。

1
thirdender

他の答えはあまりにも複雑すぎた/私には不明瞭だった。これが私が思いついたものです。

ステップ1:docker-composeを使用してDynamoDBローカルをカスタムネットワークで実行する

docker-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を使用しています。このエイリアスは、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 localabp-sam-backendで定義された既存のネットワークdocker-compose.ymlを使用するように指示していることに注意してください

エンドツーエンドの例

https://github.com/rynop/abp-sam-nestjs で見つけることができる実用的な例(および他の機能の束)を作りました

1
rynop