Руководство экономного программиста по использованию API AWS без нарушения банковского счета
Облако AWS стало практически нормой: более миллиона компаний по всему миру создают на нем приложения. В своей карьере в какой-то момент вам придется или придется что-то развернуть в этой экосистеме: это неизбежно, что показывает, насколько далеко досягаемость AWS.
Одна из самых больших проблем при попытке создать облако - это огромное количество сервисов, доступных в вашем распоряжении, и количество движущихся частей. Прошли те времена, когда создание приложений с помощью пользовательского интерфейса было простым: некоторая бизнес-логика, база данных и домен, и все готово. Теперь у нас есть сервисы, которые обещают постоянную масштабируемость практически для всего, что вы можете придумать.
Возьмем, к примеру, создание на базе бессерверной архитектуры AWS. Он обещает простоту использования, но в нем есть N движущихся частей, чтобы все работало. Если вы создадите простую лямбда-функцию, вам придется использовать смесь сервисов, таких как CloudWatch, S3, IAM, Kinesis, Step Functions и т. Д.
При использовании AWS создать среду разработки, похожую на производственную, сложно, особенно когда вы ограничены организационными ограничениями, которые обычно связаны либо с безопасностью, либо с затратами. Необходимость развертывания для тестирования является обременительной, поскольку большинство служб представляют собой черные ящики; это действительно усложняет жизнь, когда что-то не работает.
Что такое LocalStack All About?
LocalStack - это проект с открытым кодом от Atlassian, который обеспечивает простой способ разработки облачных приложений AWS прямо с вашего локального хоста. Он запускает тестовую среду на вашем локальном компьютере, которая обеспечивает почти те же функции паритета и API-интерфейсы, что и реальная облачная среда AWS, за исключением масштабирования, надежности и большого количества волшебства.

Это делается с помощью комбинации инструментов для имитации / тестирования, в первую очередь кинезалит / диналит и мото. Хотя LocalStack написан на Python, он не зависит от языка, так как все сервисы предоставляются через HTTP-сервисы, поэтому вы можете практически использовать любой язык для взаимодействия с ним, например, с AWS.
Изначально меня беспокоило то, что LocalStack не имеет паритета функций с предложением AWS. Я понял, что ваша местная среда не обязательно должна быть индивидуальной; он просто должен быть достаточным, чтобы охватить все варианты использования.
Это помогает вам сосредоточиться на том, что важно для выполнения работы, а не на тушении пожаров с помощью инфраструктуры и борьбе с привратниками за запрос доступа к AWS. Я считаю, что если инструмент может помочь вам уменьшить общее количество ошибок в сложной распределенной системе при одновременном снижении затрат, то его стоит вложить в ваши основные локальные инструменты разработки.
Отношения любви-ненависти с AWS Gatekeepers
В зависимости от характера вашей среды иногда сервисы AWS могут быть ограничены исключительно и зарезервированы для нескольких привратников. Не поймите меня неправильно - привратники необходимы, чтобы разработчики не прострелили себе ногу. В конце концов, у них есть наглядность. Хотя иногда это может быть хорошо, когда существует слишком много ограничений, это означает, что у человека ограниченные возможности для изучения предложений AWS.
Одним из проектов, над которым я работал в AWS, был основной стек с SQS, который был единственной точкой входа в наше приложение. Вначале мы прибегали к созданию конвейеров SQS для разных разработчиков. Это привело к экспоненциальному увеличению очередей, поскольку каждый разработчик должен был получить x количество очередей, чтобы предотвратить конфликты передачи сообщений.
В мире Джеффа Безоса каждый байт имеет значение в долларах. Использование AWS для локальной разработки может быстро стать дорогостоящим, особенно если эти сервисы всегда находятся в неактивном состоянии, что обычно бывает большую часть времени. Возможно, мы не хотим этого признавать, но это всего лишь факты. Задайте себе вопрос: сколько раз вам действительно нужно задействовать экземпляр EC2, чтобы запустить приложение в среде разработки или среде контроля качества?
В некоторых из этих сред не требуется, чтобы служба работала постоянно. Бессерверная версия помогает в этом отношении, но также затрудняет тестирование. Таким образом, имеет смысл предоставлять некоторые из этих услуг по мере необходимости. Если вы собираетесь проводить тестирование в определенные дни или при выпуске функций, имеет смысл предоставлять услуги тогда, когда они наиболее необходимы.
LocalStack для моей команды решил некоторые из этих проблем, поскольку можно создать сквозное собственное приложение AWS без необходимости напрямую интегрироваться в действующую учетную запись AWS.
В этой статье я покажу вам несколько примеров того, как я подошел к этому.
Предпосылки
- Установите Docker, если вы еще этого не сделали.
- Установите фреймворк Бессерверный.
- Установите AWS CLI. Хотя мы не собираемся работать с настоящим AWS, это необходимо для взаимодействия с LocalStack.
- Awscli-local, тонкая оболочка интерфейса командной строки для использования с LocalStack, не является обязательным.
Настраивать
LocalStack можно установить двумя способами: напрямую, как в примере ниже, или с помощью Docker. Если вы используете прямой pip install, убедитесь, что вы запускаете pip в новой виртуальной среде или среде conda.
$ pip install localstack
Чтобы запустить LocalStack с Python, вы можете выполнить команду ниже.
$ localstack start
Мы будем использовать подход Docker, поскольку он позволяет каждому, кто выполняет это упражнение, иметь одинаковую согласованную рабочую среду, независимо от операционной системы.
В этой статье предполагается, что у вас есть элементарное представление о Docker и на вашем компьютере установлена его копия. Если вы этого не сделаете, было бы хорошо освежить это, прежде чем продолжить.
С чего все начинается: файл Compose
Создайте новый docker-compose.yml файл или добавьте следующий к существующему compose-file.
Создайте каталог с именем data на том же корневом уровне, что и ваш файл набора. Мы будем использовать эту папку data для подключения к нашему каталогу tmp/localstack. Каталог tmp будет использоваться стеком для постоянных данных для таких сервисов, как Kinesis, DynamoDB, Elasticsearch, S3, Secrets Manager, SSM, SQS и SNS.
Включение этого каталога гарантирует, что в случае перезапуска или сбоев стека ваши сохраненные данные не будут потеряны.
./bin:/docker-entrypoint-initaws.d
Создайте папку bin и файл bash на том же уровне, что и ваш docker-compose.yml файл: /bin/localstack-entrypoint.sh . Поскольку LocalStack не предоставляет значимого пользовательского интерфейса, если вы не потратите немного денег на корпоративную версию, localstack-entrypoint.sh файл сценария bash будет служить цели создания служб и ресурсов в нашем LocalStack, таких как файлы S3, таблицы базы данных и т. д. ., при загрузке LocalStack.
Если вы не уверены в написании сценариев bash, вы также можете выполнять сценарии Python непосредственно из localstack-entrypoint.sh, при условии, что эти сценарии помещены в ту же папку или напрямую связаны с AWS CLI. Если вы хотите запускать специальные команды в среде LocalStack, мы увидим, как это делается, в приведенном ниже сценарии.
LocalStack требует установки учетных данных, однако на данном этапе разработки платформа не использует механизм аутентификации IAM для какой-либо реальной аутентификации. Какие бы учетные данные вы ни указали, LocalStack примет их без проверки. Всегда следите за тем, чтобы вы придерживались передовых методов безопасности и не передавали свои настоящие ключи AWS в систему контроля версий.
LocalStack ports '4563-4599:4563-4599' и '8080'
Когда ваш контейнер Docker запускается, LocalStack откроет порты, определенные в приведенном выше docker-compose.yml файле, где левый номер связывает порт на вашем хосте с портом контейнера справа. В большинстве случаев эти два числа могут быть одинаковыми, например, 8080:8080. Если у вас есть другие функции, работающие на порту справа, вам, возможно, придется изменить значение по умолчанию, например, на 8086:8080. Например, открыв ваш браузер на http://localhost:8086, он перенаправит на 8080 вашего контейнера.
Строка '4566-4599:4566-4599' делает то же самое, но связывает целый ряд портов. Эти номера портов используются LocalStack в качестве конечных точек для различных API, таких как S3, RDS, API-шлюз и т. Д.
Обратите внимание: указанные выше порты могут быть открыты для внешнего мира, если вы не защищены сетевым брандмауэром. Вы всегда можете выбрать привязку только к хост-машине 127.0.0.1:8080:8080.
Переменные среды LocalStack
LocalStack имеет большое количество переменных среды, которые передаются контейнеру LocalStack при загрузке.
SERVICES=s3: вы можете определить список сервисов AWS, разделенных запятыми, для эмуляции. Каждая служба может запускать другой док-контейнер для обслуживания таких запросов.DATA_DIR=/tmp/localstack/data: это каталог, в котором LocalStack будет сохранять свои данные внутри. Подробнее об этом в следующих разделах.
Volumes
'./data:/tmp/localstack'
Контейнеры Docker не хранят состояние, и единственный способ сделать это - использовать тома, которые обращаются к части вашего жесткого диска. ./data относится к вашему docker-compose.yml файлу. Вы можете выбрать любой другой путь, какой пожелаете.
Вышеупомянутой конфигурации компоновки достаточно, чтобы вы начали. Для запуска ваша среда LocalStack через Docker compose выполняет следующую команду в том же месте, что и ваш docker-compose.yml файл. Вы можете добавить аргумент -d в конце, чтобы запустить LocalStack в качестве демона в фоновом режиме.
$ docker-compose up
Посмотрите на свою консоль во время работы docker-compose up. Вы увидите, что LocalStack создал файл:
../data/data/recorded_api_calls.json
Ранее мы говорили о каталоге LocalStack tmp, в котором хранятся ваши файлы. Это постоянство достигается за счет автоматического создания recorded_api_calls.json файла , который упрощает воспроизведение ранее выполненных вызовов сервисов AWS .
Когда контейнер перезапустится, он повторно применит эти вызовы. так мы можем сохранять наши данные между перезапусками. Как только мы начнем загрузку, мы не увидим новых файлов в этом каталоге. Вместо этого наши загрузки будут записаны в этот файл как необработанные байтовые данные. Вы можете включить этот файл в свое репо, если хотите поделиться состоянием контейнера с другими, но в зависимости от того, сколько вы загрузили, этот файл может быстро стать огромным.
Если вы хотите иметь возможность восстановить корзину позже, вы можете сделать резервную копию этого файла. Когда вы будете готовы к восстановлению, просто удалите обновленный файл, замените его своей резервной копией и перезапустите контейнер.
Доступ к вашему LocalStack вне Docker
Если вы потратили немного времени на работу с AWS, вы оцените необходимость использования именованных профилей как для обеспечения безопасности, так и для управления ключами, когда у вас есть доступ к более чем одной учетной записи AWS или когда у вас есть более одного доступа. и секретный ключ.
Давайте определим новый именованный профиль с именем localstack, чтобы мы могли выполнять команды интерфейса командной строки AWS в среде LocalStack, где ~ ссылается на каталог $HOME.
~ / .aws / credentials
[localstack]
aws_access_key_id = foo
aws_secret_access_key = bar
~ / .aws / config
[profile localstack]
region = us-east-1
output = json
Если ваш LocalStack запущен, каждая из ваших команд CLI AWS теперь может состоять из параметра endpoint-url, который обеспечивает выполнение ваших команд в вашем LocalStack вместе с именованным профилем, который мы создали для имитации аутентификации.
$ aws --endpoint-url=http://localhost:4572 s3 ls "s3://nyc-tlc/trip data/" --profile localstack
Использование LocalStack с SQS
В приведенном ниже примере показано, как вы подключаетесь к LocalStack с помощью boto3 SQS. Те же принципы можно применить, если вы используете другие языки программирования.
Эквивалент Node.js:
var AWS = require(‘aws-sdk’);
// Create an SQS service object using localstack endpoint
var config = {
endpoint: new AWS.Endpoint('http://localhost:4576'),
accessKeyId: 'foo',
secretAccessKey: 'bar',
region: 'us-east-1'
}
var sqs = new AWS.SQS(config);
С помощью Java мы можем добиться чего-то похожего:
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.net.URI;
public class Sqs {
private SqsClient client;
public Sqs(URI endpoint) {
client = SqsClient.builder()
.region(Region.US_EAST_1)
.endpointOverride(endpoint)
.build();
}
}
Использование LocalStack с Dask
Dask - это незаменимый инструмент в вашем наборе инструментов, если вы собираетесь обрабатывать относительно средние и большие данные в своих решениях для анализа данных. По сути, вы пишете код один раз, а Dask обрабатывает, как распределить вашу работу по нескольким процессорам или узлам, управляя вычислениями, превышающими объем памяти. Тестирование Dask на LocalStack тривиально, если вы точно понимаете, где вам нужно изменить, как показано в приведенном ниже примере.
Вы должны убедиться, что вы явно определили storage_options и явно определили свой endpoint-url, чтобы boto3 понимал, где находится ваш LocalStack.
os.environ['LOCALSTACK_S3_ENDPOINT_URL'] = 'http://localstack:4572'
Обратите внимание, как LOCALSTACK_S3_ENDPOINT_URL указывает на LocalStack, который является DNS по умолчанию, предоставленным вашему экземпляру LocalStack Docker. Dask постоянно поддерживает локальное хранилище файлов, поэтому важно, чтобы ваш код Dask работал в той же сети, что и ваш докер-контейнер. Для лучшей иллюстрации того, как все части связаны между собой, вы можете обратиться к ссылке GitHub в конце этой статьи.
Как легко создать лямбда-функцию в вашем LocalStack
Если вам не нравится писать файлы CloudFormation YAML, бессерверный вариант - это альтернативный вариант, который упрощает развертывание лямбда-функций.
Не вдаваясь в подробности того, как работает бессерверный режим, приведенный ниже serverless.yml файл конфигурации должен дать вам представление о том, что требуется для развертывания шлюза API с функцией HTTP. Раздел custom - ›localstack определяет все конфигурации, необходимые для развертывания вашей локальной лямбда-функции в LocalStack.
Лямбда-функция иллюстрирует простую функцию, которая возвращает «Hello World» с текущей меткой времени.
def endpoint(event, context):
current_time = datetime.datetime.now().time()
body = {
"message": "Hello, world",
"eventTime": str(current_time)
}
response = {
"statusCode": 200,
"body": json.dumps(body)
}
return response
Вышеупомянутый файл serverless.yml выполнит за нас всю тяжелую работу, такую как создание пакета лямбда, загрузка его в наш LocalStack, предоставление любых дополнительных необходимых ресурсов, например, шлюза API. Одна вещь, которую он не сделает для нас автоматически, - это создание корзины S3. поэтому важно обновить localstack-entrypoint.sh командой создания корзины или выполнить ее один раз вручную после запуска стека.
# Create lambda deploy bucket for our simple http endpoint example $ aws --endpoint-url=$LOCALSTACK_S3_URL s3api create-bucket --bucket simple-http-endpoint-local-deploy
В нашем serverless.yml файле мы используем ${self:service}-${opt:stage}-deploy вместо жестко заданного имени сегмента. Бессерверные переменные позволяют пользователям динамически заменять значения конфигурации в serverless.yml config. Они особенно полезны при предоставлении секретов для ваших бессерверных сервисов или когда мы хотим выполнить развертывание в нескольких средах, например, CI, dev, QA и production с помощью аргумента stage.
Если ваш LocalStack работает в фоновом режиме, единственное, что вам нужно сделать, это выполнить следующую команду, которая вызовет развертывание на вашем LocalStack, поскольку ваш параметр stage указывает на ваш local.
$ serverless deploy --stage local --profile localstack
Чтобы выполнить лямбда-функцию без сервера на LocalStack, вы можете выполнить следующее:
$ serverless invoke --function currentTime --log --profile localstack --stage local
Это дает результат ниже.
Чтобы вызвать нашу лямбда-функцию через наш браузер, обслуживаемый API-шлюзом, мы можем выполнить приведенный ниже URL-адрес, где шаблон URL-адреса для выполнения API-интерфейса LocalStack выглядит следующим образом:
http://localhost:4566/restapis/<apiId>/<stage>/_user_request_/<methodPath>
Если мы опустим аргумент профиля и изменим стадию на профиль разработчика, например, если предположим, что наш именованный профиль AWS по умолчанию указывает на активную учетную запись AWS, для этой учетной записи будет инициирована обычная последовательность оперативного развертывания.
Проверка работоспособности LocalStack
После запуска LocalStack вы можете получить доступ к конечной точке проверки работоспособности, нажав этот URL:
http://localhost:4566/health
{
"services": {
"cloudformation": "running",
"cloudwatch": "running",
"iam": "running",
"sts": "running",
"lambda": "running",
"logs": "running",
"s3": "running",
"sqs": "running",
"events": "running",
"apigateway": "running"
}
}
Обратите внимание, что первоначальный запуск ваших вызовов API для отдыха может занять некоторое время. Конечная точка отобразит общее количество запущенных служб и их соответствующий статус. Где запущена служба, будет зависеть от того, где вы указали в переменной среды LocalStack.
SERVICES=s3,sqs,lambda,cloudformation,sts,iam,cloudwatch,apigateway,events
Более локальный подход с помощью утилиты awscli-local
До сих пор мы использовали интерфейс командной строки AWS по умолчанию. Если вы не хотите постоянно указывать URL-адрес конечной точки при выполнении команд интерфейса командной строки, вы можете выбрать использование пакета awscli-local. Это аккуратная небольшая оболочка вокруг интерфейса командной строки AWS, которая гарантирует, что все, что вы запускаете, по умолчанию работает с вашим LocalStack.
Как создать ведро S3
Вы можете создать корзину S3 под названием «my-test-bucket» с помощью следующей команды. Если вы хотите отобразить содержимое корзины, важно предоставить ACL-доступ для общего чтения.
$ awslocal s3 mb s3://my-test-bucket
Вы должны увидеть «make_bucket: my-test-bucket» в своем терминале. Убедитесь, что сегмент был успешно создан.
$ awslocal s3 ls
Проблемы с LocalStack
- Параметры LocalStack, которые не работают вместе, сохранение ваших сегментов в точках монтирования и попытка развернуть лямбда-выражение путем заархивирования и копирования вашей лямбды в корзину LocalStack вызовут ошибку, указанную ниже.
2020-07-22T12:12:51:DEBUG:localstack.services.cloudformation.cloudformation_listener: Error response for CloudFormation action "CreateStack" (400) POST /: b'Unknown error: Please note that Lambda mounts (bucket name "__local__") cannot be used with LAMBDA_REMOTE_DOCKER=1 Traceback (most recent call last):\n File "/opt/code/localstack/localstack/services/awslambda/lambda_api.py", line 954, in create_function\n result = set_function_code(func_details.code, lambda_name)\n File "/opt/code/localstack/localstack/services/awslambda/lambda_api.py", line 721, in set_function_code\n lambda_cwd = lambda_cwd or set_archive_code(code_passed, lambda_name)\n File "/opt/code/localstack/localstack/services/awslambda/lambda_api.py", line 676, in set_archive_code\n raise Exception(msg % BUCKET_MARKER_LOCAL)\nException: Please note that Lambda mounts (bucket name "__local__") cannot be used with LAMBDA_REMOTE_DOCKER=1\n' localstac
- Всегда полезно удалить
/data/data/recorded_api_calls.jsonфайл, если вы внесли некоторые изменения в настройки среды создания докеров LocalStack. Я заметил, что иногда он вылетает при воспроизведении выполненных вызовов API. - В вашем
docker-compose.yml, вероятно, будет хорошей идеей указать точную версию образа LocalStack, которую вы хотите использовать, а не извлекать самую последнюю. Последний тег затрудняет отслеживание того, какая версия образа запущена, и иногда новые функции могут содержать критические изменения. - Джефф Безос работает быстро, поэтому не ожидайте, что LocalStack сможет идти в ногу с предложениями AWS, но это бесплатно.
- На первый взгляд, вы можете подумать, что все это бесплатно в отношении самого LocalStack, но есть некоторые расширенные функции, которые могут потребовать от вас некоторых долларов. Но из того, что я видел до сих пор, основы должны в значительной степени охватывать большинство ваших сценариев использования - разработчики тоже должны есть.
image: localstack/localstack:<TAG-VERSION-NUMBER>
Дополнительные сведения о проблемах, о которых вам следует знать, см. В файле README, где содержатся советы по устранению неполадок Localstack. Осведомленность о некоторых проблемах сэкономит вам и вашей команде невероятное количество времени на отладку.
Каковы мои альтернативы LocalStack?
Если вы чувствуете, что LocalStack не удовлетворяет некоторые из ваших потребностей, вы всегда можете выбрать использование фиктивных SDK, которые являются обычным способом работы. Этот подход работает лучше всего, если вы разрабатываете свои классы с учетом расширения.
В качестве альтернативы корзине S3 существует MinIO в качестве прямой замены облачной службы хранилища объектов S3.
Если вы создаете для других облачных сервисов, таких как Google, у вас есть другие варианты, такие как эмуляторы Google Cloud и фреймворк FaaS с открытым исходным кодом (функция как услуга) от Google для написания переносимых Node.js. функции, которые можно запускать на вашем локальном компьютере. Если вы собираетесь использовать облачные технологии для работы, вам может пригодиться комбинированный подход.
Последние мысли
При создании приложений на AWS вам необходимо взять под контроль экономическую модель своей архитектуры. Если не соблюдать осторожность, легко попасть в бесконечную кроличью нору дорогих счетов.
Мокинг в определенной степени работает, но не отражает действительную реальность после того, как вы нажмете кнопку «Развернуть».
LocalStack представляет собой отличную отправную точку, предоставляя разработчикам платформу для экспериментов и тестирования нового кода, не отвлекаясь от попыток убедить ваших боссов в том, почему им нужно выкладывать пару сотен долларов в месяц за подтверждение концепции. На мой взгляд, переход на подход LocalStack - это прагматичный подход к хешированию кода, который будет выполняться на AWS.
Небольшой побочный проект, который вы можете попробовать, - это создать оболочку boto3 или AWS SDK с вашими наиболее часто используемыми сервисами AWS и включить функцию переключения LocalStack с помощью переменной среды или файлов свойств. Конечные точки LocalStack можно настроить в файле YAML, как показано ниже.
endpoints: S3: http://localhost:4572 DynamoDB: http://localhost:4569 CloudFormation: http://localhost:4581 Elasticsearch: http://localhost:4571 ES: http://localhost:4578 SNS: http://localhost:4575 SQS: http://localhost:4576 Lambda: http://localhost:4574 Kinesis: http://localhost:4568
Не стесняйтесь клонировать репозиторий ниже, в котором есть больше примеров для вашей справки:
Тимотимугайи / localstack_python_examples
С помощью LocalStack вы можете сделать гораздо больше, что выходит за рамки данной статьи. Я рекомендую вам потратить некоторое время на раздел проблем LocalStack GitHub, чтобы ознакомиться с некоторыми расширенными настройками и конфигурациями.
Надеюсь, вам понравилось читать. Поделитесь своими мыслями в разделе комментариев ниже. Если вы чувствуете, что эта статья поможет следующему разработчику, продвигайте ее вперед.