Deploy to App Service using Azure Pipelines

Azure DevOps Services | Azure DevOps Server 2020 | Azure DevOps Server 2019

Use Azure Pipelines to automatically deploy your web app to Azure App Service on every successful build. Azure Pipelines lets you build, test, and deploy with continuous integration (CI) and continuous delivery (CD) using Azure DevOps.

YAML pipelines are defined using a YAML file in your repository. A step is the smallest building block of a pipeline and can be a script or task (prepackaged script). Learn about the key concepts and components that make up a pipeline.

You'll use the Azure Web App task (AzureWebApp) to deploy to Azure App Service in your pipeline. For more complicated scenarios such as needing to use XML parameters in your deploy, you can use the Azure App Service deploy task (AzureRmWebAppDeployment).

Prerequisites

1. Create a pipeline for your stack

The code examples in this section assume you're deploying an ASP.NET web app. You can adapt the instructions for other frameworks.

Learn more about Azure Pipelines ecosystem support.

  1. Sign in to your Azure DevOps organization and navigate to your project.

  2. Go to Pipelines, and then select New Pipeline.

  3. When prompted, select the location of your source code: either Azure Repos Git or GitHub.

    You might be redirected to GitHub to sign in. If so, enter your GitHub credentials.

  4. When the list of repositories appears, select your repository.

  5. You might be redirected to GitHub to install the Azure Pipelines app. If so, select Approve & install.

  6. When the Configure tab appears, select ASP.NET Core.

  7. When your new pipeline appears, take a look at the YAML to see what it does. When you're ready, select Save and run.

2. Add the deployment task

  1. Click the end of the YAML file, then select Show assistant.'

  2. Use the Task assistant to add the Azure Web App task.

    Screenshot of Azure web app task.

    Alternatively, you can add the Azure App Service deploy (AzureRmWebAppDeployment) task.

  3. Choose your Azure subscription. Make sure to Authorize your connection. The authorization creates the required service connection.

  4. Select the App type, App name, and Runtime stack based on your App Service app. Your complete YAML should look similar to the following code.

    variables:
      buildConfiguration: 'Release'
    
    steps:
    - script: dotnet build --configuration $(buildConfiguration)
      displayName: 'dotnet build $(buildConfiguration)'
    - task: DotNetCoreCLI@2
      inputs:
        command: 'publish'
        publishWebProjects: true
    - task: AzureWebApp@1
      inputs:
        azureSubscription: '<service-connection-name>'
        appType: 'webAppLinux'
        appName: '<app-name>'
        package: '$(System.DefaultWorkingDirectory)/**/*.zip'
    
    • azureSubscription: Name of the authorized service connection to your Azure subscription.
    • appName: Name of your existing app.
    • package: File path to the package or a folder containing your app service contents. Wildcards are supported.

Example: Deploy a .NET app

To deploy a .zip web package (for example, from an ASP.NET web app) to an Azure Web App, use the following snippet to deploy the build to an app.

variables:
  buildConfiguration: 'Release'

steps:
- script: dotnet build --configuration $(buildConfiguration)
  displayName: 'dotnet build $(buildConfiguration)'
- task: DotNetCoreCLI@2
  inputs:
    command: 'publish'
    publishWebProjects: true
- task: AzureWebApp@1
  inputs:
    azureSubscription: '<service-connection-name>'
    appType: 'webAppLinux'
    appName: '<app-name>'
    package: '$(System.DefaultWorkingDirectory)/**/*.zip'
  • azureSubscription: your Azure subscription.
  • appType: your Web App type.
  • appName: the name of your existing app service.
  • package: the file path to the package or a folder containing your app service contents. Wildcards are supported.

Example: deploy to a virtual application

By default, your deployment happens to the root application in the Azure Web App. You can deploy to a specific virtual application by using the VirtualApplication property of the Azure App Service deploy (AzureRmWebAppDeployment) task:

- task: AzureRmWebAppDeployment@4
  inputs:
    VirtualApplication: '<name of virtual application>'

Example: Deploy to a slot

The following example shows how to deploy to a staging slot, and then swap to a production slot:

- task: AzureWebApp@1
  inputs:
    azureSubscription: '<service-connection-name>'
    appType: webAppLinux
    appName: '<app-name>'
    deployToSlotOrASE: true
    resourceGroupName: '<name of resource group>'
    slotName: staging
    package: '$(Build.ArtifactStagingDirectory)/**/*.zip'

- task: AzureAppServiceManage@0
  inputs:
    azureSubscription: '<service-connection-name>'
    appType: webAppLinux
    WebAppName: '<app-name>'
    ResourceGroupName: '<name of resource group>'
    SourceSlot: staging
    SwapWithProduction: true
  • azureSubscription: your Azure subscription.
  • appType: (optional) Use webAppLinux to deploy to a Web App on Linux.
  • appName: the name of your existing app service.
  • deployToSlotOrASE: Boolean. Deploy to an existing deployment slot or Azure App Service Environment.
  • resourceGroupName: Name of the resource group. Required if deployToSlotOrASE is true.
  • slotName: Name of the slot, which defaults to production. Required if deployToSlotOrASE is true.
  • package: the file path to the package or a folder containing your app service contents. Wildcards are supported.
  • SourceSlot: Slot sent to production when SwapWithProduction is true.
  • SwapWithProduction: Boolean. Swap the traffic of source slot with production.

