Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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
Fork the sample repository at https://github.com/Microsoft/python-sample-vscode-flask-tutorial to your GitHub account.
Clone your fork to your local machine by using
git clone <your-forked-repository-url>.git.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 runTo test the app, go to http://localhost:5000 in a browser window, and verify that you see the title Visual Studio Flask Tutorial.
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.
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.
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
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>Change directory to the cloned repository folder.
cd python-sample-vscode-flask-tutorialRun 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. Runningaz webapp upwith 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:
- Creates a default resource group.
- Creates a default App Service plan.
- Creates a web app with the assigned name. The app
URLis<your-web-app-name>.azurewebsites.net. - Deploys all files from the current working directory to a ZIP archive, with build automation enabled.
- 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 upor otheraz webappcommands. 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:
First, the UsePythonVersion task selects the version of Python to use, as defined in the
pythonVersionvariable.- task: UsePythonVersion@0 inputs: versionSpec: '$(pythonVersion)' displayName: 'Use Python $(pythonVersion)'The next step uses a script that creates a virtual Python environment and installs the app's dependencies from
requirements.txt. TheworkingDirectoryparameter 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"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: trueThe parameters are set as follows:
Parameter Description rootFolderOrFileThe location of the app code. includeRootFolderWhether to include the root folder in the .zip file. Set to false. If set totrue, the contents of the .zip file are put in a folder named s and the task can't find the app code.archiveTypeThe type of archive to create. Set to zip.archiveFileThe location of the .zip file to create. replaceExistingArchiveIndicates whether to replace an existing archive if the file already exists. Set to true.The
.zipfile then uploads to the pipeline as an artifact nameddrop. The deployment stage uses the .zip file to deploy the app.- upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip displayName: 'Upload package' artifact: drop- The
uploadparameter sets the location and name of the .zip file to upload. - The
artifactparameter sets the name of the created artifact todrop.
- The
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
runOncekeyword specifies that the deployment job runs once. - The
deploykeyword specifies thestepsto run in the deployment job.
The steps in this stage run the following tasks:
- UsePythonVersion@0 selects the version of Python to use, same as in the Build stage.
- AzureWebApp@1 deploys the web app and the
dropZIP 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
azureSubscriptionparameter contains theazureServiceConnectionIdspecified in the pipeline variables. - The
appNamecontains the value of thewebAppNamevariable. - The
packagespecifies 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.
In the pipeline editor, select Save and run.
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.
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.
From the deployment job, select the Deploy Azure Web App task to display its output.
From the output, select the URL after App Service Application URL. The app should appear as follows:
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:
- On the portal page for your web app, select Configuration from the left navigation menu.
- On the Application Settings tab, select New Application Setting.
- In the popup that appears, set Name to
SCM_DO_BUILD_DURING_DEPLOYMENT, set Value totrue, and select OK. - Select Save at the top of the Configuration page.
- 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.
- Go to the GitHub repository for your app.
- Make a change to the code, such as changing the title of the app.
- Commit the change.
- Go to your pipeline and verify that a new run is created and is running.
- When the run completes, verify that the change deployed to your web app.
- In the Azure portal, go to your web app and select Deployment Center from the left navigation menu.
- 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.