How To Build and Deploy a Flask Application Using Docker on Ubuntu 18.04

Introduction

Administrators apply Docker to replicate, deploy, and manage applications using containers. The latter can be explained as a package that stores dependencies required by an application to run at the level of an operating system. For better understanding, each application that is deployed using Docker is settled in its own environment. Moreover, its requirements are handled on a separate basis.

Flask is a framework that does not require specific tools or plug-ins to run and is built on Python. It is highly structured, yet flexible and lightweight; moreover, it does not require specific plug-ins or tools to run.

Therefore, if you deploy a Flask application with Docker, you will be able to replicate the application across different servers with minimal reconfiguration.

This guide will show you how to create, deploy, and update a Flask application with Docker. 

Step One — How to Set Up the Flask Application


First of all, you need to create a directory structure to hold the Flask application. Thus, we will create a directory called TestApp in /var/www. Note that the command can be modiefed to name differently.

$ sudo mkdir /var/www/TestApp

Then switch to TestApp directory you have just created:

$ cd /var/www/TestApp

After that, make the base folder structure for the Flask application:

$ sudo mkdir -p app/static app/templates 

Using the -p flag means that mkdir will create a directory and needed parent directories. In the process of making the templates and static  directories, mkdir will create the app parent directory.

All files related to the Flask application like blueprints, which support common patterns within an application or across multiple applications and create application components, and views, which are the code written to respond to requests to your application, will be contained in the app directory.

The static directory stores CSS, images, and JavaScript files. The templates directory is the place to keep the HTML templates for the project.

Since the base folder structure is ready, create the files that are needed to run the Flask application. The first one to be created is an __init__.py file inside the app directory. It informs the Python interpreter that the app directory should be treated as a package, which it actually is.

In order to create the file, run the command below:

$ sudo nano app/__init__.py

In Python, you can group modules into logical hierarchies and namespaces due to Python packages. Based on this approach, the code can broken down into manageable individual blocks that perform specific functions.

Add the code provided below to the __init__.py file. This will create a Flask instance and import the logic from the views.py file. You will create the views.py file  after saving the one you are now modifying:

/var/www/TestApp/app/__init__.py
from flask import Flask
app = Flask(__name__)
from app import views

After that, save and close the file.

Having created the __init__.py file created, proceed to creating the views.py file in your app directory. It will represent most of your application logic.

$ sudo nano app/views.py

The next step is to add the code provided below to views.py file. The code will return the hello world! string to people visiting your web page:

/var/www/TestApp/app/views.py
from app import app

@app.route('/')
def home():
   return "hello world!"

The @app.route line above the function is called a decorator, which serves to modify the function following it. As to what concerns our example, it tells Flask which URL will trigger the home() function. The text hello world  that is returned by the home function will be shown to the user on the browser.

Having created the views.py file, proceed to the uwsgi.ini file. The uWSGI configurations for our application will be contained in this file. uWSGI is a deployment option for Nginx. The latter is both an application server and a protocol, which can serve FastCGI, uWSGI, and HTTP protocols.

Run the command below to create this file:

$ sudo nano uwsgi.ini

 To configure the uWSGI server,add the content provided below to your file:

/var/www/TestApp/uwsgi.ini
[uwsgi]
module = main
callable = app
master = true

This code is here to define the module that will serve Flask application. In our case, it is the main.py file, which is referenced as main. uWSGI is instructed by the callable option to use the app instance, which is exported by the main application. Due to master option, your application keeps running;  thus little downtime even in case of reloading the entire application.

The next step is to create the main.py file. This file is the application entry point. It tells uWSGI how to interact with the application.

$ sudo nano main.py

Having created the file, insert the code below. This way, you will import the Flask instance called app from the package of the application created previously.

/var/www/TestApp/main.py
from app import app

Lastly, you need to create a requirements.txt file. It will specify the dependencies installed by the pip package manager to your Docker deployment:

$ sudo nano requirements.txt

