Edit

Share via


Use Azure Pipelines to build and deploy a Python web app to Azure App Service

Azure DevOps Services

This tutorial shows you how to use Azure Pipelines for continuous integration and continuous delivery (CI/CD) to build and deploy a Python web app to Azure App Service on Linux. Your pipeline automatically builds and deploys your Python web app to App Service whenever there's a commit to your app code repository.

In this tutorial, you:

  • Create a Python web app and upload it to Azure App Service.
  • Connect your Azure DevOps project to Azure.
  • Create an Azure Pipelines Python-specific build and deployment pipeline for your app.
  • Run the pipeline to build, test, and deploy to your Azure App Service web app.
  • Set a trigger to run the pipeline whenever you commit to your repository.

To understand more about Azure Pipelines concepts, watch the following video:

Prerequisites

Product Requirements
Azure DevOps - An Azure DevOps project.
- An ability to run pipelines on Microsoft-hosted agents. You can either purchase a parallel job or you can request a free tier.
- Basic knowledge of YAML and Azure Pipelines. For more information, see Create your first pipeline.
- Permissions:
     - To create a pipeline: you must be in the Contributors group and the group needs to have Create build pipeline permission set to Allow. Members of the Project Administrators group can manage pipelines.
    - To create service connections: You must have the Administrator or Creator role for service connections.
GitHub - A GitHub account.
- A GitHub service connection to authorize Azure Pipelines.
Azure An Azure subscription.
Product Requirements
Azure DevOps - An Azure DevOps project.
- A self-hosted agent. To create one, see Self-hosted agents.
- Basic knowledge of YAML and Azure Pipelines. For more information, see Create your first pipeline.
- Permissions:
    - To create a pipeline: you must be in the Contributors group and the group needs to have Create build pipeline permission set to Allow. Members of the Project Administrators group can manage pipelines.
    - To create service connections: You must have the Administrator or Creator role for service connections.
GitHub - A GitHub account.
- A GitHub service connection to authorize Azure Pipelines.
Azure An Azure subscription.

Configure a self-hosted agent

Downloading Python versions isn't supported on self-hosted build agents. To use your own self-hosted agent, you need to configure the agent to run Python.

To avoid compatibility issues, match the Python version with the runtime version in your Azure App Services web app, 3.11 in this case. You must preinstall the Python version. Use the full installer to get a pip-compatible version of Python.

The desired Python version needs to be added to the tool cache on the self-hosted agent so the pipeline task can use it. Normally, the tool cache is located under the _work/_tool directory of the agent. Alternatively, you can override the path with the environment variable AGENT_TOOLSDIRECTORY. Under the tools directory, create the following directory structure based on your Python version:

$AGENT_TOOLSDIRECTORY/
    Python/
        {version number}/
            {platform}/
                {tool files}
            {platform}.complete

The version number should follow the format of 1.2.3. The platform should either be x86 or x64. The tool files should be the unzipped Python version files. The {platform}.complete should be a 0-byte file that looks like x86.complete or x64.complete and just signifies the tool is properly installed in the cache.

For example, to use Python 3.11 on a 64-bit Windows machine, create the following directory structure:

$AGENT_TOOLSDIRECTORY/
    Python/
        3.11.4/
            x64/
                {python files}
            x64.complete

If the machine hosting your agent already has the Python version you want to use, you can copy the files to the tool cache. If you don't have the Python version, you can download it from the Python website.

Prepare the sample app

  1. Fork the sample repository at https://github.com/Microsoft/python-sample-vscode-flask-tutorial to your GitHub account.

  2. Clone your fork to your local machine by using git clone <your-forked-repository-url>.git.

  3. Go to your local clone by using cd python-sample-vscode-flask-tutorial, and build and run the app locally to make sure it works.

    python -m venv .env
    source .env/Scripts/activate
    pip install --upgrade pip
    pip install -r ./requirements.txt
    export FLASK_APP=hello_app.webapp
    flask run
    
  4. To test the app, go to http://localhost:5000 in a browser window, and verify that you see the title Visual Studio Flask Tutorial.

  5. Close the browser window and stop the Flask server by using Ctrl+C.

Create and deploy the App Service web app

Create your Azure App Service web app by using Cloud Shell in the Azure portal. To use Cloud Shell, sign in to the Azure portal and select the Cloud Shell button on the toolbar.

Screenshot of Azure Cloud Shell button on the Azure portal toolbar.

