Создайте свою инфраструктуру с помощью простой диаграммы
27 января 2023 г.Многие из вас, вероятно, уже слышали об Инфраструктура как код (IaC), в котором используется декларативный подход к управлению системной инфраструктурой и ее предоставлению с помощью машиночитаемых файлов определений.
В настоящее время существует множество инструментов/фреймворков/облачных сервисов (Terraform от HashiCorp, AWS CDK, бессерверная модель приложений AWS (SAM), AWS CloudFormation, Google Deployment Manager), которые предлагают это из коробки. Но что, если я скажу вам, что вы можете добиться этого, просто перетаскивая блоки на диаграмме без написания строки конфигурации и/или кода?
На конференции re:Invent 2022 компания AWS анонсировала сервис Application Composer (в настоящее время находится в предварительной версии), который помогает упростить и ускорить архитектуру. , настройка и сборка бессерверных приложений.
Это практическое руководство будет включать следующие темы:
* как создать инфраструктуру через AWS Application Composer Console * как протестировать сгенерированный шаблон инфраструктуры локально с помощью SAM и локального образа DynamoDB * создание простых приложений Node.js для чтения/сохранения данных в DynamoDB * развертывание инфраструктуры и кода в вашем аккаунте AWS с помощью SAM
Предварительные требования к среде разработки
Что нужно сделать перед началом:
* Создайте учетную запись AWS для доступа к консоли AWS. * Установите AWS SAM: https. ://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html#install-sam-cli-instructions * Установите AWS CLI: https://docs.aws.amazon.com/cli /latest/userguide/getting-started-install.html * Установите Docker: https://docs.docker.com/get-docker/
Схема инфраструктуры
Представим, что нам нужно создать инфраструктуру для простого приложения TODO, в котором пользователь может:
* прочитать все пункты списка дел * создать новую задачу * обновить задачу, изменив ее название или дополнив ее
Перейдите в консоль Application Composer и нажмите кнопку «Создать проект». Убедитесь, что вы создаете проект в подключенном режиме — таким образом Application Composer автоматически синхронизирует изменения между браузером и вашей локальной файловой системой. Эта интересная функция доступна благодаря встроенному в браузер API доступа к файловой системе. Обратите внимание: если вы используете Chrome/Edge/Opera, браузер запросит специальное разрешение, чтобы предоставить доступ для чтения и записи к указанной вами папке.
Если вы используете Firefox или Safari, этот режим будет недоступен — это связано с тем, что API FileSystemHandle.requestPermission и FileSystemHandle.queryPermission все еще являются экспериментальными. Однако это означает только то, что вы не сможете пользоваться автоматической синхронизацией изменений шаблона инфраструктуры и вам придется загружать его вручную каждый раз, когда вы применяете изменения к своей схеме.
Теперь перейдем к самому интересному — перетаскиванию 🙂 В своем проекте я рисую следующую схему:
При проектировании своей инфраструктуры я решил спрогнозировать шаблон чтения-записи для своего приложения и предположил, что оно будет более тяжелым для чтения , следовательно, могут потребоваться другие подходы к масштабированию для операций чтения и записи. Поэтому я создал две функции Lambda, которые используют API Gateway в качестве источника событий. Вот и все!
Теперь вы можете перейти в папку вашего проекта и найти сгенерированный шаблон SAM. Application Composer даже определил политику выполнения DynamoDBCrudPolicy
для моих лямбда-функций (сузившись до ресурса ToDosTable — принцип наименьших привилегий, насколько это круто?). Тем не менее, я все же рекомендую вручную изменить его на DynamoDBReadPolicy
для нашей функции GetToDos
.
Реализация
Теперь давайте добавим немного кода перед локальной отладкой нашего приложения.
Давайте сначала определим наш преобразователь DynamoDB (я использовал для этого библиотеку @aws/dynamodb-data-mapper
):
const {
DynamoDbSchema,
DynamoDbTable,
DataMapper,
} = require("@aws/dynamodb-data-mapper");
class ToDoItem {
get [DynamoDbTable]() {
return process.env.TABLE_NAME; // Table name will be passed via environment variables
}
get [DynamoDbSchema]() {
return {
Id: {
type: "String",
keyType: "HASH",
},
Title: { type: "String" },
CreatedAt: {
type: "Number",
},
ModifiedAt: {
type: "Number",
},
CompletedAt: {
type: "Number",
},
};
}
}
class ToDoItemMapper {
constructor(client) {
this.mapper = new DataMapper({
client, // the SDK client used to execute operations
});
}
scan() {
return this.mapper.scan(ToDoItem);
}
getById(id) {
const item = new ToDoItem();
item.Id = id;
return this.mapper.get(item);
}
put(item) {
return this.mapper.put(item);
}
update(item) {
return this.mapper.update(item);
}
}
Наш обработчик списка будет выглядеть так просто:
const mapper = new ToDoItemMapper(ddbClient);
exports.handler = async () => {
const iterator = mapper.scan();
const todoItems = [];
for await (const record of iterator) {
todoItems.push(transform(record));
}
return {
statusCode: 200,
body: JSON.stringify(todoItems),
};
};
Обработчик CreateOrUpdate:
const mapper = new ToDoItemMapper(ddbClient);
const createToDo = async ({ title }) => {
if (!title) {
throw new Error(
"InvalidParameterException: title attribute is required"
);
}
const item = new ToDoItem();
const now = Date.now();
item.Id = uuid.v4();
item.Title = title;
item.CreatedAt = now;
item.ModifiedAt = now;
const persisted = await mapper.put(item);
return transformToModel(persisted);
};
const updateToDo = async (item) => {
if (!item.id) {
throw new Error("InvalidParameterException: id attribute is required");
}
const itemToUpdate = await mapper.getById(item.id);
itemToUpdate.ModifiedAt = Date.now();
itemToUpdate.Title = item.title;
itemToUpdate.CompletedAt = item.isCompleted === true ? Date.now() : undefined;
const persisted = await mapper.put(itemToUpdate);
return transformToModel(itemToUpdate);
};
exports.handler = async (event) => {
if (event.requestContext.httpMethod === "POST") {
const newItem = await createToDoItem(JSON.parse(event.body));
return {
statusCode: 200,
body: JSON.stringify(newItem),
};
}
if (event.requestContext.httpMethod === "PUT") {
const id = event.pathParameters.id;
const requestPayload = JSON.parse(event.body);
const updatedItem = await updateToDoItem({ ...requestPayload, id });
return {
statusCode: 200,
body: JSON.stringify(updatedItem),
};
}
return {
statusCode: 405,
body: "Method not supported",
};
};
Полный пример можно найти в моем репозитории на GitHub.
Локальный запуск
Теперь давайте попробуем запустить наше приложение локально, прежде чем развернуть его в рабочей среде. SAM уже поставляется с командой start-api
, которая запускает запросы маршрутизации локального экземпляра шлюза API в локальные среды выполнения Lambda. Однако нам нужно где-то сохранить наши данные. Самым простым решением было бы подключить наши локальные Lambdas к DynamoDB, работающему в облаке (например, если у вас есть некоторая промежуточная среда, которая воспроизводит производственную среду). Но для нашего примера предположим, что у нас еще нет настройки среды, и попробуем запустить базу данных DynamoDB в памяти локально:
docker run -p 8000:8000 amazon/dynamodb-local
И здесь возникает первая проблема: SAM также использует Docker для запуска локальных функций API Gateway и Lambda, а контейнер Docker НЕ запускает локальный процесс DynamoDB ВНУТРИ контейнера (< em>localhost) — любой запрос к http://localhost:8000
внутри функции Lambda завершится ошибкой.
Решение просто — создайте сеть Docker и явно укажите ее как для контейнеров SAM, так и для контейнеров DynamoDB!
docker network create sam-demo-net
docker run -p 8000:8000 --network sam-demo-net --name ddblocal amazon/dynamodb-local
sam local start-api --env-vars json/env.json --docker-network sam-demo-net
Теперь мы можем использовать функцию обнаружения служб Docker и получить доступ к локальной конечной точке DynamoDB, используя имя контейнера (ddblocal
):
const ddbClient = new DynamoDb({
...(process.env.AWS_SAM_LOCAL === "true"
? { endpoint: "http://ddblocal:8000" }
: {}),
});
Полные инструкции по запуску см. в файле README.
Теперь пришло время проверить это!
Вставьте элемент списка дел в таблицу, выполнив следующую команду CURL в командной строке:
curl -X POST -d '{"title":"test ToDo"}' http://127.0.0.1:3000/todos
{"id":"25962e09-7f16-4ab9-ac88-64f8c4a20710","title":"test ToDo","isCompleted":false}%
Давайте получим элементы списка задач из локального экземпляра DynamoDB, выполнив следующую команду CURL в командной строке:
curl http://127.0.0.1:3000/todos
[{"id":"25962e09-7f16-4ab9-ac88-64f8c4a20710","title":"test ToDo","isCompleted":false}]%
И, наконец, давайте выполним нашу задачу:
curl -X PUT -d '{"title":"test ToDo (completed)", "isCompleted": true}' http://127.0.0.1:3000/todos/25962e09-7f16-4ab9-ac88-64f8c4a20710
{"id":"25962e09-7f16-4ab9-ac88-64f8c4a20710","title":"test ToDo (completed)","isCompleted":true}%
Все работает — отлично! Давайте развернем!
Пора запускать!
С AWS SAM для развертывания достаточно выполнить одну команду:
sam deploy --guided
Флаг --guided
запустит мастер, который поможет настроить параметры развертывания (имя стека AWS CloudFormation, регионы AWS и т. д.). После того, как вы выполните этот мастер в первый раз, вам будет предложено сохранить эту настройку развертывания и повторно использовать ее в следующих развертываниях.
В результате этой операции SAM преобразует свой шаблон в формат, совместимый с CloudFormation, и создаст на его основе стек в аккаунте, который вы указали в конфигурации AWS SDK.
Заключительные мысли
Было бы интересно посмотреть, как эта служба будет развиваться в будущем. Будет ли представлен новый подход, который расширит «инфраструктуру как код» (IaC) — «инфраструктуру как схему» (IaD)? По крайней мере, было бы неплохо увидеть глубокую интеграцию с SAM API (развертывание, упаковка, начальная загрузка конвейера), которая предоставит пользователям «родной» способ предоставления инфраструктуры AWS непосредственно из консоли AWS Application Composer.
:::информация Первоначально опубликовано по адресу https://thesametech.com 4 января 2023 г.
:::
Вы также можете подписаться на меня в Twitter, подпишитесь на мой Telegram-канал, и подключитесь к LinkedIn чтобы получать уведомления о новых сообщениях!
Оригинал