Damilare Jolayemi Damilare is an enthusiastic problem-solver who enjoys building whatever works on the computer. He has a knack for slapping his keyboards till something works. When he's not talking to his laptop, you'll find him hopping on road trips and sharing moments with his friends, or watching shows on Netflix.

Build and deploy a Flask app using Docker

6 min read 1816

Build and deploy a Flask app using Docker

If you’ve ever built a web application with Python, chances are that you used a framework to achieve this, one of which could be Flask. Flask is an open-source, beginner-friendly web framework built on the Python programming language. Flask is suitable when you want to develop an application with a light codebase rapidly.

Docker is an open-source tool that enables you to containerize your applications. It aids in building, testing, deploying, and managing your applications within an isolated environment, and we’ll use it to do everything except test in this article.

Prerequisites

  • Python ≥ v3.8 installed on your machine
  • Working knowledge of building applications using Flask and Python
  • At least 4GB of RAM on your machine to enable compatibility with Docker
  • Intermediate level knowledge of CLIs
  • Any suitable IDE or text editor

Creating the Flask app

Let’s proceed to create a simple Flask application that renders a message on the browser. Create a folder with the name flask_docker to contain your application.

mkdir flask_docker

Next, cd into the flask_docker directory and run the below command to install Flask.

pip install Flask

After successfully installing Flask, the next step is to create a Python file that receives and responds to requests in our application. Create a view.py file that will contain the Python code snippet below:

from flask import Flask, render_template
import os

app = Flask(__name__)


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