The Cloud Shell appears along the bottom of the browser. Make sure Bash is selected as the environment in the dropdown menu. You can maximize the Cloud Shell window to give yourself more room.

Screenshot of Azure Cloud Shell.

Tip

To paste into Cloud Shell, use Ctrl+Shift+V or right-click and select Paste from the context menu.

Create and deploy the web app

  1. In Cloud Shell, clone your forked repository to Azure with the following command, replacing <your-forked-repository-url> with the URL of your forked repository.

    git clone <your-forked-repository-url>
    
  2. Change directory to the cloned repository folder.

    cd python-sample-vscode-flask-tutorial
    
  3. Run the az webapp up command to provision the App Service web app and do the first deployment. Use the --name <your-web-app-name> parameter to assign a name that's unique across Azure, such as a personal or company name along with an app identifier, like --name <your-name>-flaskpipelines. Running az webapp up with no parameters assigns a randomly generated web app name that's unique in Azure.

    az webapp up --name <your-web-app-name>
    

The az webapp up command recognizes the app as a Python app, and takes the following actions:

  1. Creates a default resource group.
  2. Creates a default App Service plan.
  3. Creates a web app with the assigned name. The app URL is <your-web-app-name>.azurewebsites.net.
  4. Deploys all files from the current working directory to a ZIP archive, with build automation enabled.
  5. Caches the parameters locally in the .azure/config file so you don't need to specify them again when deploying from the project folder with az webapp up or other az webapp commands. The commands use the cached values automatically by default.

You can override the default actions with your own values by using the command parameters. For more information, see az webapp up.

The az webapp up command produces the following JSON output for the sample web app:

{
  "URL": <your-web-app-url>,
  "appserviceplan": <your-app-service-plan-name>,
  "location": <your-azure-region>,
  "name": <your-web-app-name>,
  "os": "Linux",
  "resourcegroup": <your-resource-group>,
  "runtime_version": "python|3.11",
  "runtime_version_detected": "-",
  "sku": <sku>,
  "src_path": <repository-source-path>
}

Record the URL, resourcegroup, and runtime_version values to use later in this tutorial.

Set the startup command

The python-sample-vscode-flask-tutorial app has a startup.txt file that contains the specific startup command for the web app. Set the web app startup-file configuration property to startup.txt by entering the following command, using your resource group and web app names.

az webapp config set --resource-group <your-resource-group> --name <your-web-app-name> --startup-file startup.txt

When the command completes, the JSON output shows all the configuration settings for your web app.

To see the running app, open a browser and go to the URL shown in the az webapp up command output. If you see a generic page, wait a few seconds for the App Service to start, then refresh the page. Verify that you see the title Visual Studio Flask Tutorial.

Connect your Azure DevOps project to your Azure subscription

To use Azure Pipelines to deploy to your Azure App Service web app, you need to connect your Azure DevOps project to your Azure resources.

Create a service principal

A service principal is an identity created for applications, hosted services, and automated tools to access Azure resources. This access is restricted to the roles assigned to the service principal, giving you control over which resources can be accessed at which level.

To create a service principal, run the following command in Bash Cloud Shell. Replace <service-principal-name> with a name for your service principal, <your-subscription-id> with your Azure subscription ID, and <your-resource-group> with the resource group for the web app.

az ad sp create-for-rbac --display-name <service-principal-name> --role contributor --scopes /subscriptions/<your-subscription-id>/resourceGroups/<your-resource-group>

The command returns the following JSON object:

{
  "appId": "<client GUID>",
  "displayName": "<service-principal-name">,
  "password": "<password-string>",
  "tenant": "<tenant GUID>"
  ...
}

Make a note of the appId, password, and tenantId values to use for creating a service connection in the next section.

Create a service connection