The line below will add Flask as a dependency, specifying the Flask version to be installed, which is 1.0.2 at the moment of writing. The available updates can be downloaded on the official website.

/var/www/TestApp/requirements.txt
Flask==1.0.2

Having finished, save and close the file. With Flask application being successfully installed, you can proceed to Docker set up.

Step Two —  Docker Set Up

To create your Docker deployment, you need to create two files, namely start.sh and Dockerfile. The latter is a text document containing the commands that serve to assemble the image while start.sh file is a shell script. It serves to create a container from the Dockerfile and build an image.

The first step is to create the Dockerfile.

$ sudo nano Dockerfile

Then, add the configuration you want to the Dockerfile (namely what extra requirements to be included and how the image will be built).

/var/www/TestApp/Dockerfile
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7
RUN apk --update add bash nano
ENV STATIC_URL /static
ENV STATIC_PATH /var/www/app/static
COPY ./requirements.txt /var/www/requirements.txt
RUN pip install -r /var/www/requirements.txt

In our tutorial, the an existing image, tiangolo/uwsgi-nginx-flask will be a building brick for Docker image. It is taken from  DockerHub, and can be considered a great choice because it supports various OS images and Python versions.

The parent image used to run the application and install the bash command processor, and the nano text editor is specified in the first two lines. Also, it installs the git client for pulling and pushing to version control hosting services, namely GitLab, GitHub, and Bitbucket. Note the environment variable specific to this Docker image, ENV STATIC_URL /static. It defines the static folder that serves all assets such as CSS files, images, and JavaScript files.

The last two lines of the command are here to copy the requirements.txt file into the container. It is done to execute the container and parse the requirements.txt file in order to install the dependencies that were specified earlier.

Add your configuration and save and close the file.

Having modified your Dockerfile, you can proceed to writing your start.sh script, which will build the Docker container. However, first of all, ensure that you have an open port. Run the following command to check it:

$ sudo nc localhost 56733 < /dev/null; echo $?

If the command returns 1 as an output, the port is free and usable. If not, choose a different port for start.sh file.

Having found an open port, create the start.sh script, which is a shell script. It will build an image from the Dockerfile and create a container from the resulting Docker image. 

$ sudo nano start.sh

Insert your configuration to the new file:

/var/www/TestApp/start.sh
#!/bin/bash
app="docker.test"
docker build -t ${app} .
docker run -d -p 56733:80 \
  --name=${app} \
  -v $PWD:/app ${app}

The first line specifies that it is a bash file and will be executed as commands. The line is called a shebang. The second line stands for the name of the container and image. It also saves as a variable named app. The following line tells Docker to build an image from your Dockerfile, which is located in the current directory. Thus, an image called docker.test is created in this example.

 A new container docker.test, which is exposed at port 56733, is created by the last three lines. Finally, the present directory gets linked to the /var/www directory of the container.

The -d flag is used to start a container asa background process or in daemon mode. The -p flag is included to bind a particular port on the Docker container to the server port. In our case, we bind port 80 on the Docker container to port 56733. The -v flag determines a Docker volume to mount on the container. In our example, the entire project directory is mounted to the /var/www folder on the Docker container.

You need to execute the start.sh script. This will create the Docker image and build a container from the image resulting from the command:

$ sudo bash start.sh

When the script stops running, the following command should be executed to list all running containers:

$ sudo docker ps

The resulting output will show the containers:

Output
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                            NAMES
58b05508f4dd        docker.test         "/entrypoint.sh /sta…"   12 seconds ago      Up 3 seconds       443/tcp, 0.0.0.0:56733->80/tcp   docker.test

You will see that the docker.test container is running. Then, go to the IP address at the specified port in your browser: http://ip-address:56733

A page similar to the one below will open:

the home page

 

Finally,  your Flask application has been successfully deployed on Docker. In the next section you will learn how to use templates to display content to users.

Step Three — How to serving Template Files

 Those files that display dynamic and static content to users visiting your application are called templates. In this section of our tutorial, we will show you how to create a HTML template for the home page for the application.

