L’infrastructure cloud n’est plus un simple décor autour de nos applications. Elle est devenue un vrai morceau du produit. Quand on manipule des Functions, du Service Bus, du Cosmos DB, du Storage, de l’APIM ou n’importe quelle brique Azure, on se rend rapidement compte que l’infra fait partie du métier, qu’elle influence les choix techniques, la sécurité, la performance et même le ROI.
Dans mon quotidien de consultant Azure et développeur .NET , j’ai trop souvent vu des équipes coincées entre des Templates ARM interminables qui se complexifie au fil du temps, ou du Terraform devenu rigide dès qu’on veut factoriser, « refactorer » ou tester sérieusement.
Pulumi prend le problème à contre-pied
et si on écrivait l’infrastructure comme on écrit une application ?
Pulumi : l’IaC qui parle enfin notre langue
Pulumi fait un choix radical : laisser tomber les DSL spécialisés et revenir à des langages de programmation classiques.
Tu écris ton infra en C#, TypeScript, Python ou Go.
Et évidemment, dès que tu reviens dans ton environnement .NET, tout prend une autre dimension.
Tu retrouves le confort du typage fort, l’IntelliSense qui t’accompagne, la compilation qui te protège des erreurs, le refactoring naturel, les tests unitaires qui sécurisent ton travail, la modularisation qui va de soi, et toute la puissance de ton IDE.
En somme, tu restes dans ton écosystème habituel.
L’infrastructure devient simplement une partie du code, intégrée à ton quotidien de développeur. Pas plus compliquée, pas plus exotique. Une extension logique de ta solution.
Provisionner une Function App Azure en C#
Avec Pulumi, créer une Function App ressemble davantage à coder une fonctionnalité qu’à assembler des blocs déclaratifs.
using Pulumi;
using Pulumi.AzureNative.Resources;
using Pulumi.AzureNative.Web;
using Pulumi.AzureNative.Storage;
class MyStack : Stack
{
public MyStack()
{
var rg = new ResourceGroup("rg-demo");
var storage = new StorageAccount("saPulumiDemo", new StorageAccountArgs
{
ResourceGroupName = rg.Name,
Sku = new Pulumi.AzureNative.Storage.Inputs.SkuArgs
{
Name = Pulumi.AzureNative.Storage.SkuName.Standard_LRS
},
Kind = Pulumi.AzureNative.Storage.Kind.StorageV2
});
var plan = new AppServicePlan("planDemo", new AppServicePlanArgs
{
ResourceGroupName = rg.Name,
Kind = "FunctionApp",
Sku = new Pulumi.AzureNative.Web.Inputs.SkuDescriptionArgs
{
Tier = "Dynamic",
Name = "Y1"
}
});
var function = new WebApp("fa-demo", new WebAppArgs
{
ResourceGroupName = rg.Name,
ServerFarmId = plan.Id,
SiteConfig = new Pulumi.AzureNative.Web.Inputs.SiteConfigArgs
{
AppSettings =
{
new Pulumi.AzureNative.Web.Inputs.NameValuePairArgs {
Name = "FUNCTIONS_EXTENSION_VERSION",
Value = "~4"
},
new Pulumi.AzureNative.Web.Inputs.NameValuePairArgs {
Name = "AzureWebJobsStorage",
Value = storage.PrimaryEndpoints.Apply(e => e.Blob)
}
}
}
});
this.Endpoint = function.DefaultHostName;
}
[Output]
public Output<string> Endpoint { get; set; }
}
Ce qui est agréable avec cette approche, c’est qu’on reste dans un espace cognitif unique : le même langage, les mêmes patterns, les mêmes réflexes.
Déployer avec Pulumi dans la CI/CD
L’intégration dans une pipeline GitHub Actions ou Azure DevOps est d’une simplicité déconcertante.
Tu installes Pulumi, tu te connectes à ton backend d’état (Azure Blob recommandé), puis tu lances :
pulumi preview
pulumi up --yes
Le preview est un allié puissant :
il montre exactement ce que Pulumi va faire — créations, modifications, suppressions — avant la moindre action sur ton cloud.
Tu maîtrises totalement l’impact du changement.
Quand Pulumi devient indispensable
À partir du moment où ton infrastructure cesse d’être un simple bloc unique pour devenir un véritable écosystème — avec des API .NET qui se répondent, une gestion centralisée via APIM, des Functions qui orchestrent les flux, un Service Bus qui véhicule les messages, des bases Cosmos DB, du stockage distribué, de l’observabilité AppInsights et plusieurs environnements qui doivent rester alignés — la complexité explose naturellement.
C’est précisément là que Pulumi agit comme un catalyseur de cohérence.
Tu peux aborder ton infrastructure comme une architecture logicielle à part entière : façonner tes abstractions, factoriser les schémas récurrents, imposer une discipline commune, vérifier ton travail avec des tests, et maintenir le tout sans t’épuiser à recoller les morceaux à la main.
Pulumi transforme un ensemble hétérogène en un système maîtrisable. Un cadre où tu reprends le contrôle.
Du code au cloud, structurer Pulumi comme une architecture logicielle