A service connection provides authenticated access from Azure Pipelines to external and remote services. To deploy to your Azure App Service web app, create a service connection to the resource group for your web app.

  1. On your Azure DevOps project page, select Project settings.

  2. From Project Settings, select Pipelines > Service connections.

  3. On the Service connections page, select New service connection or Create service connection if this service connection is the first in the project.

    Screenshot of selecting Pipeline Service connections in Project Settings.

  4. On the New service connection screen, select Azure Resource Manager and then select Next.

    Screenshot of Azure Resource Manager service connection selection.

  5. On the New Azure service connection screen, select your Identity type. This example uses App registration (automatic), which is recommended. For more information about authentication methods, see Connect to Azure by using an Azure Resource Manager service connection.

  6. For Credential, select Workload identity federation (automatic).

  7. Complete the following fields:

    • Scope level: Select Subscription.
    • Subscription: Select your Azure subscription.
    • Resource group: Select the resource group that contains your web app.
    • Service Connection Name: Enter a descriptive name for the connection.
    • Grant access permissions to all pipelines: Select this check box to grant access to all pipelines in the project.
  8. Select Save.

    Screenshot of New Azure service connection dialog box.

  1. On your Azure DevOps project page, select Project settings.

  2. From Project Settings, select Pipelines > Service connections.

  3. On the Service connections page, select New service connection or Create service connection if this service connection is the first in the project.

    Screenshot of project settings button on the project dashboard.

  4. On the New service connection screen, select Azure Resource Manager and then select Next.

    Screenshot that shows the Azure Resource Manager selection.

  5. Select Service principal (manual) and then select Next.

    Screenshot that shows selecting a service principal (manual) authentication method selection.

  6. On the New Azure service connection screen, complete the following fields:

    • Environment: Select Azure Cloud.
    • Scope Level: Select Subscription.
    • Subscription Id: Enter your Azure subscription ID.
    • Subscription Name: Enter your Azure subscription name.
  7. In the Authentication section, complete the following fields:

    • Service Principal Id: Enter the appId value returned by the az ad sp create-for-rbac command.
    • Credential: Select Service principal key.
    • Service principal key: Enter the password value returned by the az ad sp create-for-rbac command.
    • Tenant Id: Enter the tenant value returned by the az ad sp create-for-rbac command.
    • Select Verify to verify the connection.
  8. In the Details section, under Service Connection Name, enter a name for the service connection.

  9. Select the check box for Grant access permissions to all pipelines.

  10. Select Verify and save.

    Screenshot of top part of the new service connection screen.

The new connection appears in the Service connections list, and is ready to use in your pipeline.

Create a pipeline

Create a pipeline to build and deploy your Python web app to Azure App Service.

  1. On the left navigation menu for your project, select Pipelines.

  2. On the Pipelines page, select New pipeline, or Create pipeline if this pipeline is the first in the project.

    Screenshot of new pipeline button on the pipelines list.

  3. On the Where is your code screen, select GitHub. You might be prompted to sign into GitHub.

    Screenshot of selecting GitHub as the location of your code.

  4. On the Select a repository screen, select your forked sample repository. GitHub might prompt you to enter your GitHub password again, or to install the Azure Pipelines GitHub app. Follow onscreen instructions to install the app. For more information, see GitHub app authentication.

    Screenshot of repository selection.

  5. On the Configure your pipeline page, select Python to Linux Web App on Azure.

  6. On the next screen, select your Azure subscription and select Continue.

  7. On the next screen, select your Azure web app and select Validate and configure.

Azure Pipelines creates an azure-pipelines.yml file and displays it in the YAML pipeline editor.

  1. On the left navigation menu for your project, select Pipelines.

  2. On the Pipelines page, select New pipeline, or Create pipeline if this pipeline is the first in the project.

    Screenshot of new pipeline button on the pipelines list.

  3. On the Where is your code page, select GitHub Enterprise Server. You might be prompted to sign into GitHub.

    Screenshot of select GitHub as the location of your code.

  4. On the Select a repository tab, select your forked sample repository. GitHub might prompt you to enter your GitHub password again or install the Azure Pipelines GitHub extension or app. Follow onscreen instructions to install the app. For more information, see Access to GitHub repositories.

    Screenshot of repository selection.

  5. On the Configure your pipeline page, select Starter pipeline.

  6. On the Review your pipeline YAML page, replace the contents of the starter azure-pipelines.yml file with the following YAML pipeline file. In the YAML file:

    • Replace the <your-service-connection-name> and <your-web-app-name> placeholders with your own values.

    • Replace <your-pool-name> with the name of the agent pool you want to use, and replace <your-python-version> with the version of Python running on your agent. This version should match the runtime_version from the JSON output of the az webapp up command.

YAML pipeline file

On the Review your pipeline YAML page, look at the pipeline to see what it does. Make sure all the default inputs are appropriate for your code. To learn about the pipeline YAML file schema, see the YAML schema reference.

The following complete example YAML pipeline file defines your CI/CD pipeline as a series of stages, jobs, and steps, where each step contains the details for different tasks and scripts. The generated YAML code automatically populates the placeholders with values for your app and connection.

trigger:
- main

