This article is contributed. See the original author and article here.


Guest post by Malcolm Smith Fraser, MS Candidate at Duke University | Race and the Professions Fellow at The Kenan Institute of Ethics. Malcolm is an Interdisciplinary Data Science master’s student at Duke University. He is interested in data science, machine learning engineering, and cloud computing. Away from the computer screen his passions revolve around music, fitness, and good food.

Continuous Delivery

In short, continuous delivery (and its younger sibling continuous integration) is a way to ensure that any code you write is always in a functioning state. While continuous integration automates the process of testing our code every time it is checked into a repository, continuous delivery adds the extra step of also updating any applications running on that code. This could be a single step such as updating a static website, or multiple steps – like updating a container that lives in a container registry, then initiating a redeployment of an application that runs on that container image.


The functionality behind continuous delivery lies in the build server. Some build servers are their own standalone services and others are integrated with the various cloud providers. Services like Jenkins, Travis, GitHub Actions and Azure DevOps are all examples of build servers. I will not go into too much depth on these in this post, but they are pretty cool.


In this post I am going to focus on continuous delivery for a Flask-based web application that runs on Azure App Service. However, most of the things I will show are applicable to other applications. I will be showing continuous delivery with Azure DevOps and GitHub Actions which both have very nice integrations with Azure App Service. All code for this application can be found in my GitHub repository here. [malcolmsfraser/AzureFlask-CD (]



When working properly with Azure DevOps, the continuous delivery workflow looks like this:

Deployed web application.





Make a change and push it to my repository.



Push triggers an app build and new deployment.



Updated web app!





Cool right!?


The main component you need when setting up continuous delivery for any service is a .yml build file. This is what the build server uses to execute commands when activated. Thankfully, the sleek integrations that Azure has with the two build servers I am using means that you do not need to concern yourself with all the syntax needed to write the file yourself.


Azure DevOps

Once you have an application up and running on Azure App Service. Navigate to the Azure DevOps home screen [] and create a free account. Follow the prompts to create a new project.




Next you need to create a service connection between your Azure DevOps project and the resource group under which your App Services application is deployed.

*Please note that if you are part of an organization that limits your permissions in making changes to the Active Directory, you might not be able to make this connection. I had to switch to a non Microsoft account to create the service connection.


Navigate to project settings, and then select service connections.




Create a new service connection to the Resource group containing the web application.




Now that you have successfully connected to the resource deploying your application, it is time to setup the continuous delivery pipeline.

Click Pipelines à New pipeline. You will then be prompted connect to where your code is hosted (I chose GitHub, but it could be on any of the supported options) and then specify the specific repository where the code lives.






The following page is where you can select the type of pipeline you will be deploying. Since I am working with a Python web application I selected “Python to Linux Web App on Azure”. However, if you click “Show more” you can see how you can easily configure a pipeline do various things – like build and push a Docker image to Azure Container Registry, which could even be followed by a Kubernetes deployment… lots of options to fit your needs.






Once you select the appropriate pipeline configuration, you will be prompted to connect it to the specific resource you are creating it for. Again, since I am working with a web application, I select the name of the appropriate Azure App Service resource in the group I connected to earlier. On the next screen I can hit “Save and run” and a file named azure-pipelines.yml will be pushed to my repository by Azure DevOps. Now every time I make a push to this repository, it will trigger Azure DevOps to redeploy the web application with any new changes.


GitHub Actions

I also could have set up CD with GitHub Actions, which is separate from the Azure DevOps workflow. To initialize you need to navigate to your Azure App Service resource and select “Deployment Center” from the menu on the right.




From there, navigate to the settings tab and create a new CI/CD integration, connect to your repository, select the runtime, and click save.

If you are using GitHub, this will create a file in your repository named .github/workflows/master_{app-name}.yml. Like the Azure DevOps workflow, now whenever you push you your repo GitHub Actions will kick start a deployment to Azure App Service.




Adding other steps to continuous delivery

Up until now the continuous delivery us only deploying your application. Better practice would be to also lint and test the application before it gets deployed (I am just linting here but adding a test would be the same idea). Simply insert these steps to the .yml file after the python environment has built. I use a Makefile to simplify these commands (make lint), but you could run them explicitly.


Azure DevOps (azure-pipelines.yml) on left and GitHub Actions (master_FlaskApp-CD.yml) on right:




Both options for continuous delivery are very straightforward. That being said, it is very easy to see how Azure DevOps could quickly be used to continuously deliver a wide range of applications by changing just a single step in the process, while the current workflow for GitHub Actions that I used is more specific to the Python/Linux web app use case. I suspect that the integration for GitHub Actions is probably just as seamless across other Azure services, but I have not tried it yet.


Next, I want to try this with a containerized deployment…because containers are cool.

Additional Learning Resources
DevOps Learning Pathways 

Evolve your DevOps practices learning path – Learn | Microsoft Docs
Deploy applications with Azure DevOps learning path – Learn | Microsoft Docs
Build applications with Azure DevOps learning path – Learn | Microsoft Docs

Container and DevOps
Introduction to Azure Kubernetes Service – Learn | Microsoft Docs
Introduction to Kubernetes – Learn | Microsoft Docs
Automate multi-container Kubernetes deployments with Azure Pipelines – Learn | Microsoft Docs
Automate Docker container deployments with Azure Pipelines – Learn | Microsoft Docs

Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.