How to Run Flask in Containers

by Bill Heller
How to Run Flask in Containers

This article is an excerpt from my book Mastering Python Networking, Third Edition – the one-stop solution to using Python for network automation, programmability, and DevOps.

Containers have become very popular over the last few years. Containers offer more abstractions and virtualization beyond hypervisor-based virtual machines. An in-depth discussion of containers is beyond the scope of this article. For our readers, we will offer a simple example of how we can run our Flask app in a Docker container. Flask is a micro web framework written in Python classified as a microframework because it does not require particular tools or libraries.

In this article, we will build our example based on the free DigitalOcean Docker tutorial on building containers on Ubuntu 18.04 machines. If you are new to containers, I would highly recommend that you go through the tutorial and then return to this section afterwards.

Let’s make sure Docker is installed:

$ sudo docker --version

Docker version 19.03.2, build 6a30dfc

We will make a directory named TestApp to house our code:

$ mkdir TestApp

$ cd TestApp/

In the directory, we will make another directory called app and create the __init__.py file:

$ mkdir app

$ touch app/__init__.py

For more information on user session management, logging in, logging out, and remembering user sessions, I would highly recommend using the Flask-Login extension.

Under the app directory is where we will contain the logic of our application. We’ll use a single-file app:

$ cat app/__init__.py

from flask import Flask, url_for, jsonify, request

from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///network.db'

db = SQLAlchemy(app)


@app.route('/')

def home():

return "Hello Python Netowrking!"

<skip>

class Device(db.Model):

       __tablename__ = 'devices'

       id = db.Column(db.Integer, primary_key=True)

       hostname = db.Column(db.String(64), unique=True)

       loopback = db.Column(db.String(120), unique=True)

       mgmt_ip = db.Column(db.String(120), unique=True)

       role = db.Column(db.String(64))

       vendor = db.Column(db.String(64))

        os = db.Column(db.String(64))

<skip>

We can also copy the SQLite database file we created to this directory:

$ tree app/

app/

├── __init__.py

├── network.db

We will place the requirements.txt file in the TestApp directory, as well as creating the main.py file as our entry point and an ini file for uwsgi:

$ cat main.py

from app import app

$ cat uwsgi.ini

[uwsgi]

module = main

callable = app

master = true

We will use a pre-made Docker image and create a Dockerfile that builds the Docker image:

$ cat Dockerfile

FROM tiangolo/uwsgi-nginx-flask:python3.7-alpine3.7

RUN apk --update add bash vim

RUN mkdir /TestApp

ENV STATIC_URL /static

ENV STATIC_PATH /TestApp/static

COPY ./requirements.txt /TestApp/requirements.txt

RUN pip install -r /TestApp/requirements.txt

Our start.sh shell script will build the image, run it as a daemon in the background, then forward port 8000 to the Docker container:

$ cat start.sh

#!/bin/bash

app="docker.test"

docker build -t ${app} .

docker run -d -p 8000:80 \

      --name=${app} \

      -v $PWD:/app ${app}

We can now use the start.sh script to build the image and launch our container:

$ sudo bash start.sh

Sending build context to Docker daemon 49.15kB

Step 1/7 : FROM tiangolo/uwsgi-nginx-flask:python3.7-alpine3.7

python3.7-alpine3.7: Pulling from tiangolo/uwsgi-nginx-flask

48ecbb6b270e: Pulling fs layer

692f29ee68fa: Pulling fs layer

<skip>

Our Flask now runs in the container that can be viewed from our host machine port 8000:

$ sudo docker ps

CONTAINER     ID       IMAGE      COMMAND        CREATED

STATUS               PORTS             NAMES

ac5384e6b007  docker.test       "/entrypoint.sh /sta…" 55

minutes ago   Up 46 minutes     443/tcp, 0.0.0.0:8000->80/tcp

docker.test

We can see the management host IP displayed in the address bar as follows:

How to Run Flask in Containers
Figure 1: Management host IP

We can see the Flask API endpoint as follows:

How to Run Flask in Containers
Figure 2: Flask API endpoint

Once we are done, we can use the following commands to stop and delete the container:

$ sudo docker stop <container id>

$ sudo docker rm <containter id>

We can also delete the Docker image:

$ sudo docker images -a -q #find the image id

$ sudo docker rmi <image id>

As we can see, running Flask in a container environment provides us with even more flexibility and the option to deploy our own API abstraction in production. Containers, of course, offer their own complexity and add more management tasks so we need to weigh up the benefits and overhead when it comes to our deployment methods.

Additional Resources:
Mastering Python Networking, Third Edition
Automation & Programmability Training

Related Posts

Close Bitnami banner
Bitnami