variables:
  # Azure Resource Manager connection created during pipeline creation
  azureServiceConnectionId: '<GUID>'

  # Web app name
  webAppName: '<your-webapp-name>'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'

  # Environment name
  environmentName: '<your-webapp-name>'

  # Project root folder. Point to the folder containing manage.py file.
  projectRoot: $(System.DefaultWorkingDirectory)

  pythonVersion: '3.11'

stages:
- stage: Build
  displayName: Build stage
  jobs:
  - job: BuildJob
    pool:
      vmImage: $(vmImageName)
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '$(pythonVersion)'
      displayName: 'Use Python $(pythonVersion)'

    - script: |
        python -m venv antenv
        source antenv/bin/activate
        python -m pip install --upgrade pip
        pip install setuptools
        pip install -r requirements.txt
      workingDirectory: $(projectRoot)
      displayName: "Install requirements"

    - task: ArchiveFiles@2
      displayName: 'Archive files'
      inputs:
        rootFolderOrFile: '$(projectRoot)'
        includeRootFolder: false
        archiveType: zip
        archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
        replaceExistingArchive: true

    - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
      displayName: 'Upload package'
      artifact: drop

- stage: Deploy
  displayName: 'Deploy Web App'
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: DeploymentJob
    pool:
      vmImage: $(vmImageName)
    environment: $(environmentName)
    strategy:
      runOnce:
        deploy:
          steps:

          - task: UsePythonVersion@0
            inputs:
              versionSpec: '$(pythonVersion)'
            displayName: 'Use Python version'

          - task: AzureWebApp@1
            displayName: 'Deploy Azure Web App : $(webAppName)'
            inputs:
              azureSubscription: $(azureServiceConnectionId)
              appName: $(webAppName)
              package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
trigger:
- main

variables:
  # Azure Resource Manager connection created during pipeline creation
  azureServiceConnectionId: '<your-service-connection-name>'

  # Web app name
  webAppName: '<your-web-app-name>'

  # Environment name
  environmentName: '<your-web-app-name>'

  # Project root folder. 
  projectRoot: $(System.DefaultWorkingDirectory)

  # Python version: 
  pythonVersion: '<your-python-version>'

stages:
- stage: Build
  displayName: Build stage
  jobs:
  - job: BuildJob
pool:
      name: '<your-pool-name>'
      demands: python
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '$(pythonVersion)'
      displayName: 'Use Python $(pythonVersion)'

    - script: |
        python -m venv antenv
        source antenv/bin/activate
        python -m pip install --upgrade pip
        pip install -r requirements.txt
      workingDirectory: $(projectRoot)
      displayName: "Install requirements"

    - task: ArchiveFiles@2
      displayName: 'Archive files'
      inputs:
        rootFolderOrFile: '$(projectRoot)'
        includeRootFolder: false
        archiveType: zip
        archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
        replaceExistingArchive: true

    - task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'drop'
        publishLocation: 'Container'

- stage: Deploy
  displayName: 'Deploy Web App'
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: DeploymentJob
    pool:
      name: '<your-pool-name'
    environment: $(environmentName)
    strategy:
      runOnce:
        deploy:
          steps:

          - task: UsePythonVersion@0
            inputs:
              versionSpec: '$(pythonVersion)'
            displayName: 'Use Python version'

          - task: AzureWebApp@1
            displayName: 'Deploy Azure Web App : <your-web-app-name>'
            inputs:
              azureSubscription: $(azureServiceConnectionId)
              appName: $(webAppName)
              package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
              startUpCommand: 'startup.txt'

Variables

The variables section at the beginning of the YAML file defines the following variables:

Variable Description
azureServiceConnectionId The ID of the Azure Resource Manager service connection.
webAppName The name of the App Service web app.
vmImageName The name of the operating system to use for the build agent.
environmentName The name of the environment to deploy to, which is automatically created when the deployment job runs.
projectRoot The root folder containing the app code.
pythonVersion The version of Python to use on the build and deployment agents.
Variable Description
azureServiceConnectionId The ID of the Azure Resource Manager service connection.
webAppName The name of the App Service web app.
environmentName The name of the environment to deploy to, which is automatically created when the deployment job runs.
projectRoot The folder containing the app code. The value is an automatic system variable.
pythonVersion The version of Python to use on the build and deployment agents.

Build and deployment stages

The pipeline consists of build and deployment stages.

Build stage