Quand ton infrastructure commence à ressembler à un vrai système, Pulumi te permet d’aller beaucoup plus loin qu’une simple description de ressources.
Modules métier
Tu peux découper ton infra en vraies briques :
- Module
Messaging(ServiceBus, topics, règles…) - Module
Backend(APIs, Functions, App Service…) - Module
Data(Cosmos DB, SQL, Storage…) - Module
Security(Key Vault, RBAC, identités managées…) - Module
Monitoring(dashboards, logs, alerting…)
Ta stack devient claire, lisible, maintenable.
Multi-environnements sans duplication
Un module = une logique.
Une stack = une configuration (dev, prod, staging).
Pas besoin de dupliquer ce qui existe déjà.
Pulumi Policy
Tu peux imposer des règles globales :
“aucune ressource sans tag compliance”, “diagnostics activés sur toutes les bases”.
La qualité est standardisée.
Tests d’infrastructure
Tu peux écrire des tests unitaires en C# qui valident ta configuration.
Oui, l’infrastructure devient testable.
Anti-Pattern Iac – quelques erreurs à éviter
Dans l’Infrastructure as Code, les dérapages arrivent vite, souvent parce que l’on reproduit des réflexes issus d’outils plus anciens. L’un des pièges les plus fréquents consiste à vouloir tout regrouper dans une seule stack. Sur le moment, cela paraît pratique ; avec le temps, on se retrouve prisonnier d’un monolithe où la moindre modification déclenche une réaction en chaîne. À l’inverse, lorsque l’infrastructure est découpée par domaines, chaque partie respire et évolue à son propre rythme.
Un autre travers classique vient du copier-coller. On duplique une ressource, on change un nom, et tout semble tenir… jusqu’au jour où ce patchwork devient impossible à suivre. Extraire des abstractions claires, créer des modules ou des fabriques, c’est souvent ce qui permet à l’ensemble de rester lisible et cohérent.
La gestion des environnements peut également basculer dans la complexité si l’on commence à parsemer le code de conditions du type si on est en prod alors…. On croit gérer un détail, mais on construit un labyrinthe dans lequel plus personne ne se retrouve. Les fichiers de configuration dédiés à chaque stack évitent ce piège et clarifient immédiatement l’intention.
Un écueil plus subtil consiste à déclarer son infrastructure sans jamais la tester. Pourtant, du code non testé finit inévitablement par rompre au moment le moins opportun. Pulumi offre les outils pour vérifier ses déploiements, et s’en priver revient à avancer sans filet.
Il arrive aussi que l’infrastructure se mélange à la logique métier, parfois directement dans le code applicatif. C’est le meilleur moyen de brouiller les responsabilités. Garder un projet Pulumi séparé, clairement identifié dans la solution, permet à chaque couche de jouer son rôle.
Enfin, certaines équipes continuent d’utiliser un backend local pour stocker l’état. C’est une solution tentante en solo, mais catastrophique dès qu’on travaille à plusieurs. Un backend partagé — qu’il s’agisse d’Azure Blob ou du service managé de Pulumi — apporte la stabilité nécessaire. Et tant qu’à fiabiliser le déploiement, autant activer l’observabilité dès la création des ressources : une infrastructure silencieuse est souvent celle qui surprendra le plus.
Au fond, toutes ces erreurs ont un point commun : elles naissent de compromis rapides. Les éviter, c’est s’offrir une IaC plus claire, plus robuste, et surtout plus sereine au quotidien.
GitHub Actions
Pour intégrer Pulumi dans un flux CI/CD GitHub, on cherche quelque chose de simple, lisible, mais surtout prévisible.
L’objectif n’est pas de construire une usine à gaz : pose un cadre propre pour déployer ton infrastructure automatiquement à chaque push sur main, ou à chaque validation de Pull Request si tu veux l’utiliser en “plan-only”.
Le pipeline ci-dessous installe .NET, installe le CLI Pulumi, se connecte au backend d’état (dans cet exemple un container Azure Blob), puis exécute le déploiement de la stack choisie.
L’idée, c’est que l’IaC soit traitée comme ton code applicatif : versionnée, revue, testée, appliquée par une pipeline, jamais manuellement.
Une stack Pulumi devient alors un composant vivant du projet, raccordé à son cycle de livraison.
name: Deploy Infrastructure
on:
push:
branches: ["main"]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: "8.0.x"
- name: Install Pulumi CLI
uses: pulumi/actions-install-pulumi-cli@v2
- name: Azure Login via Service Principal
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Pulumi Login (Azure Blob backend)
run: pulumi login "azblob://${{ secrets.PULUMI_STATE_CONTAINER }}"
- name: Select Stack
run: pulumi stack select ${{ secrets.PULUMI_STACK }}
- name: Install Infra Dependencies
run: dotnet restore ./src/Infra/Infra.csproj
- name: Preview Infrastructure Changes
run: pulumi preview --stack ${{ secrets.PULUMI_STACK }}
- name: Deploy Infrastructure
run: pulumi up --yes --stack ${{ secrets.PULUMI_STACK }}
Secrets à ajouter dans GitHub
Dans Settings → Secrets → Actions :
AZURE_CREDENTIALS → JSON du service principal (Azure AD)
PULUMI_STACK → nom de la stack (ex. dev, prod)
PULUMI_STATE_CONTAINER → URL du container d’état Pulumi (ex. pulumi-state)
Pulumi change profondément notre façon de travailler l’infrastructure
On sort enfin d’une logique de templates opaques, de copier-coller et de pipelines fragiles pour revenir à quelque chose de plus sain : du vrai code, versionné, testé, relu, pensé comme un composant à part entière du produit.
Dans un écosystème Azure riche et vivant, cette approche fait la différence.
On construit des plateformes cohérentes, on capitalise sur les patterns, on partage les bonnes pratiques, et surtout on développe une infra qui respire au même rythme que l’application elle-même.
Et quand on est développeur .NET, l’expérience est encore plus naturelle, Pulumi s’intègre parfaitement dans notre environnement, nos outils, notre façon d’aborder les projets.
Le fossé entre “dev” et “infra” se referme, et l’équipe gagne une vision plus globale du système.
Si tu veux partir sur de bonnes bases, j’ai préparé un squelette complet : structure propre, modules, stacks, tests, et pipeline GitHub Actions. Tu peux le télécharger ici :
Télécharger le sample Pulumi C# sur GitHub
https://github.com/xraboteu/pulumi-csharp-sample




