using Flask, Docker and Azure App Service

Robert van Straalen
Jun 10 · 6 min read

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:

# base image
FROM python:3.6
# set web server root as working dir
WORKDIR /home/site/wwwroot
# install required packages
COPY requirements.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt

# copy all files
COPY . .

# expose port 8000
EXPOSE 8000

# start flask app using Gunicorn
CMD gunicorn -w 4 -b :8000 src.app:app

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:

data/*
.git

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

docker build -t myapp .

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:

docker run -p 8000:80 myapp

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

docker login

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

docker tag myapp robertvs/myapp:latest

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

docker push robertvs/myapp

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:

docker build -t myapp . && \
docker tag myapp robertvs/myapp:latest && \
docker push robertvs/myapp:latest

and the live version will be updated automatically.

Data Science Lab Amsterdam

A team of passionate digital thinkers who share their learnings as Data Scientists and Engineers

Robert van Straalen

Written by

Senior Data Scientist @ Data Science Lab.

Data Science Lab Amsterdam

A team of passionate digital thinkers who share their learnings as Data Scientists and Engineers

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade