Automated deployment of a Vue Flask app using Azure Pipelines
In this article we will look at how to automate the deployment of a Vue Flask app to Azure App Service with Azure Pipelines. In a previous article I covered building a Vue Flask app to query a SQL database and return data to the browser to view or download. We will start with the same template, prepare it for deployment and configure the app service and pipeline in Azure. The result will be a deployed Flask app which serves a static Vue.js frontend. If you have your own application, you can adapt these steps. Before starting, you will need an Azure subscription alongside Python, Node.js and Yarn installed.
Download the template
First go to this public repository and download the project template as a zip file. Extract the folder contents and open the folder in a code editor like Visual Studio Code.
Configure the template for deployment
One thing needs adding before we deploy. Create a new file startup.py
at the top of the folder - same directory as run.py
. This will be the file Azure App Service uses to start the application.
"""
The startup file for Azure App Service that just imports the app object.
"""
from app import app
Setting up the automated pipeline
Here are the step by step actions the video below will go through to create the automated pipeline:
- Create a new Azure App Service in the Azure portal
- Set the environment variable
SCM_DO_BUILD_DURING_DEPLOYMENT
to true in the App Service - Create a new project in Azure DevOps
- Create an Azure Repo in the project
- Push the application code to the Azure Repo
- Set up an Azure Pipeline in the project
- Build and deploy the app to Azure App Service
- Check the site is deployed (had to hard refresh with Ctrl + F5) 😄
Setting the SCM_DO_BUILD_DURING_DEPLOYMENT
environment variable to true took me a while to figure out. It's in this section of the docs and states:
If your app fails because of a missing dependency, then your requirements.txt file was not processed during deployment. This behavior happens if you created the web app directly on the portal rather than using the az webapp up command as shown in this article. The az webapp up command specifically sets the build action SCM_DO_BUILD_DURING_DEPLOYMENT to true. If you provisioned the app service through the portal, however, this action is not automatically set.
The YAML I used for the build and deploy steps looked like this:
# Python to Linux Web App on Azure
# Build your Python project and deploy it to Azure as a Linux Web App.
# Change python version to one thats appropriate for your application.
# https://docs.microsoft.com/azure/devops/pipelines/languages/python
trigger:
- master
variables:
# Azure Resource Manager connection created during pipeline creation
azureServiceConnectionId: 'f59ed866-b638-412b-bdce-02504965ee64'
# Web app name
webAppName: 'vue-flask-app'
# Agent VM image name
vmImageName: 'ubuntu-latest'
# Environment name
environmentName: 'vue-flask-app'
# Project root folder. Point to the folder containing manage.py file.
projectRoot: $(System.DefaultWorkingDirectory)
# Python version: 3.6
pythonVersion: '3.6'
stages:
- stage: Build
displayName: Build stage
jobs:
- job: BuildJob
pool:
vmImage: $(vmImageName)
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(pythonVersion)'
displayName: 'Use Python $(pythonVersion)'
- task: NodeTool@0
inputs:
versionSpec: '10.x'
displayName: 'Install Node.js'
- script: pip install --upgrade pip
displayName: 'Upgrade pip'
workingDirectory: $(projectRoot)
- script: pip install pipenv
displayName: 'Install pipenv'
- script: python -m pipenv install --dev
displayName: 'Install Python dependencies'
- script: python -m pipenv run pip freeze > requirements.txt
displayName: 'Generate requirements.txt'
- script: |
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.9.4
export PATH="$HOME/.yarn/bin:$PATH"
yarn install
yarn upgrade
displayName: 'Install Node dependencies'
- script: yarn build
displayName: 'Build Vue app'
- script: |
pip install codecov
pip install pytest
pip install pytest-sugar
pip install pytest-cov
pip install pytest-azurepipelines
python -m pipenv run pytest --junitxml=$(System.DefaultWorkingDirectory)/testResults.xml --cov=app --cov-report=xml --cov-report=html
displayName: 'Run tests with pytest'
- task: PublishTestResults@2
displayName: "Publish test results"
inputs:
testResultsFiles: '$(System.DefaultWorkingDirectory)/testResults.xml'
testRunTitle: '$(Agent.OS) - $(Build.BuildNumber)[$(Agent.JobName)] - Python $(python.version)'
failTaskOnFailedTests: true
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
displayName: "Publish code coverage"
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
reportDirectory: '$(System.DefaultWorkingDirectory)/**/htmlcov'
- 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 : vue-flask-app'
inputs:
azureSubscription: $(azureServiceConnectionId)
appName: $(webAppName)
package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
startUpCommand: 'gunicorn --bind=0.0.0.0 --workers=4 --timeout 600 startup:app'
Your azureServiceConnectionId
will be different so be sure to change that.
Deployment was successful!
You now have a deployed Vue Flask app with a continuous integration pipeline configured. You can deploy new features with a simple push to the master branch which will trigger the pipeline. You could completely change the application we have deployed and take it in your own direction. Not only that, you might have noticed that this setup also publishes pytest code test coverage to the pipeline! Let me know in the comments if this helped you and if you have any questions. I know this was quite Azure specific, I think you could set up a similar pipeline using AWS or Google Cloud Platform.
I really like the Vue Flask combination for the ease of creating an interactive experience with Vue, alongside the many packages for data science that Python offers. You could separate this setup and have Vue served from a CDN and Python running as the API layer, but for a quick starter single-deploy setup this is perfect. It might need a little tailoring to your own needs, the template we used in this tutorial used Python 3.6 and pipenv, your setup might not, so adjust the Pipeline and App Service accordingly.
If you enjoyed this article be sure to check out other articles on the site 👍 you may be interested in: