Практические руководства, серия Облачные вычисления

Как создавать и развертывать приложения AWS на локальном компьютере

Создавайте и развертывайте облачные приложения на основе AWS на вашем локальном компьютере.

В своих предыдущих статьях я рассказывал о создании и развертывании бессерверных приложений на AWS с использованием Chalice и SAM. Это были быстрые развлекательные проекты, которые использовали возможности бессерверных вычислений и позволили нам развернуть бессерверное приложение на AWS в течение нескольких минут.

Но многие люди не могут полностью использовать такие руководства из-за отсутствия учетной записи AWS. Настройка учетной записи AWS и настройка среды разработки могут занять много времени, а иногда также приводить к нежелательным расходам (при неправильной настройке).

В этой статье я проведу вас через шаги, необходимые для создания и развертывания бессерверного приложения без необходимости создавать и настраивать реальную учетную запись AWS.

На этот раз мы создадим образец приложения Pet Store с использованием Amazon API Gateway, AWS Lambda и Amazon DynamoDB. Это приложение будет иметь API для добавления нового питомца и получения списка доступных питомцев.

Предпосылки

В этом руководстве мы будем использовать AWS SAM. Вы можете установить и настроить SAM, следуя рекомендациям из предыдущей статьи.

Как создать проект

Выполните команду sam-init, чтобы создать новый проект. Это создаст папку pet-store в вашем текущем каталоге.

sam init -r java11 -d maven --app-template pet-store -n pet-store

Подробнее о передаваемых параметрах читайте в предыдущей статье.

Давайте изменим pom.xml, чтобы обновить имя модуля на PetStore и использовать Java 11 вместо Java 8.

Давайте теперь создадим Pet класс, который будет содержать атрибуты для домашних животных. Мы начнем с простых атрибутов, таких как name, age и category.

Поскольку в качестве хранилища данных мы будем использовать Amazon DynamoDB, давайте добавим соответствующие зависимости SDK в pom.xml.

Это приведет к появлению зависимостей для AWS SDK для DynamoDB и HTTP-клиента Apache, которые будут использоваться для создания синхронного клиента DynamoDB.

Как читать и писать предметы

Нам нужно создать класс доступа к данным для взаимодействия с Amazon DynamoDB и выполнения наших запросов чтения / записи. Создайте класс PetStoreClient и добавьте зависимость от DynamoDbClient.

Теперь мы создадим две функции в классе PetStoreClient для чтения и записи элементов из DynamoDB.

Напишите элемент

Добавление одного элемента в DynamoDB - это PUT запрос. Мы создадим PutItemRequest и укажем имя таблицы и атрибуты элемента, которые нужно добавить.

Затем мы воспользуемся DynamoDbClient, чтобы поместить этот элемент в DynamoDB.

Читать статьи

Чтение списка элементов в DynamoDB - это SCAN запрос. Мы создадим ScanRequest и укажем имя таблицы для сканирования.

Затем мы будем использовать DynamoDbClient для сканирования таблицы в DynamoDB и возврата списка элементов.

Примечание. Запрос на сканирование проходит через все элементы в таблице и поэтому не рекомендуется для реальных случаев использования.

Как разрешить зависимости

Мы добавили DynamoDbClient в качестве зависимости в наш класс PetStoreClient. Как правило, все такие зависимости в коде следует разрешать с помощью внедрения зависимостей (DI).

Когда мы говорим о DI, Spring - первое имя, которое приходит в голову. Однако экосистема Spring ОГРОМНА, и мы в конечном итоге добавим множество ее фреймворков, даже если мы захотим использовать только часть DI. Инъекция также выполняется во время выполнения, что еще больше увеличивает время холодного запуска Lambda.

Guice - еще один приятный фреймворк для внедрения зависимостей, который намного легче Spring. Но, как и Spring, он выполняет инъекцию во время выполнения и, следовательно, также не является хорошим кандидатом для DI.

Затем есть Dagger, чистый фреймворк только для DI, который вводит зависимости во время компиляции !! Его небольшой размер и внедрение во время компиляции делают его идеальным выбором для реализации DI в лямбдах.

Я углублюсь в детали DI и расскажу об использовании Dagger в другой статье. Однако в этой статье мы будем использовать нестареющий стиль статических фабричных методов для предоставления зависимостей.

Давайте создадим класс DependencyModule и объявим в нем все наши зависимости.

В этом классе мы создаем новый экземпляр DynamoDbClient и внедряем его в наш PetStoreClient. Мы также создаем экземпляр ObjectMapper, чтобы помочь нам справиться с сериализацией и десериализацией объектов JSON.

Как обновить конечные точки Lambda и API

Затем нам нужно обновить точку входа для функции Lambda и добавить наши конкретные конечные точки для добавления и получения домашних животных.

Добавьте следующий фрагмент в раздел Resources файла template.yaml.

Это обновляет нашу функцию для использования метода handleRequest из класса App, а также добавляет две конечные точки API для добавления и получения домашних животных.

Также обновите раздел Outputs, чтобы отразить новое имя функции.

Как интегрировать клиента

Теперь, когда у нас есть готовый код для взаимодействия с DynamoDB и отсортированные зависимости, нам нужно внести изменения в обработчик Lambda, чтобы вызвать этот код.

Обновите код в App.java, чтобы вызывать функции в PetStoreClient и выполнять действия в соответствии с запросом API.

Поскольку мы использовали статические фабрики для внедрения зависимостей, мы не сможем эффективно протестировать наш код. Я расскажу о модульном тестировании облачных приложений в другой статье. На данный момент нам нужно удалить модульные тесты, чтобы построить проект.

Как построить проект

В папке pet-store выполните команду sam build.

