Mittelstand Radar : Signaux d'achat du Mittelstand allemand — réservez dès maintenant votre première édition du rapport.Rejoindre la liste d'attente
Dessins architecturaux abstraits et plans sur une table lumineuse
Retour au blog
dotnetaspirearchitecture

Aspire 13 : nouvelle architecture, nouvelle expérience développeur

Sven HennessenDevOps

Aspire 13 ne s'est pas contenté de recevoir de nouvelles fonctionnalités : toute son architecture interne a été reconstruite. Le modèle pipeline, l'AppHost en fichier unique et le support TypeScript changent la manière de travailler avec Aspire.

La plupart des changements visibles dans Aspire 13 sont des fonctionnalités : nouvelles cibles de déploiement, nouveaux langages, nouvelles intégrations. Moins visibles mais plus fondamentales sont les évolutions sous-jacentes : la manière dont Aspire coordonne en interne les étapes de déploiement, à quoi ressemble l'AppHost lui-même et comment la surface CLI est structurée. Cet article décrit les décisions architecturales qui rendent tout le reste possible.

La fin du modèle publisher

Dans Aspire 9, il existait un modèle d'extension pour le déploiement : l'interface IDistributedApplicationPublisher. Toute personne souhaitant construire un chemin de déploiement personnalisé implémentait cette interface, l'enregistrait via WithPublishingCallback et recevait un PublishingContext. Le modèle était séquentiel, difficile à tester et fortement couplé au format du manifest.

Aspire 13 a entièrement supprimé ces APIs. Le remplacement est le modèle pipeline.

Le modèle pipeline : PipelineStep et graphe de dépendances

Au lieu d'un publisher central, les ressources dans l'AppHost contribuent désormais avec leurs propres objets PipelineStep. Chaque étape déclare explicitement de quelles autres étapes elle dépend. Aspire construit un graphe orienté à partir de ces dépendances et exécute en parallèle les étapes indépendantes.

resource.WithPipelineStepFactory((context, steps) =>
{
    var build = steps.AddStep("build-image", async ctx => {
        // build container image
    });
    var push = steps.AddStep("push-image", async ctx => {
        // push image to registry
    }).DependsOn(build);
    var deploy = steps.AddStep("deploy", async ctx => {
        // deploy to cluster
    }).DependsOn(push);
});

Le résultat est un processus de déploiement qu'Aspire parallélise partout où les dépendances l'autorisent. Les images de services indépendants sont construites et poussées simultanément ; le provisionnement et le build s'exécutent en parallèle tant qu'aucune étape n'a besoin du résultat d'une autre.

Le pipeline est inspectable avant exécution :

aspire deploy --list-steps              # show all steps and dependencies
aspire deploy --pipeline-log-level debug  # verbose output per step
aspire deploy --environment staging       # target a specific environment

Persistance de l'état de déploiement

Un changement simple mais efficace : Aspire 13 se souvient, d'un déploiement à l'autre, de ce qui a déjà été saisi.

Dans Aspire 9, azd up redemandait l'abonnement, la région et le groupe de ressources à chaque exécution. Dans Aspire 13, ces entrées sont enregistrées par projet et par environnement dans le profil utilisateur :

~/.aspire/deployments/<project-hash>/<environment>.json

L'appel suivant à aspire deploy préremplit ces valeurs. --clear-cache réinitialise l'état sauvegardé. Toute personne passant d'un environnement à l'autre donne le nom via --environment :

aspire deploy --environment production
aspire deploy --environment staging --clear-cache

Single-file AppHost

Auparavant, chaque projet Aspire nécessitait son propre fichier projet C# avec les package references. Depuis Aspire 13, un AppHost peut être écrit dans un seul fichier sans .csproj séparé :

#:sdk Aspire.AppHost.Sdk@13.0.0
#:package Aspire.Hosting.PostgreSQL@13.0.0
#:package Aspire.Hosting.Redis@13.0.0

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");
var db = builder.AddPostgres("db");
var api = builder.AddProject<Projects.Api>("api")
    .WithReference(cache)
    .WithReference(db);

builder.Build().Run();

Les directives #:sdk et #:package remplacent le fichier projet. Le SDK télécharge automatiquement les packages spécifiés au premier démarrage. Pour les petits setups, les prototypes ou les démos, la structure de projet n'est plus un obstacle à l'entrée.

TypeScript AppHost

À partir d'Aspire 13.4, en disponibilité générale, l'AppHost peut aussi être écrit en TypeScript. Au lieu d'un projet C#, le point d'entrée est un fichier .mts :

import { createBuilder } from "@aspire/hosting";
import { addPostgres } from "@aspire/hosting-postgresql";
import { addRedis } from "@aspire/hosting-redis";

const builder = await createBuilder(process.argv);

const cache = addRedis(builder, "cache");
const db = addPostgres(builder, "db");
builder.addProject("api", "../Api/Api.csproj")
    .withReference(cache)
    .withReference(db);

await builder.build().run();

L'API TypeScript reflète la surface C# : mêmes concepts, mêmes méthodes, générées à partir des mêmes commentaires de documentation XML. Aspire valide le code TypeScript avant le démarrage.

Quiconque orchestre un frontend TypeScript ou un backend Python n'a donc plus besoin de .NET dans la toolchain AppHost, uniquement de la CLI Aspire.

La nouvelle CLI Aspire

En parallèle de l'architecture pipeline, la surface CLI a été restructurée. En 9.x, le chemin principal était azd up. Depuis Aspire 13.4, les commandes suivantes sont stables :

CommandeFonction
aspire deployExécuter le déploiement
aspire publishGénérer les artefacts de déploiement, charts Helm, fichiers Compose
aspire destroySupprimer un déploiement
aspire runDémarrer l'AppHost localement
aspire doctorDiagnostics de l'environnement, versions, conflits
aspire integration listLister les intégrations d'hébergement disponibles
aspire logs --searchRécupérer des logs avec filtrage côté serveur
aspire lsLister tous les AppHosts du répertoire courant

aspire doctor est particulièrement utile dans des environnements où plusieurs versions d'Aspire coexistent : il vérifie la version CLI, la version SDK, les outils installés, Helm, Docker, et signale les conflits.

Lacune connue : aspire doctor vérifie actuellement si Docker tourne, mais pas si le plugin docker buildx est installé. Sur des installations Ubuntu fraîches avec docker.io, sans docker-buildx, l'étape de build d'image échoue avec un message trompeur :

Container runtime 'Docker' is not running or is unhealthy.

La vraie cause est l'absence du plugin buildx. apt-get install -y docker-buildx résout le problème. Le ticket (microsoft/aspire#16118) est connu et toujours ouvert. aspire doctor couvrira cette vérification dans une future release.

Ce que le modèle pipeline ne résout toujours pas

Le modèle pipeline rend les étapes de déploiement visibles et parallélisables, c'est un vrai progrès par rapport au modèle publisher séquentiel. Mais une lacune structurelle demeure : les valeurs qu'un service ne produit qu'après son démarrage, secrets client Keycloak, tokens Vault, clés d'accès MinIO, ne peuvent pas être transmises à des services dépendants au cours du même pipeline run.

En local, cela fonctionne sans friction via ResourceReadyEvent. En mode déploiement, il n'existe pas encore d'équivalent. Le workaround actuel est un pattern en deux déploiements : le premier démarre le service, une étape pipeline personnalisée le provisionne et enregistre les valeurs dans l'état de déploiement. Le second lit cet état et injecte les valeurs. Toute personne déployant ce type de service devrait en tenir compte dès le premier aspire deploy (microsoft/aspire#18097).

Besoin d'aide ?

Vous voulez adopter le nouveau modèle pipeline dans vos projets Aspire existants, ou construire des étapes de déploiement personnalisées via WithPipelineStepFactory, mais vous ne savez pas comment aborder la migration ? Nous pouvons vous aider. Contactez-nous et nous préparerons ensemble votre architecture Aspire pour la version 13.

Nous contacter