CI/CD .NET avec Visual Studio et Azure
Ce skill guide la mise en place d’un pipeline complet : un push déclenche le build et les tests, produit un artefact unique, le déploie en staging, attend une approbation, puis bascule en production avec possibilité de retour arrière. Le but est un déploiement reproductible, sécurisé et réversible, pas seulement un pipeline qui passe au vert.
Avant de commencer : clarifier le contexte
Poser (en une seule fois, sans interroger inutilement) les questions dont la réponse change le pipeline :
- Type d’application : API/site web (App Service), Functions, conteneur (ACR + Container Apps ou AKS).
- Dépôt : Azure Repos ou GitHub (Azure Pipelines ou GitHub Actions).
- Version de .NET et nom de la solution et des projets de tests.
- Un environnement ou deux (staging + production).
Si l’utilisateur n’a pas de préférence, partir sur : ASP.NET Core, App Service Linux, Azure Repos, Azure Pipelines YAML, slot staging + production.
Principes directeurs (et pourquoi)
- Construire une seule fois, déployer le même artefact partout. Sinon staging ne valide pas ce qui part en production.
- Échouer vite. Restore, build et tests unitaires avant tout déploiement ; les étapes lourdes viennent après.
- Pas de secrets dans le dépôt ni dans le YAML. Utiliser Key Vault, des variables protégées et la Managed Identity.
- Workload Identity Federation pour la service connection : aucun secret à renouveler ni à faire fuiter.
- Retour arrière trivial : avec les slots, un second swap restaure la version précédente.
- Pipeline as code : tout est versionné avec le projet.
Procédure
1. Préparer le projet dans Visual Studio
- Projet de tests (xUnit ou NUnit) qui passe dans Test Explorer.
- Endpoint de santé :
builder.Services.AddHealthChecks();puisapp.MapHealthChecks("/health");(sert aux smoke tests). - Dépôt Git créé (menu Git, Create Git Repository) et poussé vers Azure DevOps ou GitHub.
2. Créer les ressources Azure
Utiliser Azure CLI, ou de préférence Bicep ou Terraform si l’utilisateur veut de l’Infrastructure as Code :
“`bash
az loginaz group create -n rg-monapp -l canadaeastaz appservice plan create -n plan-monapp -g rg-monapp --sku S1az webapp create -n monapp-web -g rg-monapp -p plan-monapp --runtime "dotnet:8"az webapp deployment slot create -n monapp-web -g rg-monapp --slot staging
- Les slots exigent un plan Standard (S1) ou supérieur.
- Le nom du Web App doit être unique mondialement.
- Vérifier les runtimes valides avec
az webapp list-runtimesplutôt que de se fier à la mémoire. - Ajouter Application Insights.
3. Configurer Azure DevOps
- Service connection Azure Resource Manager en Workload Identity Federation, limitée au groupe de ressources (ex.
sc-azure-prod). - Environnements
stagingetproduction; ajouter une Approval check surproduction. - Si le pipeline reste en attente sur une nouvelle organisation, vérifier le parallélisme des agents hébergés.
4. Écrire azure-pipelines.yml
Utiliser le modèle dans references/pipeline-template.md (à la fin de ce fichier). Trois stages : Build (restore, build, tests avec couverture, publish, artefact), DeployStaging (slot + smoke test sur /health), DeployProd (environnement avec approbation, puis swap des slots). Les déploiements ne se déclenchent que sur main.
5. Protéger la branche main
Branch policies : revue obligatoire, build validation (le pipeline doit réussir avant merge), commentaires résolus. Ainsi les PR ne font que la CI, et seul un merge sur main déploie.
6. Secrets et configuration
- Azure Key Vault + Managed Identity de l’App Service ; références
@Microsoft.KeyVault(SecretUri=...)dans les paramètres. - Paramètres propres à un environnement marqués comme « Deployment slot setting ».
7. Monitoring et rollback
- Application Insights, alertes sur taux d’erreur et temps de réponse.
- Rollback : refaire un swap des slots.
Variantes à proposer selon le contexte
- Conteneurs : build et push d’image vers ACR, scan Trivy, déploiement sur App Service for Containers ou Container Apps.
- GitHub Actions : même structure (jobs build, staging, production avec
environment:), identifiants via OIDC. - Raccourci Visual Studio (clic droit, Publish, Azure) : bon pour un prototype ; le signaler comme moins complet (pas d’approbation ni de staging).
- Canary : Testing in production des slots pour router un pourcentage du trafic avant le swap.
- DevSecOps : CodeQL, scan des dépendances, détection de secrets.
Checklist avant de livrer
- [ ] Aucun secret dans le dépôt ni dans le YAML
- [ ] Même artefact déployé en staging et en production
- [ ] Smoke test sur /health avant le swap
- [ ] Approbation configurée sur l’environnement production
- [ ] Branch policy avec build validation sur main
- [ ] Rollback décrit à l’utilisateur (swap inverse)
- [ ] Noms, régions et versions de runtime adaptés au projet réel
Format de réponse
Répondre dans la langue de l’utilisateur. Donner d’abord une vue d’ensemble courte (schéma en une ligne du flux), puis les étapes numérotées avec les commandes et fichiers complets, puis la checklist. Terminer par les décisions encore ouvertes à confirmer. Ne pas inventer de noms de tâches Azure Pipelines : en cas de doute sur une tâche ou un paramètre, le dire et renvoyer à la documentation Microsoft.
Modèle de pipeline (références)
“`yaml
trigger: branches: include: [main]pr: branches: include: [main]pool: vmImage: 'ubuntu-latest'variables: buildConfiguration: 'Release' azureSubscription: 'sc-azure-prod' webAppName: 'monapp-web' resourceGroup: 'rg-monapp'stages:- stage: Build jobs: - job: BuildTest steps: - task: UseDotNet@2 inputs: { packageType: sdk, version: '8.x' } - task: DotNetCoreCLI@2 displayName: Restore inputs: { command: restore, projects: '**/*.csproj' } - task: DotNetCoreCLI@2 displayName: Build inputs: command: build projects: '**/*.csproj' arguments: '--configuration $(buildConfiguration) --no-restore' - task: DotNetCoreCLI@2 displayName: Tests unitaires inputs: command: test projects: '**/*Tests.csproj' arguments: '--configuration $(buildConfiguration) --no-build --collect:"XPlat Code Coverage"' - task: DotNetCoreCLI@2 displayName: Publish inputs: command: publish publishWebProjects: true arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)' zipAfterPublish: true - publish: $(Build.ArtifactStagingDirectory) artifact: drop- stage: DeployStaging dependsOn: Build condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) jobs: - deployment: Staging environment: staging strategy: runOnce: deploy: steps: - task: AzureWebApp@1 inputs: azureSubscription: $(azureSubscription) appType: webApp appName: $(webAppName) deployToSlotOrASE: true resourceGroupName: $(resourceGroup) slotName: staging package: $(Pipeline.Workspace)/drop/**/*.zip - script: | sleep 20 curl --fail --retry 5 --retry-delay 10 https://$(webAppName)-staging.azurewebsites.net/health displayName: Smoke test- stage: DeployProd dependsOn: DeployStaging jobs: - deployment: Production environment: production strategy: runOnce: deploy: steps: - task: AzureAppServiceManage@0 displayName: Swap staging vers production inputs: azureSubscription: $(azureSubscription) Action: 'Swap Slots' WebAppName: $(webAppName) ResourceGroupName: $(resourceGroup) SourceSlot: staging SwapWithProduction: true
===========================================================
J’ai rédigé le skill azure-cicd-dotnet.
Ce qu’il contient :
- Déclencheur : pipeline, déploiement Azure,
azure-pipelines.yml, slots, service connection, Azure DevOps, CI/CD avec Visual Studio. La description est volontairement « insistante » pour qu’il se déclenche même si tu ne dis pas « CI/CD ». - Clarification initiale : il demande le type d’application, le dépôt (Azure Repos ou GitHub) et la version de .NET, avec des valeurs par défaut si tu n’as pas de préférence.
- Principes avec leur raison : un seul artefact déployé partout, échec rapide, aucun secret dans le dépôt, Workload Identity Federation, rollback par swap.
- Les 7 étapes : projet, ressources Azure, Azure DevOps, YAML, protection de
main, secrets, monitoring. - Variantes : conteneurs, GitHub Actions, canary, DevSecOps.
- Checklist finale et format de réponse.
- Gabarit YAML complet intégré en bas du fichier.
Limites :
- Je n’ai pas pu lancer de tests dans cet environnement (pas d’exécution de code ni de sous-agents), donc le skill n’a pas été évalué sur des cas réels. Je te suggère de l’essayer sur 2 ou 3 demandes, par exemple « crée-moi un pipeline pour mon API .NET 8 sur Azure » ou « ajoute l’approbation avant la production », puis de me dire ce qui cloche.
- Les noms de tâches Azure Pipelines (
AzureWebApp@1,AzureAppServiceManage@0) et les runtimes évoluent. Vérifie-les dans la documentation Microsoft avant un usage réel.