Изучение микростеков, преимущества использования микростеков перед монолитными стеками, реализация микростеков с использованием Pulumi

Pulumi — это инструмент Инфраструктура как код (IaC) с открытым исходным кодом, который помогает разработчикам предоставлять и управлять облачной инфраструктурой с помощью различных поставщиков. Многие разработчики предпочитают использовать инструменты IaC из-за их согласованности. Другими словами, вы можете тиражировать инфраструктуру на разных этапах без написания сложных скриптов.

В настоящее время многие разработчики используют Pulumi для объявления инфраструктуры, следуя монолитной структуре проекта. Это означает, что вся инфраструктура управляется одним проектом Pulumi.

Однако Pulumi представила новую структуру проекта под названием «Микростеки». микростеки похожи на микросервисы. Они разбили один проект на несколько более мелких проектов.

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

Изучение микростеков

С точки зрения непрофессионала, микростеки — это эквивалент микросервисов в виде проектов/стеков. Вы делите свой основной проект на несколько меньших проектов и распределяете ресурсы между каждым проектом.

Микростеки против монолитных стеков

Монолитные стеки

Давайте посмотрим на пример приложения, управляемого с помощью ресурсов AWS, показанного ниже.

.
├── Pulumi.dev.yml
├── Pulumi.prod.yml
├── Pulumi.yml
├── api-gateway
│   ├── index.ts
│   ├── micro-service-01
│   │   └── index.ts
│   └── micro-service-02
│       └── index.ts
├── database
│   ├── table-01.ts
│   └── table-02.ts
├── index.ts
├── package-lock.json
├── package.json
├── ses
│   └── templates.ts
├── sns
│   └── topics.ts
└── sqs
└── queues.ts

Приведенная выше структура каталогов представляет собой один проект Pulumi (монолитный стек) с API-шлюзом, таблицами DynamoDB, темами SNS, очередями и шаблонами SES.

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

  • Отсутствие независимости: у вас может быть инфраструктура, такая как проверка домена, конфигурации VPC, которые редко меняются, а также функции Lambda (в вашем шлюзе API), которые часто меняются. Поэтому при использовании развертываний вам нужно будет внимательно следить за своей инфраструктурой, чтобы не допустить каких-либо ненужных изменений.
  • Отсутствие безопасности в отдельной инфраструктуре. Благодаря монолитной структуре проекта вы не можете ограничить развертывание ресурсов для определенных пользователей. Например, вам может потребоваться только руководитель вашей группы для развертывания основной инфраструктуры. Однако это невозможно сделать в монолитных стеках, поскольку разрешения создаются для всего стека.

Микростеки

Pulumi представила Micro-Stacks, чтобы смягчить обсуждаемые выше проблемы. Как уже говорилось, микростеки предназначены для разделения основного проекта на несколько более мелких проектов для лучшего обслуживания и эффективности.

Давайте взглянем на приложение, показанное ниже.

.
├── Pulumi.dev.yml
├── Pulumi.yml
├── api-gateway
│   ├── Pulumi.dev.yml
│   ├── Pulumi.yml
│   ├── index.ts
│   ├── micro-service-01
│   │   └── lambdas.ts
│   └── package.json
├── database
│   └── table.ts
├── index.ts
├── package.json
├── ses
│   └── templates.ts
├── sns
│   └── topics.ts
└── sqs
    └── queues.ts

В этом приложении мы видим два проекта Pulumi. Основной проект управляет ресурсами SES, темами SNS, очередями, таблицами DynamoDB. Другой проект Pulumi управляет шлюзом API. Это два микростека, так как мы успешно разбили сложный проект на два небольших проекта.

Этот подход принес множество преимуществ для разработчиков:

  • Дополнительная безопасность: пользователи могут предоставить определенным пользователям разрешение на развертывание определенных ресурсов, разделив их на отдельные стеки.
  • Улучшенная производительность. Благодаря микростекам каждый проект содержит меньше ресурсов. Поэтому время развертывания и сборки меньше, чем развертывание проекта монолитной структуры.
  • Улучшенная независимость. Вы можете выделить редко обновляемые ресурсы в отдельный стек, чтобы в них не вносились ненужные изменения.

