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

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 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.

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.

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.

Variables

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

Build and deployment stages

The pipeline consists of build and deployment stages.

Build stage

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.

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.