Example: Deploy to multiple web apps

You can use jobs in your YAML file to set up a pipeline of deployments. By using jobs, you can control the order of deployment to multiple web apps.

jobs:
- job: buildandtest
  pool:
    vmImage: ubuntu-latest
 
  steps:
  # publish an artifact called drop
  - task: PublishPipelineArtifact@1
    inputs:
      targetPath: '$(Build.ArtifactStagingDirectory)' 
      artifactName: drop
  
  # deploy to Azure Web App staging
  - task: AzureWebApp@1
    inputs:
      azureSubscription: '<service-connection-name>'
      appType: <app type>
      appName: '<staging-app-name>'
      deployToSlotOrASE: true
      resourceGroupName: <group-name>
      slotName: 'staging'
      package: '$(Build.ArtifactStagingDirectory)/**/*.zip'

- job: deploy
  dependsOn: buildandtest
  condition: succeeded()

  pool: 
    vmImage: ubuntu-latest  
  
  steps:
    # download the artifact drop from the previous job
  - task: DownloadPipelineArtifact@2
    inputs:
      source: 'current'
      artifact: 'drop'
      path: '$(Pipeline.Workspace)'

  - task: AzureWebApp@1
    inputs:
      azureSubscription: '<service-connection-name>'
      appType: <app type>
      appName: '<production-app-name>'
      resourceGroupName: <group-name>
      package: '$(Pipeline.Workspace)/**/*.zip'

Example: Make variable substitutions

For most language stacks, app settings and connection strings can be set as environment variables at runtime.

But there are other reasons you would want to make variable substitutions to your Web.config. In this example, your Web.config file contains a connection string named connectionString. You can change its value before deploying to each web app. You can do this either by applying a Web.config transformation or by substituting variables in your Web.config file.

The following snippet shows an example of variable substitution by using the Azure App Service Deploy (AzureRmWebAppDeployment) task:

jobs:
- job: test
  variables:
    connectionString: <test-stage connection string>
  steps:
  - task: AzureRmWebAppDeployment@4
    inputs:
      azureSubscription: '<Test stage Azure service connection>'
      WebAppName: '<name of test stage web app>'
      enableXmlVariableSubstitution: true

- job: prod
  dependsOn: test
  variables:
    connectionString: <prod-stage connection string>
  steps:
  - task: AzureRmWebAppDeployment@4
    inputs:
      azureSubscription: '<Prod stage Azure service connection>'
      WebAppName: '<name of prod stage web app>'
      enableXmlVariableSubstitution: true

Example: Deploy conditionally

To do this in YAML, you can use one of the following techniques:

  • Isolate the deployment steps into a separate job, and add a condition to that job.
  • Add a condition to the step.

The following example shows how to use step conditions to deploy only builds that originate from the main branch:

- task: AzureWebApp@1
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  inputs:
    azureSubscription: '<service-connection-name>'
    appName: '<app-name>'

To learn more about conditions, see Specify conditions.

Example: deploy using Web Deploy

The Azure App Service deploy (AzureRmWebAppDeployment) task can deploy to App Service using Web Deploy.

trigger:
- main

pool:
  vmImage: windows-latest

variables:
  buildConfiguration: 'Release'

steps:
- script: dotnet build --configuration $(buildConfiguration)
  displayName: 'dotnet build $(buildConfiguration)'
- task: DotNetCoreCLI@2
  inputs:
    command: 'publish'
    publishWebProjects: true
    arguments: '--configuration $(buildConfiguration)'
    zipAfterPublish: true
- task: AzureRmWebAppDeployment@4
  inputs:
    ConnectionType: 'AzureRM'
    azureSubscription: '<service-connection-name>'
    appType: 'webApp'
    WebAppName: '<app-name>'
    packageForLinux: '$(System.DefaultWorkingDirectory)/**/*.zip'
    enableCustomDeployment: true
    DeploymentType: 'webDeploy'

Frequently asked questions

What's the difference between the AzureWebApp and AzureRmWebAppDeployment tasks?

The Azure Web App task (AzureWebApp) is the simplest way to deploy to an Azure Web App. By default, your deployment happens to the root application in the Azure Web App.

The Azure App Service Deploy task (AzureRmWebAppDeployment) can handle more custom scenarios, such as:

Note

File transforms and variable substitution are also supported by the separate File Transform task for use in Azure Pipelines. You can use the File Transform task to apply file transformations and variable substitutions on any configuration and parameters files.

I get the message "Invalid App Service package or folder path provided."

In YAML pipelines, depending on your pipeline, there may be a mismatch between where your built web package is saved and where the deploy task is looking for it. For example, the AzureWebApp task picks up the web package for deployment. For example, the AzureWebApp task looks in $(System.DefaultWorkingDirectory)/**/*.zip. If the web package is deposited elsewhere, modify the value of package.

I get the message "Publish using webdeploy options are supported only when using Windows agent."

This error occurs in the AzureRmWebAppDeployment task when you configure the task to deploy using Web Deploy, but your agent isn't running Windows. Verify that your YAML has something similar to the following code:

pool:
  vmImage: windows-latest

Web Deploy doesn't work when I disable basic authentication

For troubleshooting information on getting Microsoft Entra ID authentication to work with the AzureRmWebAppDeployment task, see I can't Web Deploy to my Azure App Service using Microsoft Entra ID authentication from my Windows agent

Next steps