Благодаря этим преимуществам многие разработчики начинают переходить на структуру на основе микростеков при управлении облачными ресурсами с помощью инструментов IaC.

Как мне разделить мой проект на микростеки?

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

  1. Вы можете разделить каждую микрослужбу в своем приложении на микростек.
  2. Вы можете разделить свои контейнерные и бессерверные функции на два стека, чтобы развертывать их независимо.
  3. Вы можете разделить свой проект на основе инфраструктуры. Например, вы можете разбить свою основную инфраструктуру, такую ​​как маршрутизация, DNS, VPC, в один стек, свои таблицы базы данных, темы SNS, очереди в другой стек и, наконец, шлюз API в другой стек.

При использовании микростеков вы можете задаться вопросом, как вы можете получить доступ к своим ресурсам в проектах Pulumi. Опять же, это область, в которой Pulumi преуспевает. С Pulumi внедрение микростеков и совместное использование ресурсов между стеками стало проще, чем когда-либо!

Внедрение микростеков с Pulumi

Чтобы понять, как вы можете реализовать микростеки, давайте рассмотрим демонстрацию пошаговой реализации микростеков.

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

Шаг 1: Предварительные условия

Прежде чем приступить к работе, убедитесь, что у вас есть:

  1. Pulumi CLI — используйте brew install pulumi или choco install pulumi для установки Pulumi.
  2. Учетная запись Pulumi. Создайте бесплатную учетную запись в Pulumi и аутентифицируйте свой CLI с помощью своей учетной записи Pulumi для выполнения развертываний.
  3. AWS CLI — загрузите и установите AWS CLI и настройте свой профиль AWS.

Шаг 2: Создание первого проекта Pulumi

Во-первых, давайте создадим проект Pulumi для предоставления таблицы DynamoDB.

Чтобы создать проект Pulumi, выполните приведенную ниже команду и следуйте инструкциям на экране.

pulumi new aws-typescript

Я назову проект как «core-infrastructure» и создам стек по умолчанию «dev» в регионе Вирджиния (us-east-1 ).

Шаг 3: Настройка первого проекта

После этого перейдите к index.ts и удалите весь код по умолчанию.

Откройте файл Pulumi.dev.yaml и добавьте приведенные ниже конфигурации.

config:
  aws:region: us-east-1
  core-infrastructure:env: development

Это поможет ссылаться на переменные стадии в разных стеках.

Затем создайте каталог dynamodb с одним файлом машинописного текста с именем user-table.ts, чтобы определить таблицу базы данных в корневом каталоге. Ваш каталог должен быть таким, как показано ниже.

.
├── Pulumi.dev.yaml
├── Pulumi.yaml
├── dynamodb
│   ├── note-table.ts
├── index.ts
├── package-lock.json
├── package.json
└── tsconfig.json

Откройте файл note-table.ts и добавьте код, показанный ниже.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); // retrive the config information stored in the pulumi.STACK-NAME.yaml file
const env = config.require('env'); // retrieve the env variable from the config file

export const notesTable = new aws.dynamodb.Table(${env}-notes-table , {
   billingMode: 'PAY_PER_REQUEST',
     attributes: [
       {
         name: 'id',
         type: 'S'
       }
     ],
   hashKey: 'id',
});

Фрагмент выше объявляет таблицу DynamoDB с пропускной способностью по запросу и хэш-ключом id.

Ранее я упоминал, что ваши ресурсы должны быть разделены между стеками. Для этого мы должны экспортировать ARN и имена ресурсов из текущего стека, чтобы на них можно было ссылаться в других стеках.

Для этого перейдите к входному файлу в вашем проекте Pulumi (index.ts) и добавьте фрагмент, показанный ниже.

import { notesTable } from './dynamodb/note-table';

export const notesTableName = notesTable.name;
export const notesTableArn = notesTable.arn;

Важно отметить, что при доступе к этим ресурсам из разных стеков мы должны обращаться к тем же именам переменных (notesTableName, notesTableArn), что и экспортируемые.

