Слышали ли вы о новом супергерое в мире .NET — Aspire? .NET Aspire — это амбициозный проект, цель которого — предоставить разработчикам удобный способ создания современных облачных распределенных приложений.

Дисклеймер: я не буду предоставлять пошаговое руководство, поскольку компания Microsoft проделала огромную работу по написанию понятной документации. Я лишь покажу несколько интересных концепций и расскажу о том, где, на мой взгляд, проект Aspire не справился со своими обещаниями. Если вы еще не читали обзор .NET Aspire, сделайте это, прежде чем продолжить чтение статьи.

Считается ли стек Aspire экспериментальным?

Если вы следили за выставкой Microsoft Build 2024, то знаете, что стек .NET Aspire прошел экспериментальную фазу разработки и теперь общедоступен.

Aspire, который возник из реального эксперимента под названием Tye, представляет собой следующую итерацию этого проекта. Tye был экспериментальной площадкой для команды .NET, на которой она тестировала новые идеи и концепции. Сейчас Tye выведен из эксплуатации, что в конечном итоге привело к разработке Aspire.

Примечание: для работы с Aspire необходимо загрузить последнюю версию Visual Studio 2022 или JetBrains Rider.

Что такое Aspire?

Понять, что же такое Aspire на самом деле, непросто. Aspire обещает облегчить работу с сервисами и облачными ресурсами в локальных средах. Вы можете сказать, что для решения этой задачи уже есть различные инструменты, такие как контейнеры, Docker-Compose, Rancher, Docker Desktop и многие другие. Вы правы, но Aspire продвинулся еще на один шаг дальше, чтобы расширить возможности разработчиков. Aspire утверждает, что все, что вам нужно, — это IDE, C# и докерная среда выполнения, работающая в фоновом режиме (например, Docker Desktop). Всего этого достаточно, чтобы запустить и отладить мультисервисное приложение и легко использовать внешние сервисы, такие как Redis или базы данных, на локальном компьютере.

Что предлагает Aspire?

Защитные механизмы

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

Aspire выбрал такой же подход. Aspire — это высоконадежная платформа с расширенным набором инструментов. Aspire делает ставку на контейнеры, Open Telemetry и расширения для IDE (Visual Studio 2022 или JetBrains Rider).

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

Пакеты NuGet

Фундаментальной структурной единицей Aspire являются компоненты, которые представляют собой пакеты NuGet. Компоненты Aspire предназначены для интеграции приложения с различными облачными сервисами и платформами. Компания Microsoft выбрала для Aspire несколько сервисов, включая сервисы Azure и проекты с открытым исходным кодом. Microsoft уже подготовила компоненты для SQL Server, RabbitMQ и Kafka. Полный список компонентов можно посмотреть здесь.

Инструментарий

Компоненты полезны, но их одних недостаточно. Инструментарий — это то, что делает Aspire таким интересным. Инструментарий включает набор инструментов командной строки или расширений IDE, которые помогают работать с компонентами Aspire. В настоящее время он поддерживает Visual Studio 2022, JetBrains Rider и .NET CLI.

Инструментарий охватывает следующие области:

  • оркестрирование нескольких служб;
  • запуск и отладку приложений .NET;
  • распространение общих настроек с помощью переменных среды;
  • запуск и остановку контейнеров Docker для облачных ресурсов (Redis, SQL Server и т. д.);
  • мониторинг и трассировку приложения.

Тем не менее есть некоторые аспекты, в которых Aspire не оправдывает своих обещаний.

Развертывание

Aspire — это не только стек для локальной разработки. Он также предназначен для развертывания.

Можно запустить dotnet build со специальной целью, чтобы сгенерировать манифест Aspire.

Пример манифеста Aspire:

{
"resources": {
"api": {
"type": "project.v0",
"path": "../WebApplication1/WebApplication1.csproj",
"env": {
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http"
},
"https": {
"scheme": "https",
"protocol": "tcp",
"transport": "http"
}
}
},
"eventhubs": {
"type": "azure.bicep.v0",
"path": "eventhub.bicep",
"parameters": {
"eventHubNamespaceName": "mynamespace",
"principalId": "",
"principalType": "",
"eventHubs": ["hub1"]
}
}
}
}

В этом примере показан манифест с двумя ресурсами: проектом .NET и конфигурацией Azure Event Hub.

Манифест — промежуточный формат, созданный для Aspire. Сторонние инструменты развертывания могут использовать манифест Aspire для развертывания приложений на различных облачных платформах.

Звучит слишком хорошо, чтобы быть правдой? Да, именно так, поэтому стоит проверить, не обещает ли Aspire больше, чем выполняет.

Поддержка оставляет желать лучшего

Сегодня можно развернуть приложение Aspire в Azure Container Apps и Kubernetes (через Aspir8). Встроенная поддержка других облачных сервисов (Amazon, Google Cloud) в настоящее время практически отсутствует, хотя со временем может расшириться.

Настройка развертывания

Даже если вас устраивает использование Azure Container Apps или Kubernetes, есть и другие проблемы. Одна из них — настройка.

Открыв пример проекта Aspire, можно увидеть примерно следующее:

var builder = DistributedApplication.CreateBuilder(args);

var sql = builder.AddSqlServer("sql")
.WithDataVolume()
.AddDatabase("sqldata");
builder
.AddProject<Projects.AspireApp007_ApiService>("apiservice")
.WithReference(sql);
builder.Build().Run();

Этот код запускает приложение локально как обычный проект .NET API, а база данных SQL работает как контейнер в локальной среде выполнения Docker. Но как думаете, что произойдет, когда вы выполните следующую команду?

azd up

Azd CLI интерфейс командной строки от Microsoft Azure, который позволяет разработчикам управлять и автоматизировать сервисы Azure.

Приведенный выше код автоматически создаст несколько новых ресурсов Azure в вашей подписке:

Запуск azd up создает новую группу ресурсов и развертывает несколько облачных ресурсов. Однако модель предоставления, используемая для базы данных SQL, остается неясной.

Я не смог найти никакой информации об этом в документации, поэтому проверил свойства контейнера.

Видно, что azd выбрал 0,5 ядра процессора и объем памяти 1 Гб. Вероятно, это разумные настройки по умолчанию для тестирования или локальной разработки. Но чтобы обновить их до производственной версии, нужно использовать следующую команду:

azd infra synth

При этом создается несколько Yaml-файлов, которые можно настроить для изменения параметров облачных ресурсов. Например, если требуется, чтобы контейнер для SQL использовал больше памяти, нужно обновить файл {имя ресурса}.tmpl.yaml следующим образом:

...
containers:
- image: {{ .Image }}
name: sql
# добавьте эти три строки
resources:
cpu: "1" # Установите ограничения по CPU (например, 1 CPU)
memory: "2Gi" # Установите ограничения по памяти (например, 2 Гб)
...

Как по мне, этот процесс немного громоздок. Правда, команда Aspire утверждает, что в дальнейшем можно будет настраивать его с помощью C#.

Локальный оркестратор

Локальный оркестратор Aspire предназначен только для среды разработки. Это означает, что разработчики используют оркестратор Aspire для локальной разработки, а Kubernetes — для производства. Таков рекомендуемый подход на данный момент.

Проиллюстрирую проблему на примере. В манифесте Aspire не отражены настройки реплик, а это значит, что любой инструмент развертывания фактически игнорирует строку WithReplicas.

var apiService = builder
.AddProject<Projects.AspireApp007_ApiService>("apiservice")
.WithReference(sql)
.WithReplicas(3); // только для локальной разработки

Локально у вас есть три реплики, но чтобы иметь три реплики в кластере Kubernetes, все равно нужно вручную обновить развертывание.

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

Предназначен ли Aspire только для монорепозиториев в настоящее время?

И да, и нет. Aspire — инструмент разработки, поэтому для получения максимальных преимуществ необходимо загружать все проекты локально. Это непросто, поскольку крупные приложения состоят из сотен микросервисов. Мало кто захочет запускать сотни микросервисов на своем локальном компьютере.

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

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

Например, рассмотрим ситуацию, когда команда разработчиков создает IoT-платформу с высоким трафиком, требующую обработки больших объемов неструктурированных данных. Идеальным выбором для такого сценария была бы база данных NoSQL. Однако, поскольку Aspire поддерживает базы данных SQL, команда решает использовать базу данных SQL. Это решение приведет к узким местам в производительности и проблемам масштабирования. Принять решение о том, какой облачный ресурс использовать, сегодня достаточно сложно, а новые инструменты Aspire еще более усложняют ситуацию.

Неподдерживаемые облачные ресурсы

Как уже говорилось, Aspire включает встроенную поддержку различных облачных ресурсов, таких как Redis, SQL Server и Azure Service Bus. Но что, если нужен ресурс, который не поддерживается, например база данных NoSQL типа Cassandra? Aspire поддерживает не все базы данных и сервисы. Следовательно, вам придется вручную подключать эти неподдерживаемые ресурсы, лишаясь таких ключевых преимуществ Aspire, как наблюдаемость и простота локальной разработки.

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

Что касается более позитивных моментов, то есть возможность написать собственную обертку для Aspire — вот руководство. Оно не выглядит слишком сложным, поэтому я предполагаю, что авторы облачных ресурсов могут написать такие обертки Aspire в будущем.

Один из удивительных фактов — Aspire 1.0 не поддерживает Azure Functions, что довольно странно, учитывая, что Azure Functions являются ключевой функциональной особенностью Azure. Однако поддержка Azure Functions уже включена в дорожную карту.

Aspire как инструмент маркетинга

Можно также рассматривать Aspire как маркетинговый инструмент. Думаю, ни для кого не секрет, что Microsoft пытается привлечь больше разработчиков к использованию платформы .NET и Azure Cloud. Minimal API — отличный пример этого. Он создан не для разработчиков старой школы .NET, которым нравится иметь дело с определенным уровнем сложности — контроллерами, маршрутизацией, program.cs vs startup.cs и т. д. (шучу, конечно). Minimal API, похоже, предназначен для разработчиков нового поколения, переходящих из экосистем Node.js или Python.

Я рассматриваю Aspire как одну из таких кампаний Microsoft по адаптации новых пользователей. Упрощенные инструменты более привлекательны для новичков, которые могут быть обескуражены сложностью традиционных приложений ASP.NET.

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

Эффективное интеграционное тестирование

Aspire предлагает более эффективный подход к интеграционному тестированию, позволяя проводить тестирование на реальных облачных ресурсах без необходимости развертывания приложения в облаке. Таким образом, можно выявить ошибки, пропущенные при тестировании на имитационных данных. Это хорошо иллюстрирует известный мем:

Однако будьте внимательны. Некоторые ресурсы слишком тяжелы для запуска в локальной среде, а некоторые даже не могут быть запущены локально, например Azure Service Bus — семь лет ждем.

Команда Aspire тоже думает над этим вопросом, и, похоже, готовится представить полную slim-версию компонентов Aspire. Это означает, что в будущем может появиться возможность запускать slim-версию ресурса, содержащую только фиктивные данные. На этом этапе мы пройдем полный круг.

  1. До Aspire: тестирование с использованием имитационных данных.
  1. После Aspire 1.0: тестирование на реальном ресурсе.
  1. Aspire в будущем: тестирование на slim-сервисе с имитированными данными

Но довольно рассуждений. Поговорим лучше о том, где можно применять Aspire.

Варианты использования Aspire

Для меня очевидны несколько подходящих вариантов использования Aspire 1.0.

  1. Новое приложение, содержащее несколько микросервисов (ключевое слово в данном случае — «несколько»). Если у вас много микросервисов, то в итоге в Aspire будет много компонентов, что затруднит управление ими в едином репозитории.
  1. Эксперименты с новыми облачными ресурсами. Если вам нужно изучить или опробовать новый облачный сервис, а Aspire его поддерживает, проще всего создать новое приложение Aspire и добавить несколько строк кода на C# для тестирования нового компонента. До появления Aspire пришлось бы искать клиент C#, контейнер Docker, управлять настройками и т. д. Готовые компоненты Aspire дают огромное преимущество для таких случаев использования.
  1. Существующие приложения, которые состоят максимум из трех микросервисов с несколькими облачными ресурсами, поддерживаемыми Aspire (SQL, Redis). Я попытался преобразовать одно из своих более простых приложений в модель приложения Aspire. Хотя шаблон Aspire не распознал, что я использую Directory.Packages.props, неправильно разместил Service Defaults и разделил вещи в неправильных пространствах имен, потребовалось всего несколько минут, чтобы заставить его работать. Количество проблем оказалось на удивление меньше, чем ожидалось.

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

Амбиции Aspire

В чем я не уверен, так это в амбициях Aspire. В настоящее время он, похоже, ориентирован на проекты на C# и Azure. Однако Aspire также включает поддержку NodeJS. Поддержка NodeJS, несмотря на свои ограничения (отсутствие поддержки реплик), намекает на амбициозные цели Aspire в будущем.

// NodeJS:
var apiService = builder
.AddProject<Projects.AspireApp007_ApiService>("apiservice")
.WithReference(sql)
.WithReplicas(3);

builder
.AddNodeApp("NodeTest", "./start.js")
.WithReplicas(3) // этот метод отсутствует

Aspire также поддерживает как хост Docker, так и хост Podman. Я протестировал примеры приложений с помощью Podman и Docker — они работали в обоих случаях. Хотя знаю, что Podman стремится быть совместимым с API Docker, это все равно приятная особенность и продуманный подход со стороны Aspire.

Если исследовать GitHub на предмет проблем Aspire, то можно обнаружить множество новых запросов по функциональности, причем довольно часто разработчики Aspire отвечают на них положительно. Я уже упоминал о полных или slim-ресурсах и определении облачного развертывания в коде C#. Но идей гораздо больше, например, поддержка не-NET-микросервисов, интеграция с Pulumi, интеграция AWS и GCP и многое другое.

Вердикт

У Aspire большие амбиции. В наше время он может стать полезным инструментом для новых проектов, работающих в Azure.

Но все же есть несколько проблем.

  • Одно из ограничений заключается в том, что все микросервисы должны быть в .NET 8. Классический .NET в настоящее время не поддерживается и, вероятно, не будет поддерживаться в будущем.
  • Если у вас несколько микросервисов и один или два облачных ресурса (БД, шина сообщений и т. д.), вы в хорошем положении. Однако если вы используете сложный монолит или сотни микросервисов, найти подходящее место для начала тестирования и оценки Aspire будет непросто.
  • Aspire способен повлиять на общую архитектуру проекта. Разработчики могут предпочесть ресурсы, поддерживаемые Aspire, ресурсам, которые больше подходят для их использования, но требуют более тщательного обслуживания.
  • Aspire все еще нуждается в дополнительной функциональности, чтобы стать более универсальным продуктом. Текущая версия Aspire в значительной степени ориентирована на Azure и C#.

Учитывая эти сдерживающие факторы, предположу, что процесс внедрения Aspire будет не быстрым. Тем не менее, с нетерпением жду, когда Aspire справится с различными проблемами, чтобы стать общепризнанным и проверенным инструментом. Видимо, команде Aspire предстоит выполнить значительный объем работы.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Marek Sirkovský: .NET Aspire — Aspiring for Sanity in Cloud Development

Предыдущая статья21 рекомендация по HTML
Следующая статьяОбзор курса “Полное введение в React” от Frontend Masters