Это компилирует ваш исходный код и строит все зависимости, которые у вас есть в приложении. Затем он перемещает все файлы в папку .aws-sam/build, чтобы они были готовы к упаковке и развертыванию.

Как тестировать локально (часть 1)

В предыдущей статье мы обсуждали, как SAM CLI предоставляет команду sam local для локального запуска вашего приложения. Это внутренне использует Docker для имитации среды выполнения Lambda. Если у вас не установлен Docker, вы можете получить его здесь.

Это было хорошо для API Daily News, поскольку он извлекал данные из Интернета и не зависел от каких-либо других компонентов AWS. Однако в текущем проекте мы полагаемся на Amazon DynamoDB как на наше хранилище данных, и нам нужен доступ к нему, чтобы мы могли успешно запустить наше приложение.

По сути, нам нужен способ имитировать сервисы, предоставляемые AWS на нашем локальном компьютере, чтобы мы могли тестировать их локально, не используя реальную учетную запись AWS.

Как запустить AWS локально

LocalStack был создан как раз для решения этой проблемы. Его собственными словами:

LocalStack предоставляет простой в использовании фреймворк для тестирования / имитации разработки облачных приложений. Он запускает тестовую среду на вашем локальном компьютере, которая предоставляет те же функции и API, что и реальная облачная среда AWS.

Вкратце, LocalStack объединяет все функции облака AWS в контейнер докеров, работающий локально на нашей машине. Это позволяет разработчикам создавать и тестировать свои облачные приложения без необходимости развертывать их в реальной облачной учетной записи AWS.

Что это значит для разработчика?

  1. Нет необходимости создавать учетную запись AWS.
  2. Не нужно настраивать среду разработки и думать о безопасности и других настройках.
  3. Нет необходимости нести ненужные расходы на AWS в период разработки.
  4. Прозрачная локальная среда, точно имитирующая реальную среду AWS.

Как настроить LocalStack

LocalStack действительно легко настроить и начать использовать. Мы будем использовать Docker, чтобы получить последний образ LocalStack и запустить контейнер, в котором запущена фиктивная версия Amazon DynamoDB.

Создайте файл docker-compose.yaml в папке pet-store и добавьте следующее содержимое.

Давайте посмотрим на некоторые конфигурации, которые мы используем:

  • УСЛУГИ - поскольку мы зависим только от Amazon DynamoDB, мы включим только эту конкретную услугу
  • DEFAULT_REGION - мы будем использовать us-west-1 в качестве нашего региона AWS
  • LAMBDA_EXECUTOR - установка значения local означает, что все наши функции Lambda будут работать во временном каталоге на локальном компьютере.
  • DATA_DIR - место для хранения постоянных данных для таких сервисов, как Amazon DynamoDB

Примечание. Все службы LocalStack доступны через пограничную службу на порту 4566. Это единственный порт, который нам нужно использовать.

Теперь мы можем использовать docker-compose для запуска нашей локальной версии Amazon DynamoDB в собственном контейнере.

Как создать таблицу

Теперь, когда у нас запущена локальная настройка Amazon DynamoDB, мы можем создать таблицу для нашего приложения.

Мы использовали pet-store в качестве имени таблицы в нашем коде, так что давайте создадим ее. Мы будем использовать AWS CLI для доступа к Amazon DynamoDB, запущенного на нашем локальном компьютере, и создания необходимой таблицы.

Выполните следующую команду, чтобы создать таблицу с именем pet-store с атрибутом id в качестве первичного ключа.

aws --endpoint-url "http://localhost:4566" dynamodb create-table \
    --table-name pet-store \
    --attribute-definitions AttributeName=id,AttributeType=S \
    --key-schema AttributeName=id,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST

Обратите внимание, что мы использовали параметр endpoint-url, чтобы указать, что мы указываем на локально работающий экземпляр AWS, а не на фактический.

Как тестировать локально (часть 2)

Внесите следующее изменение в код DynamoDbClient, чтобы он указывал на локально работающий экземпляр Amazon DynamoDB.

Затем используйте sam build для сборки проекта и выполните следующую команду, чтобы запустить API локально.

sam local start-api

Это внутренне создает локальный сервер и предоставляет локальную конечную точку, которая реплицирует ваш REST API.

Теперь давайте протестируем наше приложение, добавив нового питомца. Выполните следующую команду, чтобы добавить нового питомца, вызвав конечную точку /pets, которую мы указали ранее.

curl --location --request PUT 'http://127.0.0.1:3000/pets' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "Rocket",
    "age": 2,
    "category": "Dog"
}'

Это создает новую запись Pet, добавляет ее в наш локальный Amazon DynamoDB и возвращает сгенерированный UUID в ответе.

Давайте добавим еще одного питомца в наш магазин.

curl --location --request PUT 'http://127.0.0.1:3000/pets' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "Candle",
    "age": 1,
    "category": "Pig"
}'

Теперь давайте вызовем наш /pets API, чтобы получить список домашних животных, доступных в нашем хранилище данных. Мы должны ожидать получить список питомцев, содержащий Rocket и Candle.

Заключение

Поздравляю !! Вы только что создали и развернули бессерверное приложение, которое полностью использует AWS DynamoDB на вашем локальном компьютере.

Теперь вы можете вносить любые изменения в свой App.java файл. Повторите sam deploy, чтобы повторно развернуть изменения, и sam local start-api, чтобы запустить локальный сервер и проверить изменения.

Когда вы будете готовы к развертыванию, вам просто нужно удалить переопределения конечной точки, и все готово. В идеальной ситуации это могло бы контролироваться переменными среды и не потребовало бы абсолютно никаких изменений кода, чтобы сделать его готовым к производству.

Полный исходный код этого руководства можно найти здесь.