После этого мы можем подготовить таблицу DynamoDB, выполнив команду, показанную ниже.

// creates faster deployments by disabling previews.
pulumi up --skip-preview --stack stack-name --yes

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

Шаг 4. Создание второго проекта Pulumi

Вот тут-то и начинается самое интересное. Мы можем создать еще один проект Pulumi, отвечающий за поддержку часто изменяемого ресурса (API Gateway).

Мы можем использовать экспортированные имена таблиц из первого проекта и передать их лямбда-функциям второго проекта для выполнения операций CRUD над таблицей.

Чтобы создать второй проект Pulumi, выполните команду ниже.

pulumi new aws-typescript

Назовите проект как api-gateway и создайте проект в том же регионе, что и ваш первый проект. Для этого я буду использовать us-east-1.

Шаг 5: Добавление информации о проекте Referrer в новый проект

После создания нового проекта откройте файл Pulumi.dev.yaml и добавьте конфигурацию, показанную ниже.

config:
  aws:region: us-east-1
  api-gateway:env: development
  api-gateway:core-org: <<YOUR-ORGANIZATION-NAME>>
  api-gateway:core-stack: dev or <<REFERRER STACK for current dev>>
  api-gateway:core-project-name: core-infrastructure or <<REFERRER PROJECT NAME>>

В этой конфигурации добавлено три новых свойства. Эти три конфигурации помогают вновь созданному проекту ссылаться на ресурсы, экспортированные из core-infrastructure project (проект, который мы создали ранее).

  1. core-org: указывает, что организация в ссылающемся проекте присутствует.
  2. core-stack: указывает имя этапа ссылающегося стека.
  3. core-project-name: определяет название ссылающегося проекта Pulumi.

Шаг 6: Создание ссылки на стек и получение экспортированных ресурсов

После добавления этих конфигураций перейдите к index.ts и удалите весь сгенерированный код. Затем создайте новый файл с именем resources.ts в корневом каталоге и добавьте в него приведенный ниже код.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config();
const env = config.require("env");

// obtain the declared configs for the dev stack in api-gateway
const referrerProjectName = config.require("core-project-name");
const referrerOrganizationName = config.require("core-org");
const referrerStageName = config.require("core-stack");

// create a stack reference to obtain resources from the referrer stack
const coreInfrastructureReference = new pulumi.StackReference(${referrerOrganizationName}/${referrerProjectName}/${referrerStageName} );

// notesTableName is the value exported from core-infrastructure
export const noteTable = coreInfrastructureReference.requireOutput("notesTableName");

В приведенном выше фрагменте вы можете увидеть строку — new Pulumi.StackReference(). Он отвечает за установление соединения со стеком реферера. Для этого конструктора требуется строка формата organization/project/stack.

Обратите внимание, что проект должен быть связан с вашей организацией.

После этого экспортированные переменные импортируются вызовом метода requireOutput('resourceNameExportedInReferrer').

Шаг 7. Объявление микрослужбы Notes

В корневом каталоге создайте новый каталог с именем notes, а внутри него создайте файл с именем lambda.ts. Этот файл объявит микросервис и его лямбда-функцию, добавив приведенный ниже код в файл lambda.ts.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
import { noteTable } from "../resources"; // import the table
import { nanoid } from 'nanoid';

const config = new pulumi.Config();
const env = config.require("env");

export const createNote = new aws.lambda.CallbackFunction(${env}-create-note , {
   callback: async (event: awsx.apigateway.Request, context): Promise<awsx.apigateway.Response> => {
     const documentClient = new aws.sdk.DynamoDB.DocumentClient();
     const { title, body } = JSON.parse(event.body as string);
     const noteId = nanoid();
     const note = {
     // hashkey as "id" as defined in core-infrastructure table.id: noteId,
       title,
       body,
     }
      
     await documentClient.put({
       TableName: noteTable.get(),
       Item: note,
     }).promise();
      
     return {
       statusCode: 200,
       body: JSON.stringify(note),
     }
  }
})
      