if __name__ == "__main__":
    port = int(os.environ.get('PORT', 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

In the code snippet above, the @app.route annotation serves to direct the request to a mapped URL. In this case, the provided URL is /, which represents the homepage.

This annotation also has a method parameter that takes a list of HTTP methods to specify the permitted method for the provided URL. By default (as illustrated), the GET method is the only permitted HTTP method.

Here is an example of how you can specify that your route should permit both GET and POST HTTP methods:

@app.route('/', methods=['POST', 'GET'])

The home() function bound to the URL provided in the @app.route annotation will run when you send a GET request to this route. The function returns a call to render_template that in turn renders the content of the index.html file, which we will create in the next section.

port = int(os.environ.get('PORT', 5000))
app.run(debug=True, host='0.0.0.0', port=port)

The above portion of the view.py file is required when we deploy this application to Heroku, which we will demonstrate in the subsequent section. Not including this will cause your application to crash on Heroku.

The HTML template

The next step is to create the index.html file and provide the content we want to render on the browser when you invoke the home() function in the view.py file.

Within the root directory, create a templates directory, then create the index.html file. Add the below code snippet to the HTML file:

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask Docker</title>
</head>
<body>
    <h1>This is a Flask App containerised with Docker</h1>
</body>
</html>

Writing Python requirement files with Docker

If you’ve ever explored any published Python project, you may have noticed a requirement.txt file. This file contains the list of packages and dependencies that you need to run your project and their respective versions.



Within the root directory, run the below command in the terminal:

pip freeze > requirements.txt

This will generate the names of the packages and their respective versions that you have installed, as well as some other inbuilt dependencies that run your Flask application. Then, it stores them in a .txt file named requirements.

Depending on the complexity of your project and the packages you have installed, the content of this file will vary from project to project.

You can also install the packages contained in this file in another project by copying the requirements.txt file to your desired project and running the following command:

pip install -r requirements.txt

The advantage of doing this is that you don’t have to run the pip install command for each package repeatedly.

Your requirements.txt file should contain at least the following content:

click==8.0.3
colorama==0.4.4
Flask==2.0.2
itsdangerous==2.0.1
Jinja2==3.0.3
MarkupSafe==2.0.1
Werkzeug==2.0.2
gunicorn==20.1.0

The version numbers generated in the requirements file may be different from what is written here because, again, this depends on the type of application you’re building and the versions of the packages you have installed when building your app.

A nice thing about containerizing with Docker is that you get to package your application with all of the runtime dependencies that are required to make it self-sufficient. Therefore, your application runs without you needing to worry about incompatibilities with its host environment.

You can test that the application works before you proceed to containerize it. Run this command on your terminal within the root directory to perform this test:

python view.py

Setting up the Dockerfile

If you don’t have Docker installed on your machine, you can follow these instructions to get started.

Create a file and name it Dockerfile. Add the following code snippet to the file:

# start by pulling the python image
FROM python:3.8-alpine

# copy the requirements file into the image
COPY ./requirements.txt /app/requirements.txt

# switch working directory
WORKDIR /app

# install the dependencies and packages in the requirements file
RUN pip install -r requirements.txt

# copy every content from the local file to the image
COPY . /app

# configure the container to run in an executed manner
ENTRYPOINT [ "python" ]

CMD ["view.py" ]

Let’s go over the instructions in this Dockerfile:

  • FROM python:3.8-alpine: Since Docker allows us to inherit existing images, we install a Python image and install it in our Docker image. Alpine is a lightweight Linux distro that will serve as the OS on which we install our image
  • COPY ./requirements.txt /app/requirements.txt: Here, we copy the requirements file and its content (the generated packages and dependencies) into the app folder of the image
  • WORKDIR /app: We proceed to set the working directory as /app, which will be the root directory of our application in the container
  • RUN pip install -r requirements.txt: This command installs all the dependencies defined in the requirements.txt file into our application within the container
  • COPY . /app: This copies every other file and its respective contents into the app folder that is the root directory of our application within the container
  • ENTRYPOINT [ "python" ]: This is the command that runs the application in the container
  • CMD [ "view.py" ]: Finally, this appends the list of parameters to the EntryPoint parameter to perform the command that runs the application. This is similar to how you would run the Python app on your terminal using the python view.py command

Build the Docker image

Let’s proceed to build the image with the command below:

docker image build -t flask_docker .

Run the container

After successfully building the image, the next step is to run an instance of the image. Here is how to perform this:

docker run -p 5000:5000 -d flask_docker

This command runs the container and its embedded application, each on port 5000 using a port-binding approach. The first 5000 is the port that we allocate to the container on our machine. The second 5000 is the port where the application will run on the container.

Here is the output of our application when we send a request to localhost:5000 on our browser:
Our app's output when run through port 5000

Deploying our Flask app to Docker Hub

Docker Registry, also known as Docker Hub, is a community of repositories where Docker users create, test, and manage containers. If you’ve worked with GitHub, this section will be very familiar to you.

Follow the next sequence of steps to deploy the image we built to Docker Hub so that you can access it anywhere.

Step 1: Create a repository on the Docker Hub

If you don’t already have an account, proceed to sign up on Docker Hub. After successfully creating an account, log in and click the Repositories tab on the navbar.
The Repositories tab in the Docker Hub navbar

Follow the steps on the page and create a new repository named flask-docker.

Step 2: Log in on your local machine

The next step is to log in on your local machine to create a connection between your machine and Docker Hub.

docker login

Step 3: Rename the Docker image

When pushing an image to Docker Hub, there is a standard format that your image name has to follow. This format is specified as:

<your-docker-hub-username>/<repository-name>.

Here is the command for renaming the image:

docker tag flask_docker <your-docker-hub-username>/flask-docker

Step 4: Push to Docker Hub

The final step is to push the image to Docker Hub by using the following command:

docker push <your-docker-hub-username>/flask-docker

This is what you should see upon successful deployment:
The results page upon successful deployment to Docker hub

Deploying our app to Heroku

Heroku is a cloud platform where developers can build and run applications in the cloud. If you don’t already have an account with Heroku, you can create one here.

Let’s proceed to deploy our containerized application to Heroku with the following steps:

Step 1: Log in to Heroku

heroku login

If you’ve not previously logged in to your Docker Hub account, you’ll be required to do this to proceed.

docker login --username=<your-username> --password=<your-password>

Step 2: Create Heroku app

heroku create <app-name>

Step 3: Create a Procfile

A Procfile contains commands that your application runs on Heroku when starting up.

Create a file and name it Procfile without an extension. Then add the following to the file:

web: gunicorn app:app

Step 4: Push the app to Heroku

heroku container:push web --app <app-name>

Step 5: Release the image

heroku container:release web --app <app-name>

You can now proceed to view your application on Heroku with the URL:

https://<app-name>.herokuapp.com/

The final app as deployed on Heroku

Conclusion

In this tutorial, we built a simple Flask app and containerized it with Docker. We also deployed the created and pushed the image to Docker Hub as well as the containerized application to Heroku. Just as demonstrated with a Flask application, you can also explore how to containerize other applications here. This project is available on my GitHub repo for more insights.

For more information on integrating Docker with your application, the Docker documentation is a helpful resource you can begin with.

If you’re also interested in growing your skill in the Python Flask framework, here is the documentation for the Flask framework that can help guide you through.

Cheers!

Get setup with LogRocket's modern error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    LogRocket.init('app/id');
    Add to your HTML:

    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • ngrx middleware
    • Vuex plugin
Get started now
Damilare Jolayemi Damilare is an enthusiastic problem-solver who enjoys building whatever works on the computer. He has a knack for slapping his keyboards till something works. When he's not talking to his laptop, you'll find him hopping on road trips and sharing moments with his friends, or watching shows on Netflix.

Leave a Reply