.NET Aspire — империя дотнета наносит ответный удар

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

Особенно, учитывая какую дичь часто завозят в шарп (например те же ужасно спроектированные Primary Constructor’ы про которые я писал, или вот прикол-пропозал от самого Тоуба). Так что ожидания у меня, честно говоря, были ниже нуля.

Но попробовав его лично, я был, честно говоря, шокирован. Трепещите, жависты! Трепещите гошники! Трещепищите питонисты — такого вы еще точно не видели.

Я даже представить не мог, что DevEx можно сделать настолько офигительным.

Эта картинка с Рэнди Ортоном - символизирует меня, ошеломленного великой мощью Aspire

Эта картинка с Рэнди Ортоном — символизирует меня, ошеломленного великой мощью Aspire

Собственно, о чем это я

Так вот, что же такое .NET Aspire?

> .NET Aspire is an opinionated, cloud ready stack for building observable, production ready, distributed applications. .NET Aspire is delivered through a collection of NuGet packages that handle specific cloud-native concerns. Cloud-native apps often consist of small, interconnected pieces or microservices rather than a single, monolithic code base.

Aspire — это темплейт + opinionated стек для микросервисных приложений. Он предоставляет следующие фичи:

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

  • Готовый тулинг — в темплейте, Aspire по умолчанию генерит код и настройки для OpenTelemetry — логи, метрики и трейсы — трех столбов observability. Не нужно возиться с секретами, каким-то своим поднятием Prometheus’а — Aspire сам коллектит всю телеметрию с сервисов, чтобы затем показывать это все в админке

  • Крутой локальный дашборд — все метрики, список контейнеров, логи, трейсы — в одной готовой админке, причем смотрящейся достаточно неплохо. Не надо ничего поднимать локально в докер композах — ни графану ни прометеус. Коллектор .NET Aspire’а получит все самостоятельно

  • Легкий деплой в Azure/k8s — по словам команды которая работает над Aspire, на релизе можно будет в одну кнопку запубликовать весь проект на облако в Azure, либо сгенерировать k8s манифесты чтобы разворачивать на своей/чужой инфраструктуре

Например — у вас есть продукт который находится в монорепе на 30 сервисов. Как правило, в микросервисах про локальное тестирование работы нескольких сервисов одновременно можно забыть — самому это настраивать как правило очень больно. С Aspire — вы сможете без проблем локально потестить то что вам надо, например сценарии failover’ов.

Хотя Aspire и ориентирован в первую очередь на распределенные приложения, его можно применять даже если у вас всего один сервис — например чтобы локально продебажить observability — посмотреть собираются ли локально метрики и трейсы. На мой взгяд — достаточно полезно.

Простота интеграции в существующие проекты

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

На на самом деле, все невероятно просто. Надо сделать всего две вещи:

  1. Создать отдельный проект AppHost, и в нём зареферить проекты которые ты хочешь запустить, в DistributedApplicationBuilder зарегистрировать соответствующие проекты

  2. Для нужных фичей, которые идут в Aspire из коробки (например OpenTelemetry, Service Discovery, коннект в PostgeSQL), нужно поставить отдельный Nuget и просто заменить регистрацию в Startup, либо вызвать Extension метод из ServiceDefaults

Всё! Aspire настроен.

Погнали тестить

Давайте теперь глянем на примере. Возьмем стандартный Starter Application темплейт.

Для начала, надо поставить Aspire. Для этого выполняем две команды:

dotnet workload update
dotnet workload install aspire

Если вы используете Rider, так же как и я, то нужно дополнительно поставить плагин: https://blog.jetbrains.com/dotnet/2024/02/19/jetbrains-rider-and-the-net-aspire-plugin/

Если используете Preview версию Visual Studio, насколько я помню там Aspire поставлен по умолчанию.

Итак, генерируем проект в нашей IDE, получаем следующую структуру:

Структура проекта

Структура проекта

Быстренько пробежимся по проектам:

  • TestAspire.AppHost — основной проект где мы описываем наше распределенное приложение — какие контейнеры поднимать (База, Брокер, Кэш), что от чего зависит, и так далее.

  • TestAspire.ServiceDefaults — проект, содержащий extension method’ы для телеметрии, Service Discovery и другие настройки. Этот проект подключается во все остальные

  • TestAspire.ApiService — API на ASP.NET Core, обычный WeatherApi из темплейта для webapi

  • TestAspire.Web — Blazor фронтенд приложение, тоже дефолтный темплейт для блазора

AppHost

Данный проект является ядром всего Aspire. По сути, чтобы Aspire подключить и воспользоваться его фишками, достаточно только добавить этот проект, и прикрутить нужные нам зависимости. Сам проект состоит всего из одного файла (не считая appsettings.json), со следующим содержимым:

// Program.cs
var builder = DistributedApplication.CreateBuilder(args);

var apiService = builder
  .AddProject("apiservice");

builder.AddProject("webfrontend")
    .WithExternalHttpEndpoints()
    .WithReference(apiService);

builder.Build().Run();

Недурно, верно? За плату в 10 строк и 1 проект, мы получаем набор невероятных фичей, работающих из коробки, про которые я писал ранее (админка, телеметрия, и т.д).

Здесь важна именно регистрация сервисов:

var apiService = builder
  .AddProject("apiservice");