export const deleteNote = new aws.lambda.CallbackFunction(${env}-delete-note , {
   callback: async (event: awsx.apigateway.Request, context): Promise<awsx.apigateway.Response> => {
      const documentClient = new aws.sdk.DynamoDB.DocumentClient();
      const { id } = JSON.parse(event.body as string);
      
      await documentClient.delete({
         TableName: noteTable.get(),
         Key: { id },
      }).promise();
      
     return {
       statusCode: 200,
       body: 'Note deleted',
     }
   }
})
      
export const getAllNotes = new aws.lambda.CallbackFunction(${env}-get-all-notes , {
   callback: async (event: awsx.apigateway.Request, context): Promise<awsx.apigateway.Response> => {
      const documentClient = new aws.sdk.DynamoDB.DocumentClient();
      const { Items = [] } = await documentClient.scan({
         TableName: noteTable.get(),
      }).promise();
      
      return {
         statusCode: 200,
         body: JSON.stringify(Items),
      }
   }
})

Три лямбда-выражения, объявленные выше, обеспечивают операции создания, обновления и получения в таблице Notes.

Вы могли заметить, что для TableName мы указали - noteTable.get() . Это метод, предлагаемый Pulumi для получения имени таблицы при ее выполнении в среде после развертывания.

Шаг 8: Добавление шлюза API

После этого мы можем создать шлюз API для вызова функций Lambda через HTTPS.

Перейдите к файлу index.ts и добавьте код, показанный ниже, чтобы добавить шлюз API.

import * as pulumi from "@pulumi/pulumi";
import * as awsx from "@pulumi/awsx";
import * as notes from './notes/lambdas';

const config = new pulumi.Config();
const env = config.require("env");

// create the API Gateway by defining HTTP Methods, Routes, Handlers
const apiGateway = new awsx.apigateway.API(${env}-api-gateway , {
 routes: [
   {
     path: '/notes/create',
     method: 'POST',
     eventHandler: notes.createNote,
   },
   {
     path: '/notes/delete',
     method: 'POST',
     eventHandler: notes.deleteNote,
   },
   {
     path: '/notes',
     method: 'GET',
     eventHandler: notes.getAllNotes,
   }
 ],
 restApiArgs: {
   binaryMediaTypes: []
 }
});

// export the URL used to invoke the API Gateway    
export const { url } = apiGateway;

Фрагмент, показанный выше, создаст шлюз API с тремя конечными точками, которые используют три функции Lambda, объявленные ранее.

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

pulumi up --skip-preview --stack dev --yes

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

После этого вы можете использовать экспортированную переменную — url для вызова объявленных маршрутов для связи с API.

И вот как вы реализуете микростеки в Pulumi!

Когда следует использовать микростеки?

Поняв, как реализовать микростеки, важно знать, когда следует использовать структуру проекта микростеков. Используйте структуру проекта с микростеком, если:

  1. В вашем монолитном проекте много ресурсов, но часто обновляются только ограниченные ресурсы.
  2. В вашем проекте есть компонент, требующий дополнительных затрат времени на развертывание. Например, у меня возникла проблема, когда один компонент моего проекта Pulumi вызывал обновления от 15 до 30 минут. Изоляция этого компонента в микростеке помогла сократить время развертывания до 6 минут!

Прежде чем выбрать микростеки, вы должны рассмотреть эти моменты, чтобы определить, нужны ли вам микростеки.

Заключение

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

Код, реализованный в этой статье, доступен в моем репозитории GitHub.

Я надеюсь, что вы нашли эту статью полезной.

Спасибо за чтение.

Создавайте компонуемые веб-приложения

Не создавайте веб-монолиты. Используйте Bit для создания и компоновки несвязанных программных компонентов — в ваших любимых средах, таких как React или Node. Создавайте масштабируемые и модульные приложения с мощными и приятными возможностями разработки.

Перенесите свою команду в Bit Cloud, чтобы вместе размещать компоненты и совместно работать над ними, а также ускорять, масштабировать и стандартизировать разработку в команде. Попробуйте компонуемые внешние интерфейсы с помощью Design System или Микроинтерфейсы или изучите компонуемые внутренние интерфейсы с серверными компонентами. .

Попробуйте →

Узнать больше