Tutorial for deploying Python's Flask framework on Docker

  • 2020-05-07 19:56:39
  • OfStack

In this article, I will try to show you how it is possible to develop python applications (mainly Web applications) with Docker. While I myself focus on Python's Flask microframework, the purpose of this article is to demonstrate how to better develop and share applications (applications developed in any language and framework) through Docker. Docker greatly reduces the gap between the development environment and the formal product by encapsulating dependencies.

Most Python developers use virtualenv in their development. It provides an easy-to-use mechanism for applications to use their own proprietary dependencies that may conflict with other applications or operating systems (especially different versions of Pyhton, different library versions, and so on). Personally, I don't have much interest in virtualenv1 for the following reasons:

I often forget to enable      , or forget to switch it when switching projects, which leads to vague error messages and confusion.       does not provide "pure" isolation, only Python level isolation (system libraries and non-python dependencies are still problematic).       I usually don't want to run it in a formal product, which means that there is a difference between the development environment and the formal product.       feels like a bit of a hack: it relies on changing scripts and setting new paths.

(check out this pythonrants article for more on why you might not want to use virtualenv)

So how can Docker get better? Docker essentially provides a very lightweight VMs (" container "in the parlance) that we can use to create a high-standard isolation and greatly reduce mismatched development and production environments. (if you are not familiar with Docker and would like to learn more, you can check out my talk about Docker at the Edinburgh technical symposium).

When we created a small visual Web APP, I used this method with Mark Coleman myself (the documentation is here). This highlights a base image installation of Python 2.7, and a bit about Flask administration and PostgreSQL. I will develop an Web application for hello world based on this image. I assume that you are developing on Linux, and that you already have git and Docker installed, MacOS's instructions should be very similar. Start by cloning and creating a basic mirror:
 


$ git clone https://github.com/mrmrcoleman/python_webapp
$ docker build -t python_webapp .

Now we need to add some code to the container and specify it. We are going to do this by creating a new project that simply points to the Docker mirror, rather than directly modifying the previous project.

Create a new project with the following structure:

 


├ ─ ─ Dockerfile
  ├ ─ ─ example_app
  │    ├ ─ ─ app
  │    │    ├ ─ ─ __init__.py
  │    │    └ ─ ─ views.py
  │    └ ─ ─ __init__.py
  ├ ─ ─ example_app.wsgi 

Or clone the address of the sample projects: https: / / github com/amouat/example_app git

In example_app/app/ _init_.py, write:
 


from flask import Flask
 
app = Flask(__name__)
from app import views

Make the other _init_.py null. In views.py, write:
 


from app import app
 
@app.route('/')
@app.route('/index')
def index():
  return "Hello, World!"

This is the minimum version of flask for our hello world application. I've used similar code in this tutorial, so if you're new to Flask or Python, you can continue using Docker instead of virtualenv, as mentioned above.

To make it run inside the Docker container, we need to do one more thing. In our instance Apache server, the example_app.wsgi file contains instructions to connect the Python code to the web server. The document should contain the following:
 


import site
site.addsitedir('/opt/example_app/')
from app import app as application

Finally, we need 1 Dockerfile to build the container and run it. In our example, it looks like this:
 


FROM python_webapp
 
MAINTAINER amouat
 
ADD example_app.wsgi /var/www/flaskapp/flaskapp.wsgi
CMD service apache2 start && tail -F /var/log/apache2/error.log

The ADD action starts WSGI with some code injected. The CMD line gets any possible error message when the container is started, starting the apache web server, and sends it to stdout.

If you:
 


$ docker build -t example_app .
$ docker run -p 5000:5000 -v $(pwd)/example_app:/opt/example_app/ -i -t example_app

You should get this feedback: open the address localhost:5000 with your browser and you will see that your site is running. If you are running VM or vagrant, remember to open port 5000.

Now that we're running the web server, it's pretty close to what we're using in production (I intentionally used Apache instead of Python's default web server). We inject code into the container by mapping from the host to the container. We could also add code on the Dockerfile command line using ADD, but then we would have to rebuild the container every time we made a change to the code.

However, this is still not very good; In development we really wanted to use the Python web server that helped us debug a lot. The good news is that we don't have to make any changes to Dockerfile. In the example_app file, start by creating one run.py file.
 


!flask/bin/python
from app import app
app.run(debug = True, host='0.0.0.0')

This will start Python's web server with debugging and listen for all connections, which we can also access from outside the container. Now restart the container with the following command:
 


$ docker run -p 5000:5000 -v $(pwd)/example_app:/opt/example_app/ -i -t example_app python /opt/example_app/run.py

You can see the page running again. This time we explicitly provide the command to run ("python /opt/example_app/ ryn.py "), which overrides the CMD line in Dockerfile. Now if you edit the source program on the host, you can immediately see the changes on the web page.

Let's take a moment to look at our results:

      1 web application running in an isolated container that fully encapsulates the application's Python dependencies and system dependencies.       is able to develop code using an existing editor or IDE and see changes directly, as if editing 1 locally.       is closer than ever to the operating environment of a formal product.       does not use virtualenv.

If you want to know how to set up a distribution path in this way, check out Mark Coleman's article on the aforementioned visualization Web application.

Unfortunately, it's not perfect. The following questions remain:

You may still encounter situations where you need to use virtualenv or its equivalent, such as conflicts between the version of the library's operating system and the version your program requires.       we haven't fully solved the data hosting problem yet, and we still need to do some testing.       I assumed the "product" was an Docker container, but this is often not the case and Docker hosting itself is just getting started.

Still, I think it's a big step toward a better future for software development, and it takes a lot of the pain out of deploying software and managing dependencies.


Related articles: