Создайте свою инфраструктуру с помощью простой диаграммы

Создайте свою инфраструктуру с помощью простой диаграммы

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 чтобы получать уведомления о новых сообщениях!


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE