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_DEPLOYMENTto 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) 😄
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'
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.