Deploying a Python app on Azure

using Flask, Docker and Azure App Service

Robert van Straalen
Data Science Lab Amsterdam
6 min readJun 10, 2019

--

My previous article described how we built an AI function for creating a path of similar faces from some starting image towards a celebrity.

This follow-up article will describe the steps needed to bring your AI to a live website on the Azure cloud platform:

  • Some Flask basics to use your Python function in a web application
  • How to use production-suitable web server Gunicorn to run it
  • How to create a Docker image for your application
  • How to deploy in using Azure App Service
  • Workflow for handling updates
Why do I need all those tools…?

Basic Flask app

Okay, first things first… So the result of the previous blog is that we have some Python scripts containing a function that does the work for creating a ‘picture path’:

We are now gonna build a basic Flask app that assumes the following structure:

  • We build a homepage in HTML, Javascript , CSS
  • We also build a form to upload a new image
  • We build a Flask app using a file app.py that links requests to either HTML pages or Python functions

This is what the Flask script (roughly) looks like:

Gunicorn

You can run this using python src/app.py and you get a perfectly fine working web page (well, only after some amount of debugging probably…). So why would we bother with this Gunicorn thing? Short answer, because the Flask webpage says this:

While lightweight and easy to use, Flask’s built-in server is not suitable for production as it doesn’t scale well and by default serves only one request at a time.

Then what’s Gunicorn? Well, from their webpage:

Gunicorn ‘Green Unicorn’ is a Python WSGI HTTP Server for UNIX. It’s a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

This basically means it is suitable for production… And no worries, it’s very easy to use. All we have to do is install it using pip install gunicorn and then replace python src/app.py by gunicorn src.app:app to run the app (ok, you’ll probably want to include some extra parameters in that call).

Docker + Azure

Ok, so we’ve got a working web app now, great! Only thing left to do is deploy it… Within the Azure platform this works via App Services and specifically, since we’re deploying a web application, a Web App.

GUI for creating a new web app in Azure

As you can see, we can choose between ‘Code’ (in our case with a Python runtime stack) or a Docker Image. I’ve found that replicating the Python environment with required packages/dependencies is easier using Docker than trying to install them via some CLI to the Web App’s VM. So let’s choose Docker here. If you do, in the next screen you need to configure which Docker image should be used and where Azure can get it from:

What’s all that stuff about? Let’s start with creating our own Docker image first and then come back to this.

Creating the Docker image

Our Docker workflow will be as follows:

  1. Create a Docker file describing what the image should look like
  2. Build the image from the file
  3. Publish the image to a registry (so it can be accessed by Azure)

Ok, suppose our project structure has (among others):

  • a src dir containing the source code and a file app.py
  • a requirements.txt denoting the required Python packages

then create a Dockerfile (no extension) in the project root with the following basic setup:

In addition, it’s good to create a .dockerignore file to specify (similar to a .gitignore file) which files should not be copied to the Docker image. This can potentially greatly reduce the image’s size! Just fill in line like this:

Now, from a terminal browse to your project root and run

This will (try to) build an image based on the Dockerfile in the current directory (that’s what the dot refers to!) and name it ‘myapp’. The first time you run this it will take a long time (installing packages mostly). If you re-build it’ll be faster because it uses cache for unchanged parts.

After building you can run the image locally using:

Remember: we made Gunicorn run the app on port 8000. The -p 8000:80 forwards port 8000 on the container to port 80 (the default http port) on the host machine. So now we can access the app by visiting localhost in the browser.

Publishing the Docker image

Now we’re going to publish the image to a registry. Azure has a container registry, Docker Hub is Docker’s registry service and there are others. We’ll use Docker Hub in this example. First you need to have an account. Then use it for

Now let’s give our image an appropriate name using the tag command. Adhere to the format of [dockerhub-username]/[repo-name]:[some-tag]

Now we publish it (i.e. upload to the registry) using the push command:

Ok great! The Docker part is done, now back to Azure.

Azure configuration

Now we know exactly what to fill in in the previous Azure form!

Now, if you remember we had a docker run command to start the container and run the app. You can’t specify this command in Azure. It kind of does it by itself.
Q: But then how do we do the port mapping?
A: Under Settings / Configuration add an entry for name WEBSITES_PORT with value 8000. It will automatically map it to port 80.

That’s it! Now your web app is running and accessible via https://myuniqueappname.azurewebsites.net

Continuous deployment

Ok one more thing… Since your app is never finished after first publication and you’ll want to update it regularly: what is the workflow for this?

First, you need to enable continuous deployment by doing the following:

  • In Azure’s page for your web app, go to ‘Container settings’, set ‘Continuous Deployment’ to ‘On’ and copy the webhook url underneath it.
  • Go to Docker Hub’s repo page for your image, go to ‘Webhooks’, add a new one and paste Azure’s webhook url under, you guessed it, ‘Webhook URL’.

What this does is create an event listener such that

  • whenever you push a new version of this image to Docker Hub
  • Docker Hub sends a message to Azure
  • Azure pulls the latest version

Once this is in place, after updating our application we can do:

and the live version will be updated automatically.

--

--

Robert van Straalen
Data Science Lab Amsterdam

Lead Data Scientist @ Data Science Lab. Working on machine learning projects across various sectors. Always looking to simplify and improve processes.