Docker is an open-source tool designed to make it easier to create, deploy, and run applications by using containers. A container is a software package that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another.
Flask is a popular Python web framework. It is classified as a microframework because it does not require particular tools or libraries. Compared to other frameworks it is lightweight and highly structured.
In this tutorial, we will explain how to deploy Flask application with Docker on Debian 10 server.
Prerequisites
- A server running Debian 10.
- A root password is configured on your server.
Getting Started
Before starting, it is a good idea to update your system's package to the latest version. You can update all the packages with the following command:
apt-get update -y
apt-get upgrade -y
Once all the packages are updated, restart your system to apply the changes.
Install Required Dependencies
Next, you will need to install the Nginx web server and other dependencies in your system. You can install all of them using the following command:
apt-get install nginx apt-transport-https ca-certificates curl gnupg2 software-properties-common curl -y
Once all the packages are installed, you can proceed to the next step.
Install Docker
By default, the latest version of Docker is not available in the Debian 10 repository. So it is a good idea to install it from the Docker official repository.
First, download and add the GPG key with the following command:
wget https://download.docker.com/linux/debian/gpg apt-key add gpg
Next, add the Docker repository with the following command:
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian buster stable"
Next, update the repository and install the Docker with the following command:
apt-get update -y
apt-get install docker-ce -y
Once the installation has been completed successfully, verify the status of the Docker with the following command:
systemctl status docker
You should get the following output:
? docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2020-04-19 06:26:25 UTC; 1min 8s ago Docs: https://docs.docker.com Main PID: 8883 (dockerd) Tasks: 10 Memory: 46.6M CGroup: /system.slice/docker.service ??8883 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock Apr 19 06:26:24 debian10 dockerd[8883]: time="2020-04-19T06:26:24.413828757Z" level=warning msg="Your kernel does not support swap memory limit Apr 19 06:26:24 debian10 dockerd[8883]: time="2020-04-19T06:26:24.413876690Z" level=warning msg="Your kernel does not support cgroup rt period" Apr 19 06:26:24 debian10 dockerd[8883]: time="2020-04-19T06:26:24.413889604Z" level=warning msg="Your kernel does not support cgroup rt runtime Apr 19 06:26:24 debian10 dockerd[8883]: time="2020-04-19T06:26:24.414115814Z" level=info msg="Loading containers: start." Apr 19 06:26:24 debian10 dockerd[8883]: time="2020-04-19T06:26:24.788332166Z" level=info msg="Default bridge (docker0) is assigned with an IP a Apr 19 06:26:24 debian10 dockerd[8883]: time="2020-04-19T06:26:24.972022325Z" level=info msg="Loading containers: done." Apr 19 06:26:25 debian10 dockerd[8883]: time="2020-04-19T06:26:25.010940205Z" level=info msg="Docker daemon" commit=afacb8b7f0 graphdriver(s)=o Apr 19 06:26:25 debian10 dockerd[8883]: time="2020-04-19T06:26:25.011145541Z" level=info msg="Daemon has completed initialization" Apr 19 06:26:25 debian10 systemd[1]: Started Docker Application Container Engine. Apr 19 06:26:25 debian10 dockerd[8883]: time="2020-04-19T06:26:25.074603639Z" level=info msg="API listen on /var/run/docker.sock"
At this point, Docker is installed and running. You can now proceed to the next step.
Setup Flask Directory Structure
Next, you will need to create a directory structure to hold your Flask application.
Let's create a directory named flask inside the /var/www/ directory:
mkdir -p /var/www/flask
Next, change the directory to a flask and create the directory structure for flask:
cd /var/www/flask
mkdir -p app/static
mkdir -p app/templates
The static directory is used to store images, CSS, and JavaScript files while the templates directory is used to store the HTML templates for your project.
Next, you will need to create an __init__.py file inside the app directory:
nano app/__init__.py
Add the following contents to create a Flask instance and import the logic from the views.py file:
from flask import Flask app = Flask(__name__) from app import views
Save and close the file then create the views.py file in your app directory.
nano app/views.py
Add the following lines
from app import app @app.route('/') def home(): return "hello world!"
Save and close the file then create the uwsgi.ini file with the following command:
nano uwsgi.ini
This file will contain the uWSGI configurations for our application as shown below:
[uwsgi] module = main callable = app master = true
Save and close the file when you are finished. uWSGI is a deployment option for Nginx that is both a protocol and an application server.
Next, you will need to create the main.py file to imports the Flask instance named app from the application package. You can create it with the following command:
nano main.py
Add the following line:
from app import app
Save and close the file when you are finished. Next, create a requirements.txt file for specifying the dependencies that the pip package manager will install to your Docker deployment:
nano requirements.txt
Add the following line that matches with the latest version of Flask:
Flask==1.1.2
Save and close the file when you are finished.
At this point, your Flask application has been configured successfully. You can now proceed to the next step.
Configure Docker to Deploy Flask
Next, you will need to create a Dockerfile to build and deploy a flask application.
First, create a Dockerfile with the following command:
cd /var/www/flask
nano Dockerfile
Add the following lines:
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
Save and close the file when you are finished. Next, create a start.sh script to build an image from the Dockerfile and create a container from the resulting Docker image.
nano start.sh
Add the following line:
#!/bin/bash app="docker.test" docker build -t ${app} . docker run -d -p 56733:80 \ --name=${app} \ -v $PWD:/app ${app}
Save and close the file when you are finished.
Note : Make sure the port 56733 is free and usable.
Finally, run the script using the following command:
bash start.sh
This will create the Docker image and build a container from the resulting image as shown below:
Sending build context to Docker daemon 9.728kB Step 1/6 : FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7 python3.6-alpine3.7: Pulling from tiangolo/uwsgi-nginx-flask 48ecbb6b270e: Pull complete 692f29ee68fa: Pull complete f75fc7ac1098: Pull complete c30e40bb471c: Pull complete Successfully built f5de17e1ce82 Successfully tagged docker.test:latest 22cd2bd23c9190cf2900fa1d7c55e4765a266e68c74dc1e6858872e9ebe7bdcd
You can now list the running containers with the following command:
docker ps
You should get the following output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 22cd2bd23c91 docker.test "/entrypoint.sh /sta…" About a minute ago Up About a minute 443/tcp, 0.0.0.0:56733->80/tcp docker.test
You can also verify the Docker container by visiting the URL http://your-server-ip:56733. You should see the following screen:
Deploy Template Files
You can also deploy template files to serve static and dynamic content. You can create a home page template for your application with the following command:
nano app/templates/home.html
Add the following codes:
<!doctype html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Welcome Flask</title> </head> <body> <h1>Home Page</h1> <p>This is the home page of our flask application.</p> </body> </html>
Save and close the file when you are finished. Next, you will need to modify the views.py file to serve the newly created file:
nano app/views.py
Update the file as shown below:
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')
Save and close the file. Then, you will need to restart the Docker containers to apply the changes.
You can restart the Docker container named docker.test with the following command:
docker stop docker.test
docker start docker.test
Now, open your web browser and type the URL http://your-server-ip:56733/template. You should see your newly created template in the following screen:
Conclusion
Congratulations! you have successfully deployed a Flask application with Docker on Debian 10 server. You can now replicate the application across different servers with minimal reconfiguration. Feel free to ask me if you have any questions.