подключение AWS SAM Local с dynamodb в докере
Я настроил пару API-шлюз /AWS-лямбда с помощью AWS sam local и подтвердил, что могу успешно вызвать ее после запуска
sam local start-api
Затем я добавил локальный экземпляр DynamodB в Docker-контейнер и создал на нем таблицу с помощью 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", "системный вызов": "подключиться", "адрес": "0.0.0.0", "порт": 8000, "регион": "ес-запад-2", "имя хоста": "0,0.0.0 "," retryable ": true," time ":" 2018-02-22T11:13: 16.165Z "} событие записи из команды: {" name ":" test "," geolocation ":" xyz "," тип ":" createDestination "} END RequestId: ed9ab38e-fb54-18a4-0852-db7e5b56c8cd
В Интернете я увидел, что вам может понадобиться подключиться к той же сети докеров, поэтому я создал сеть сетевых 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()
}
и проверка динамбклиента мой код создает шоу
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' }
Должна ли эта настройка работать? Как мне заставить их говорить друг с другом?
---- редактировать ----
Основываясь на разговоре в Твиттере, стоит упомянуть (возможно), что я могу взаимодействовать с DynamodB в CLI и в веб-оболочке.
Ответы
Ответ 1
Большое спасибо Heitor Lessa, который ответил мне на Twitter с примером репо
Который указал мне на ответ...
-
контейнер docker dynamodb находится на 127.0.0.1 из контекста моей машины (именно поэтому я мог взаимодействовать с ним)
-
Локальный контейнер-док-станция SAM находится на 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 контейнер 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 имя
Ответ 2
Если вы используете sam-local на Mac, как многие разработчики, вы можете просто использовать
options.endpoint = "http://docker.for.mac.localhost:8000"
Или на более новых установках докера 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"
Вместо того, чтобы выполнять несколько команд, как показывал Пол выше (но это может быть более независимым от платформы?).
Ответ 3
Как отметил @Paul, речь идет о настройке вашей сети между контейнерами докеров - лямбдой и базой данных.
Другой подход, который работал для меня (с использованием докеры-компоновки).
докер-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
Имя моего контейнера-докера - 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
- Docker-compose: 1.21.1
- MacOS HighSierra 10.13.6
Ответ 4
Если вы используете 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,
});
Однако я запустил LocalStack, используя docker-compose up
. Использование инструмента pip
CLI для запуска LocalStack может привести к различным идентификаторам.
Ответ 5
SAM
запускает lambci/lambda
контейнер lambci/lambda
под капотом, если у вас есть другой контейнер, содержащий, например, dynamodb
или любые другие службы, к которым вы хотите подключить вашу лямбду, так что вы должны иметь оба в одной сети.
Предположим, 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
Важно: у вашего лямбда-кода теперь должна быть конечная точка для динамо в 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 Example, как 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
без хлопот с докером, этот URL-адрес зарезервирован для внутреннего использования и дает вам доступ к вашему хост-компьютеру, но убедитесь, что вы открываете порт 8000 при запуске динамод контейнер. Хотя это довольно просто, но это не работает во всех операционных системах. Для получения более подробной информации об этой функции, пожалуйста, проверьте докер документацию