Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
You can use an Azure DevOps multistage pipeline to divide your CI/CD process into stages that represent different parts of your development cycle. Using a multistage pipeline gives you more visibility into your deployment process and makes it easier to integrate approvals and checks.
In this article, you'll create two App Service instances and build a YAML pipeline with three stages:
In a real-world scenario, you may have another stage for deploying to production depending on your DevOps process.
The example code in this exercise is for a .NET web application for a pretend space game that includes a leaderboard to show high scores. You'll deploy to both development and staging instances of Azure Web App for Linux.
Fork the following sample repository at GitHub.
https://github.com/MicrosoftDocs/mslearn-tailspin-spacegame-web-deploy
Before you can deploy your pipeline, you need to first create an App Service instance to deploy to. You'll use Azure CLI to create the instance.
Sign in to the Azure portal.
From the menu, select Cloud Shell and the Bash experience.
Generate a random number that makes your web app's domain name unique. The advantage of having a unique value is that your App Service instance won't have a name conflict with other learners completing this tutorial.
webappsuffix=$RANDOM
Open a command prompt and use a az group create
command to create a resource group named tailspin-space-game-rg that contains all of your App Service instances. Update the location
value to use your closest region.
az group create --location eastus --name tailspin-space-game-rg
Use the command prompt to create an App Service plan.
az appservice plan create \
--name tailspin-space-game-asp \
--resource-group tailspin-space-game-rg \
--sku B1 \
--is-linux
In the command prompt, create two App Service instances, one for each instance (Dev and Staging) with the az webapp create
command.
az webapp create \
--name tailspin-space-game-web-dev-$webappsuffix \
--resource-group tailspin-space-game-rg \
--plan tailspin-space-game-asp \
--runtime "DOTNET|6.0"
az webapp create \
--name tailspin-space-game-web-staging-$webappsuffix \
--resource-group tailspin-space-game-rg \
--plan tailspin-space-game-asp \
--runtime "DOTNET|6.0"
With the command prompt, list both App Service instances to verify that they're running with the az webapp list
command.
az webapp list \
--resource-group tailspin-space-game-rg \
--query "[].{hostName: defaultHostName, state: state}" \
--output table
Copy the names of the App Service instances to use as variables in the next section.
Set up your Azure DevOps project and a build pipeline. You'll also add variables for your development and staging instances.
Your build pipeline:
buildConfiguration
and releaseBranchName
Sign in to your Azure DevOps organization and go to your project.
Go to Pipelines, and then select New pipeline or Create pipeline if creating your first pipeline.
Do the steps of the wizard by first selecting GitHub as the location of your source code.
You might be redirected to GitHub to sign in. If so, enter your GitHub credentials.
When you see the list of repositories, select your repository.
You might be redirected to GitHub to install the Azure Pipelines app. If so, select Approve & install.
When the Configure tab appears, select Starter pipeline.
Replace the contents of azure-pipelines.yml with this code.
trigger:
- '*'
variables:
buildConfiguration: 'Release'
releaseBranchName: 'release'
stages:
- stage: 'Build'
displayName: 'Build the web application'
jobs:
- job: 'Build'
displayName: 'Build job'
pool:
vmImage: 'ubuntu-20.04'
demands:
- npm
variables:
wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
dotnetSdkVersion: '6.x'
steps:
- task: UseDotNet@2
displayName: 'Use .NET SDK $(dotnetSdkVersion)'
inputs:
version: '$(dotnetSdkVersion)'
- task: Npm@1
displayName: 'Run npm install'
inputs:
verbose: false
- script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
displayName: 'Compile Sass assets'
- task: gulp@1
displayName: 'Run gulp tasks'
- script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
displayName: 'Write build info'
workingDirectory: $(wwwrootDir)
- task: DotNetCoreCLI@2
displayName: 'Restore project dependencies'
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Build the project - $(buildConfiguration)'
inputs:
command: 'build'
arguments: '--no-restore --configuration $(buildConfiguration)'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Publish the project - $(buildConfiguration)'
inputs:
command: 'publish'
projects: '**/*.csproj'
publishWebProjects: false
arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
zipAfterPublish: true
- publish: '$(Build.ArtifactStagingDirectory)'
artifact: drop
When you're ready, select Save and run.
In Azure DevOps, go to Pipelines > Library.
Select + Variable group.
Under Properties, add Release for the variable group name.
Create a two variables to refer to your development and staging host names. Replace the value 1234
with the correct value for your instance.
Variable name | Example value |
---|---|
WebAppNameDev | tailspin-space-game-web-dev-1234 |
WebAppNameStaging | tailspin-space-game-web-staging-1234 |
Select Save to save your variables.
Next, you'll update your pipeline to promote your build to the Dev stage.
In Azure Pipelines, go to Pipelines > Pipelines.
Select Edit in the contextual menu to edit your pipeline.
Update azure-pipelines.yml to include a Dev stage. In the Dev stage, your pipeline will:
drop
trigger:
- '*'
variables:
buildConfiguration: 'Release'
releaseBranchName: 'release'
stages:
- stage: 'Build'
displayName: 'Build the web application'
jobs:
- job: 'Build'
displayName: 'Build job'
pool:
vmImage: 'ubuntu-20.04'
demands:
- npm
variables:
wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
dotnetSdkVersion: '6.x'
steps:
- task: UseDotNet@2
displayName: 'Use .NET SDK $(dotnetSdkVersion)'
inputs:
version: '$(dotnetSdkVersion)'
- task: Npm@1
displayName: 'Run npm install'
inputs:
verbose: false
- script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
displayName: 'Compile Sass assets'
- task: gulp@1
displayName: 'Run gulp tasks'
- script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
displayName: 'Write build info'
workingDirectory: $(wwwrootDir)
- task: DotNetCoreCLI@2
displayName: 'Restore project dependencies'
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Build the project - $(buildConfiguration)'
inputs:
command: 'build'
arguments: '--no-restore --configuration $(buildConfiguration)'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Publish the project - $(buildConfiguration)'
inputs:
command: 'publish'
projects: '**/*.csproj'
publishWebProjects: false
arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
zipAfterPublish: true
- publish: '$(Build.ArtifactStagingDirectory)'
artifact: drop
- stage: 'Dev'
displayName: 'Deploy to the dev environment'
dependsOn: Build
condition: succeeded()
jobs:
- deployment: Deploy
pool:
vmImage: 'ubuntu-20.04'
environment: dev
variables:
- group: Release
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: drop
- task: AzureWebApp@1
displayName: 'Azure App Service Deploy: dev website'
inputs:
azureSubscription: 'your-subscription'
appType: 'webAppLinux'
appName: '$(WebAppNameDev)'
package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
Change the AzureWebApp@1
task to use your subscription.
Select Settings for the task.
Update the your-subscription
value for Azure Subscription to use your own subscription. You may need to authorize access as part of this process. If you run into a problem authorizing your resource within the YAML editor, an alternate approach is to create a service connection.
Set the App type to Web App on Linux.
Select Add to update the task.
Save and run your pipeline.
Last, you'll promote the Dev stage to Staging. Unlike the Dev environment, you want to have more control in the staging environment you'll add a manual approval.
From Azure Pipelines, select Environments.
Select New environment.
Create a new environment with the name staging and Resource set to None.
On the staging environment page, select Approvals and checks.
Select Approvals.
In Approvers, select Add users and groups, and then select your account.
In Instructions to approvers, write Approve this change when it's ready for staging.
Select Save.
You'll add new stage, Staging
to the pipeline that includes a manual approval.
Edit your pipeline file and add the Staging
section.
trigger:
- '*'
variables:
buildConfiguration: 'Release'
releaseBranchName: 'release'
stages:
- stage: 'Build'
displayName: 'Build the web application'
jobs:
- job: 'Build'
displayName: 'Build job'
pool:
vmImage: 'ubuntu-20.04'
demands:
- npm
variables:
wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
dotnetSdkVersion: '6.x'
steps:
- task: UseDotNet@2
displayName: 'Use .NET SDK $(dotnetSdkVersion)'
inputs:
version: '$(dotnetSdkVersion)'
- task: Npm@1
displayName: 'Run npm install'
inputs:
verbose: false
- script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
displayName: 'Compile Sass assets'
- task: gulp@1
displayName: 'Run gulp tasks'
- script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
displayName: 'Write build info'
workingDirectory: $(wwwrootDir)
- task: DotNetCoreCLI@2
displayName: 'Restore project dependencies'
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Build the project - $(buildConfiguration)'
inputs:
command: 'build'
arguments: '--no-restore --configuration $(buildConfiguration)'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Publish the project - $(buildConfiguration)'
inputs:
command: 'publish'
projects: '**/*.csproj'
publishWebProjects: false
arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
zipAfterPublish: true
- publish: '$(Build.ArtifactStagingDirectory)'
artifact: drop
- stage: 'Dev'
displayName: 'Deploy to the dev environment'
dependsOn: Build
condition: succeeded()
jobs:
- deployment: Deploy
pool:
vmImage: 'ubuntu-20.04'
environment: dev
variables:
- group: Release
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: drop
- task: AzureWebApp@1
displayName: 'Azure App Service Deploy: dev website'
inputs:
azureSubscription: 'your-subscription'
appType: 'webAppLinux'
appName: '$(WebAppNameDev)'
package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
- stage: 'Staging'
displayName: 'Deploy to the staging environment'
dependsOn: Dev
jobs:
- deployment: Deploy
pool:
vmImage: 'ubuntu-20.04'
environment: staging
variables:
- group: 'Release'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: drop
- task: AzureWebApp@1
displayName: 'Azure App Service Deploy: staging website'
inputs:
azureSubscription: 'your-subscription'
appType: 'webAppLinux'
appName: '$(WebAppNameStaging)'
package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
Change the AzureWebApp@1
task in the Staging stage to use your subscription.
Select Settings for the task.
Update the your-subscription
value for Azure Subscription to use your own subscription. You may need to authorize access as part of this process.
Set the App type to Web App on Linux.
Select Add to update the task.
Go to the pipeline run. Watch the build as it runs. When it reaches Staging
, the pipeline waits for manual release approval. You'll also receive an email that you have a pipeline pending approval.
Review the approval and allow the pipeline to run.
If you're not going to continue to use this application, delete the resource group in Azure portal and the project in Azure DevOps with the following steps:
To clean up your resource group:
Go to the Azure portal and sign in.
From the menu bar, select Cloud Shell. When prompted, select the Bash experience.
Run the following az group delete command to delete the resource group that you used, tailspin-space-game-rg
.
az group delete --name tailspin-space-game-rg
To delete your Azure DevOps project, including the build pipeline, see Delete project.
Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowTraining
Module
Create a multistage pipeline by using Azure Pipelines - Training
Design and create a realistic release pipeline that promotes changes to various testing and staging environments.
Certification
Microsoft Certified: Azure Developer Associate - Certifications
Build end-to-end solutions in Microsoft Azure to create Azure Functions, implement and manage web apps, develop solutions utilizing Azure storage, and more.