First of all, create a home.html file in the directory app/templates:

$ sudo nano app/templates/home.html

Add the code provided below. It will create an HTML5 page with a title and some text.

/var/www/TestApp/app/templates/home.html
<!doctype html>

<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Welcome home</title>
  </head>

  <body>
    <h1>Home Page</h1>
    <p>This is the home page of our application.</p>
  </body>
</html>

After adding the template, save and close the file.

The next step is to modify the app/views.py file to make it the file that was just created:

$ sudo nano app/views.py

Import the render_template method from FlaskFirst by adding the following line at the beginning of your file. This way you will parse an HTML file to render a web page to the user.

/var/www/TestApp/app/views.py
from flask import render_template
...

In the end of the file, a new route should be added for rendering the template file. Due to this code, users are served the contents of the home.html file every time they visit the /template route on your application.

/var/www/TestApp/app/views.py
...

@app.route('/template')
def template():
    return render_template('home.html')

The app/views.py file you have updated should look as follows:

/var/www/TestApp/app/views.py
from flask import render_template
from app import app

@app.route('/')
def home():
    return "Hello world!"

@app.route('/template')
def template():
    return render_template('home.html')

When finished, save and close the file.

To take these changes into effect, the Docker containers need to be stopped and restarted. The command below should be executed to rebuild the container:

$ sudo docker stop docker.test && sudo docker start docker.test

To see the new template being served, visit your application at http://your-ip-address:56733/template.

homepage

Docker template file has been created to serve visitors on your application. In the next section, we will show you how the changes made to the application can take effect without restarting the Docker container.

Step Four — How to Update the Application

If you want to update the Docker container, install new requirements, or make some HTML and logic changes in your application, you will configure touch-reload to introduce them without the need to restart the Docker container.

Python autoreloading watches the file system for changes. Also,  when a change is detected, it refreshes the application. Moreover, autoreloading is discouraged due to its resource intensive nature. We will show you how to use touch-reload to watch for changes to a particular file, as well as reload when it is replaced or updated.

First of all, open your uwsgi.ini file:

$ sudo nano uwsgi.ini

After that, add the last line to the end of the file:

/var/www/TestApp/uwsgi.ini
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini

It specifies a file, which will be modified to trigger the reload of the entire application. Having finished, save and close the file.

To check how it works, implement a small modification to your application. Open your app/views.py file:

$ sudo nano app/views.py

Then replace the string that is returned by the home function:

/var/www/TestApp/app/views.py
from flask import render_template
from app import app

@app.route('/')
def home():
    return "<b>There has been a change</b>"

@app.route('/template')
def template():
    return render_template('home.html')

Having made the change, save and close the file.

After that, open your application’s homepage at http://ip-address:56733. The changes made will not be reflected. It means the condition for reload is a change to the uwsgi.ini file. Use touch to activate the condition and reload the application:

$ sudo touch uwsgi.ini

After that, reload the homepage of your application in your browser. This time, the changes have been incorporated:

Homepage Updated

Congratulations, you have set up a touch-reload condition to update your application after making changes.

  • NGINX, DOCKER, UBUNTU 18.04
  • 0 Users Found This Useful
Was this answer helpful?

Related Articles

How To Install Linux, Apache, MySQL, PHP (LAMP) stack on Ubuntu 18.04

Introduction ‘LAMP” is a stack of open-source software. Typically, it is installed together in...

How To Install Linux, Nginx, MySQL, PHP (LEMP stack) on Ubuntu 18.04

Introduction LEMP is a pack of software. It is generally used to serve dynamic web applications...

How To Install Nginx on CentOS 7

What is Nginx Nginx is server software that is characterized by high performance, flexibility,...

How To Install Node.js on Debian 10

Introduction Node.js a Javascript platform that allows easy creation of networked applications...

How To Install Node.js on Ubuntu 18.04

Introduction Node.js is a JavaScript platform that is used to allow users to build network...