builder.AddProject("webfrontend")
    .WithExternalHttpEndpoints()
    .WithReference(apiService);

Чтобы добавить проект, достаточно. Строка в методе — это название сервиса либо контейнера если приложение будет докеризированно. Для Api мы просто добавляем проект, но для Blazor — мы дополнительно добавляем референс на apiService — я покажу это дальше, это будет использоваться для Service Discovery .

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

// Качаем доп нугет пакет - Aspire.Host.Postgres
// Есть еще подобные для Kafka, Redis, и другой инфры
builder.AddPostgres("database").WithPgAdmin();

Т.е фактически, теперь не надо хранить кучу docker-compose.yaml с инфраструктурой. Не надо писать shell скрипты или makefile’ы чтобы их запускать. Не нужно ничего запускать вручную. Не надо париться насчет volume’ов, network’ов и прочих вещей между контейнерами, когда ты к примеру подключаешь локально тот же Postgres. Не нужно настраивать env переменные контейнеров. Захотел к постгресу подключить pgadmin — сделал это в одну строку, без конфигурации с оригинальным докером.

И все работает мать его локально. Из коробки. С докером и инфрой.

Это. Просто. Топ.

ServiceDefaults

Этот проект — добавляет некие «платформенные» extension методы, которые подключают одинаковые инфраструктурные библиотеки во все проекты внутри Solution’а. По умолчанию при генерации темплейта, там настроен сбор телеметрии. В случае, если надо добавить какой-то особый коллектор (например Prometheus), то этот код добавляется именно туда.

Метод builder.AddServiceDefaults(); добавляет все нужные зависимости в executable проекты.

ApiService

Обычное webapi приложение для погоды, из темплейта. Не отличается вообще ничем от дефолтного, кроме как добавлением ServiceDefaults:

// Program.cs -> ApiService
...
...

builder.AddServiceDefaults();

...
...

Web

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

// Program.cs

// 1
builder.AddServiceDefaults();

// 2
builder.Services.AddHttpClient(client =>
{
    // This URL uses "https+http://" to indicate HTTPS is preferred over HTTP.
    // Learn more about service discovery scheme resolution at https://aka.ms/dotnet/sdschemes.
    client.BaseAddress = new("https+http://apiservice");
});

Здесь изменение не одно, а два:

  1. Добавляем дефолтные сервисы (телеметрию, настройки) из ServiceDefaults

  2. Добавляем http клиента на ApiService, но в особом формате адреса — https+http://apiservice. Это позволит воспользоваться Service Discovery — не хардкодить url’ы между проектами. Aspire сделает это автоматически.

Админка стандартного Blazor приложения. Дезигн конечно неоч, но зато работает

Админка стандартного Blazor приложения. Дезигн конечно неоч, но зато работает

Дашборд Aspire

Больше всего в разработке я обожаю две вещи: Developer Experience и красивый визуал. В обоих этих пунктах я всегда стараюсь дотошно выстраивать мой флоу разработки — я сильно запариваюсь на ранних стадиях проектов, чтобы их можно было легко тестировать и дебажить локально.

И готовая админка, которую тебе не надо поднимать и как-то там настраивать — это прям бальзам на душу.

Покажу основные страницы куда точно стоит зайти. Начнем с основной:

Resources

Страница ресурсов - тут показываются все контейнеры приложения

Страница ресурсов — тут показываются все контейнеры приложения

Здесь у нас список всех контейнеризованных приложений. Тут могут быть как .NET приложения, так и обычные имаджи, например тот же Postgres или Kafka. Тажке можно фронт запускать, все что запускается через npm — например тот же Vue на vite или Next.js.

У каждого приложения есть статус, описание, а также ссылки на просмотр логов, деталей по контейнерам и на enpoint (например на swagger). Достаточно удобно.

Сюда еще много что хотят прикрутить, например видел пропозал на кнопку для рестарта сервисов, если они упали. (Ссыль на issue)

Traces

Мое любимое - трейсинг. Причем, выглядит даже лучше чем в Jaeger'е по умолчанию

Мое любимое — трейсинг. Причем, выглядит даже лучше чем в Jaeger’е по умолчанию

Есть страница с тресами — причем заметьте, оно отлично работает в совокупе! На скрине как раз показан пример с трейсами покрывающими сразу два сервиса — фронт и вебапи. Причем хочу заметить, сама страница выглядит неплохо, на мой личный взгляд сильно красивее чем дефолтная страница Jaeger’а.

Structured logs

Страница с структурными логами

Страница с структурными логами

Точно также есть инфа по логам — плюс хочу обратить внимание, в проекте по умолчанию настроена привязка логов к трейсам — и по некоторым логам, которые относятся к запросам можно вытянуть и посмотреть на трейс

Metrics

Страница с метриками. Прикольно что для дефолтных метрик тут собирается описание

Страница с метриками. Прикольно что для дефолтных метрик тут собирается описание

Метрики могут быть как свои, так и дефолтные. Дефолтных метрик достаточно много — и данные по GC, и по локам, по kestrel’у, много по чему.

Это только начало…

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

Если это всего лишь превью, то мне даже страшно представить чего ждать от релиза. И я если честно не представляю, как другие платформы собираются конкурировать с дотнетом по удобству разработки (кроме наверное разве что Vercel — они тоже невероятно крутые штуки делают, там удобство разработке как минимум не уступает)

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

© Habrahabr.ru