The build stage contains a single job that runs on the operating system defined in the vmImageName variable, in this case ubuntu-latest.

  - job: BuildJob
    pool:
      vmImage: $(vmImageName)

The build stage contains a single job that runs on an agent in the pool identified by the name parameter.

You can specify the agent capabilities with the demands keyword. For example, demands: python specifies that the agent must have Python installed. To specify a self-hosted agent by name, you can use demands: Agent.Name -equals <agent-name>.

  - job: BuildJob
    pool:
      name: <your-pool-name>
      demands: python

The job contains multiple steps:

  1. First, the UsePythonVersion task selects the version of Python to use, as defined in the pythonVersion variable.

       - task: UsePythonVersion@0
          inputs:
            versionSpec: '$(pythonVersion)'
            displayName: 'Use Python $(pythonVersion)'
    
  2. The next step uses a script that creates a virtual Python environment and installs the app's dependencies from requirements.txt. The workingDirectory parameter specifies the location of the app code.

       - script: |
            python -m venv antenv
            source antenv/bin/activate
            python -m pip install --upgrade pip
            pip install setuptools
            pip install  -r ./requirements.txt
          workingDirectory: $(projectRoot)
          displayName: "Install requirements"
    
  3. The ArchiveFiles task creates a ZIP archive that contains the built web app.

        - task: ArchiveFiles@2
          displayName: 'Archive files'
          inputs:
            rootFolderOrFile: '$(projectRoot)'
            includeRootFolder: false
            archiveType: zip
            archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
            replaceExistingArchive: true
    

    The parameters are set as follows:

    Parameter Description
    rootFolderOrFile The location of the app code.
    includeRootFolder Whether to include the root folder in the .zip file. Set to false. If set to true, the contents of the .zip file are put in a folder named s and the task can't find the app code.
    archiveType The type of archive to create. Set to zip.
    archiveFile The location of the .zip file to create.
    replaceExistingArchive Indicates whether to replace an existing archive if the file already exists. Set to true.
  4. The .zip file then uploads to the pipeline as an artifact named drop. The deployment stage uses the .zip file to deploy the app.

        - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
          displayName: 'Upload package'
          artifact: drop
    
    • The upload parameter sets the location and name of the .zip file to upload.
    • The artifact parameter sets the name of the created artifact to drop.

Deployment stage

The deployment stage runs if the build stage completes successfully. The dependsOn and condition keywords define this behavior.

  dependsOn: Build
  condition: succeeded()

The deployment stage contains a single deployment job configured as follows.

  - deployment: DeploymentJob
    pool:
      vmImage: $(vmImageName)
    environment: $(environmentName)
  • The deployment keyword indicates that the job is a deployment job targeting an environment to deploy to. The environment is automatically created in your project when the job is run.

  • The pool parameter specifies the deployment agent pool and uses the default agent pool if a name isn't specified. The agent runs on the operating system defined in the vmImageName variable, in this case ubuntu-latest.

  - deployment: DeploymentJob
    pool:
      name: <your-pool-name>
    environment: $(environmentName)
  • The deployment keyword indicates that the job is a deployment job targeting an environment to deploy to. The environment is automatically created in your project when the job is run.

  • The pool parameter specifies the deployment agent pool and must contain an agent with the capability to run the Python version specified in the pipeline.

The strategy keyword defines the deployment strategy.

  strategy:
    runOnce:
      deploy:
        steps:
  • The runOnce keyword specifies that the deployment job runs once.
  • The deploy keyword specifies the steps to run in the deployment job.

The steps in this stage run the following tasks:

  1. UsePythonVersion@0 selects the version of Python to use, same as in the Build stage.
  2. AzureWebApp@1 deploys the web app and the drop ZIP artifact.
- task: AzureWebApp@1
    displayName: 'Deploy Azure Web App : <your-web-app-name>'
  inputs:
    azureSubscription: $(azureServiceConnectionId)
    appName: $(webAppName)
    package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
  • The azureSubscription parameter contains the azureServiceConnectionId specified in the pipeline variables.
  • The appName contains the value of the webAppName variable.
  • The package specifies the name and location of the .zip file to deploy.

Also, because the python-vscode-flask-tutorial repository contains the app startup command in a file named startup.txt, you can specify the app startup command by adding the parameter: startUpCommand: 'startup.txt'.

Run the pipeline

You're now ready to try out the pipeline.

  1. In the pipeline editor, select Save and run.

  2. On the Save and run screen, add a commit message if desired and then select Save and run.

    You can watch the pipeline run by selecting the Stages or Jobs on the pipeline Summary page. Each job and stage displays a green check mark as it completes successfully. If errors occur, they appear in the summary or in the job steps.

    Screenshot of pipeline run summary stages section.

    You can quickly return to the YAML editor by selecting the vertical dots at the upper right on the Summary page and selecting Edit pipeline.

    Screenshot of edit pipeline comment from a build report.

  3. From the deployment job, select the Deploy Azure Web App task to display its output.

    Screenshot of pipeline stage steps.

  4. From the output, select the URL after App Service Application URL. The app should appear as follows:

    Screenshot of view of the sample app running on App Service.

Note

If an app deployment fails because of a missing dependency, the requirements.txt file wasn't processed during deployment. This issue can occur if you create the web app directly in the portal rather than using the az webapp up command.

The az webapp up command specifically sets the build action SCM_DO_BUILD_DURING_DEPLOYMENT to true. If you provision an app service through the portal, this action isn't automatically set.

To set this action:

  1. On the portal page for your web app, select Configuration from the left navigation menu.
  2. On the Application Settings tab, select New Application Setting.
  3. In the popup that appears, set Name to SCM_DO_BUILD_DURING_DEPLOYMENT, set Value to true, and select OK.
  4. Select Save at the top of the Configuration page.
  5. Run the pipeline again. The dependencies should now install during deployment.

Trigger a pipeline run

This pipeline is set to run whenever a change checks in to the code repository. To trigger a pipeline run, commit a change to the repository. For example, you can add a new feature to the app, or update the app's dependencies.

  1. Go to the GitHub repository for your app.
  2. Make a change to the code, such as changing the title of the app.
  3. Commit the change.
  4. Go to your pipeline and verify that a new run is created and is running.
  5. When the run completes, verify that the change deployed to your web app.
  6. In the Azure portal, go to your web app and select Deployment Center from the left navigation menu.
  7. Select the Logs tab and verify that the new deployment is listed.

Deploy Django apps to App Service

You can use Azure Pipelines to deploy Django apps to App Service on Linux if you're using a separate database. You can't use a SQLite database, because App Service locks the db.sqlite3 file, preventing both reads and writes. This behavior doesn't affect external databases.

As explained in Container startup process, App Service automatically looks for a wsgi.py file in your app code, which typically contains the app object. If you want to customize the startup command, use the startUpCommand parameter in the AzureWebApp@1 step of your YAML pipeline file.

When you use Django, you typically want to migrate the data models using manage.py migrate after deploying the app code. You can add startUpCommand with a post-deployment script for this purpose. For example, here's the startUpCommand property in the AzureWebApp@1 task.

  - task: AzureWebApp@1
      displayName: 'Deploy Azure Web App : $(webAppName)'
      inputs:
        azureSubscription: $(azureServiceConnectionId)
        appName: $(webAppName)
        package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
        startUpCommand: 'python manage.py migrate'

Run tests on the build agent

As part of your build process, you might want to run tests on your app code. Tests run on the build agent, so you need to install your dependencies into a virtual environment on the build agent. After the tests run, delete the test virtual environment before you create the .zip file for deployment.

The following script elements illustrate this process. Place them before the ArchiveFiles@2 task in the azure-pipelines.yml file. For more information, see Run cross-platform scripts.

# The | symbol is a continuation character, indicating a multi-line script.
# A single-line script can immediately follow "- script:".
- script: |
    python -m venv .env
    source .env/bin/activate
    pip install setuptools
    pip install -r requirements.txt

  # The displayName shows in the pipeline UI when a build runs
  displayName: 'Install dependencies on build agent'

- script: |
    # Put commands to run tests here
    displayName: 'Run tests'

- script: |
    echo Deleting .env
    deactivate
    rm -rf .env
  displayName: 'Remove .env before zip'

You can also use a task like PublishTestResults@2 to publish the test results to your pipeline. For more information, see Run tests.

Clean up resources

If you're finished with the Azure resources you created in this tutorial, delete them to avoid incurring further charges.

  • Delete the Azure DevOps project you created. Deleting the project deletes the pipeline and service connection.
  • Delete the Azure resource group that contains the App Service and the App Service Plan. In the Azure portal, go to the resource group, select Delete resource group, and follow the prompts.
  • Delete the Azure storage account that maintains the Cloud Shell file system. Close Cloud Shell, then find the resource group that begins with cloud-shell-storage-. Select Delete resource group, and follow the prompts.