Flask and Docker: An Intro for Containerization
What is docker?
Docker is a platform that allows us to develop, ship, and run our program inside an isolated unit called a container.
In modern software development, docker takes a big role, especially in a microservices architecture.
Docker simplifies our deployment. Traditionally, we would put our code base in the server, install the application dependencies, and set the environment. Only after that, we could run our application.
Sometimes, the app crashes because there is a difference between the development and production environment, and we just realize it when the apps are going to be in production.
With docker, the deployment would be much easier. We wrap our application into an image. Then ship it to our server and run it inside a container.
Docker ensures development consistency. Since the container is isolated, we could create a production-like environment with the same dependencies and configurations.
Because the app is wrapped in images, we could easily ship our app to several places and scale the app into several nodes. This is why docker important is for microservices, it provides good ways of system scaling.
Why should we learn it as a developer?
Docker has been used by a lot of companies. If you look into vacancies now, they put docker and microservices on the requirement list.
Most of the senior-level programmers and tech leads vacancies put docker or container tech as required things.
Docker is no longer something you are good to know, you should know it, you should learn it.
I know, learning is not easy. But as a developer, we need to update our skills to stay in line with technological developments.
It's hard, but it's worth it.
Okay, forget about the wise old man above. Let's just code instead.
Set up docker for Flask application.
In this tutorial, I will show you how to dockerize a Flask application.
Prerequisite
Before we start the tutorial, you need to install a couple of things.
Docker
You need to install docker first. After the installation, if you are using windows, make sure you put the docker path inside the environment variable.
PgAdmin.
In this tutorial, we also going to work with database containers using PostgreSQL. PgAdmin will be used to manage and check our database container.
How to Dockerize Flask Application.
Let's create a simple flask application with docker configuration.
Create a project folder.
Create 3 files inside flask_postgresql folders.
Let me explain it a bit.
- main.py is our flask application.
- Dockerfile is a configuration file for our docker images.
- .dockerignore is an ignore file, we could ignore several files that we don't want to include in our docker images.
I’ll explain about the docker images later.
Create a virtual env and install Flask.
Run the following command in your terminal or console.
python -m venv env
.\env\Scripts\activate
pip install flask
Freeze the requirements into requirements.txt files.
Run the following command.
pip freeze > requirements.txt
It will list our app's dependencies in requirements.txt files.
This is what our project looks like now.
Create our flask application.
Write the following code inside main.py.
To create docker images, we need to create a Dockerfile that contains our image configuration.
Now, let's write our Dockerfile.
Write the .dockerignore files.
Run the docker client.
I use windows, so I will start my windows docker desktop.
Build the docker images.
To create the docker images, run the following command.
docker build . -t flask_postgresql_image:latest
To check whether our image is created or not, use this command to show the images list.
docker images
You will see, there is an image named flask_postgresql_image.
The image is our program, but it's not running yet. To run the program, we need to create a container to execute the image, then we need to run the containers.
Create the Flask application container.
Run this command:
docker container create --name flask_postgresql_container --publish 5000:5000 flask_postgresql_image:latest
It will return an id of created containers.
Start the container.
docker container start flask_postgresql_container
After starting the container, the apps must be running now. Let's check the API using web browsers.
As you can see, it works.
But, what just happened?
Let me explain it.
Docker builds our apps into something we called images. To run our program, we need to put our image into a container and run it.
When we execute this command:
docker build . -t flask_postgresql_image:latest'
First, docker will read the .dockerignore files, so it knows that you don't want to process some files or folders.
Then it will read the Dockerfile configuration.
After loading the Dockerfile configuration, docker will execute the FROM command.
FROM python:3.11.1-slim-bullseye
FROM command specify what’s the base image we want to use for our application.
Before we could use Flask, we need python installed. So the first thing that the docker installed is Python.
Next to the base image, there are the image tags. It means, what version of python we want to use. There are a lot of versions of python images, you can see the available tags in the docker hub documentation.
After installing python, it will set our working directory to ‘app’.
WORKDIR /app
If the app folder does not exist, docker will automatically create a new folder named app.
Copy all files from our project into the working directory.
COPY . .
Install the requirements.
RUN pip3 install -r requirements.txt
Set ENV for Python.
ENV PYTHONUNBUFFERED=1
What is PYTHONUNBUFFERED mean?
It allows docker to log print statement and show it in the command line.
If PYTHONUNBUFFERED is set to False, it will not record the print statements into docker logs. For now, just let it be like this.
Expose port.
EXPOSE 5000
It tells people that this app uses port 5000 as its default port, so they need to open port 5000 to access it.
Run the flask server.
CMD ["python3", "main.py"]
This command will not be running when the image is created, it will run when the container is started.
After finishing all commands in the Dockerfile, the Flask app image is created.
Remember, when we run the docker build command, we specified a tag (-t) for the images. It will label the image, so we could easily identify them.
After creating the images, we need to create a container to run it. That's when we run the following command:
docker container create --name flask_postgresql_container --publish 5000:5000 flask_postgresql_image:latest
- - name. It is the container name.
- - publish. It is the port we want to open, the first one is our local port, and the next one is the container port. If we want to access our application, we need to connect our local port with the container port.
flask_postgresql_image: latest. It is the image we gonna use to create the container.
After creating the container, we could start the container using the following command.
docker container start flask_postgresql_container
It will run our flask application.
If we want to stop the program, we could stop the container using the following command.
docker container stop flask_postgresql_container
Okay. That's how we dockerize the flask application.
Oftentimes, we also need to deal with database containerization. Since the app needs a place to store the data.
Let's create dockerized PostgreSQL.
Dockerize Postgresql.
Create a new folder named postgresql_db.
Create a Dockerfile inside the project.
For PostgreSQL, we need to specify some environment variables, environment variables will be used to create a default user and the default database.
Build images.
Run the following command.
docker build . -t flask_postgresql_db_image
Perfect. The database images are already created.
When we work with database containers, there is something we need to be aware of.
Docker stores our data inside the container. If the container is removed, the data will no longer exist.
Of course, we don't want something like this to happen, the data should persist no matter whether the container is alive or removed.
That's why we should create something called volume. Volume is storage managed by docker that is separated from the container.
If the container is removed, the volume remains exists.
Create a volume.
Run the following command.
docker volume create flask_postgresql_volume
To show the list of existing volumes, use this command.
docker volume list
As you can see, there is a volume named flask_postgresql_volume created.
Now let's create the database container.
This time, we need to specify the volume we use for the container in the create container command.
To use volume, add the following parameter to the container creation command.
--mount type=volume,source=flask_postgresql_volume,destination=/var/lib/postgresql/data
‘source’ is the volume we have created.
‘destination’ is a folder destination inside the container directory. We set the destination to /var/lib/postgresql/data.
Docker will copy the container data from the volume into the default PostgreSQL data directory (var/lib/postgresql/data).
Whenever we add new data or perform data updates, it will be stored in our volume.
Create the database container.
docker container create --name flask_postgresql_db_container --publish 5433:5432 --mount type=volume,source=flask_postgresql_volume,destination=/var/lib/postgresql/data flask_postgresql_db_image:latest
Start the database container.
docker container start flask_postgresql_db_container
Make sure all the containers are running.
To show the list of containers, use the following command.
docker ps -a
Now 2 containers are running.
Check whether the database is work or fails.
To prove that the database is working, let's connect it with the PgAdmin application.
When we create the database container, we already specify that we want to forward port 5432 from the docker container to port 5433 in our local machine. So now we could use port 5433 to connect with our PostgreSQL database.
Create a connection in PgAdmin.
Fill in the field based on the database environment setting.
Check if the database is connected.
Perfect. It's connected.
Let’s try to interact with some data. Run the following queries to create a new table.
CREATE TABLE product (
id int,
title varchar(200),
description varchar(500),
price int,
discountPercentage numeric(2,0),
rating numeric(1,0),
stock int,
brand varchar(100),
category varchar(100),
thumnail varchar(200),
images jsonb
)
Insert some data.
INSERT INTO public.product(
id, title, description, price,
discountpercentage, rating, stock,
brand, category, thumnail, images
)
VALUES (
11, 'perfume Oil', 'Mega Discount, Impression of A...', 13,
8.4, 4.26, 65, 'Impression of Acqua Di Gio', 'fragrances',
'https://i.dummyjson.com/data/products/11/thumbnail.jpg',
'[
"https://i.dummyjson.com/data/products/11/1.jpg",
"https://i.dummyjson.com/data/products/11/2.jpg",
"https://i.dummyjson.com/data/products/11/3.jpg",
"https://i.dummyjson.com/data/products/11/thumbnail.jpg"]'
);
Now let's run the select query.
select * from product
You will receive the following results.
Now we are sure that the database container is already working.
Now let's make a bit changes to our flask application. Previously, we got the product data from our local variables, now let's retrieve the data from the database.
Since the docker container is isolated, it can’t communicate with others. The Flask application cant connect to the PostgreSQL databases. If we want to connect them, we need to create a network and each of those containers should be connected to the network.
Create the network.
Run the following command:
docker network create --driver bridge flask_postgresql_network
Connect the database container to the network.
docker network connect flask_postgresql_network flask_postgresql_db_container
The database container should be connected to the network now.
Next, we need to update the Flask application. We need to set the database environment and change the app.
Update the Dockerfile inside the flask application.
Add the following line.
ENV DB=flask_postgresql
ENV DB_USER=root
ENV DB_PASSWORD=root
ENV HOST=flask_postgresql_db_container
ENV PORT=5432
Add the following line to requirements.txt files.
psycopg2-binary==2.9.5
Update the main.py files.
Here we run a query to retrieve product data from the database.
To update the apps we need to rebuild the images and recreate the containers.
Let's do it.
Stop and remove the existing Flask apps container.
docker container stop flask_postgresql_container
docker container rm flask_postgresql_container
Remove the existing flask images.
docker rmi flask_postgresql_image
Recreate the images.
docker build . -t flask_postgresql_image:latest
Recreate the container.
docker container create --name flask_postgresql_container --publish 5000:5000 --network flask_postgresql_network flask_postgresql_image:latest
Start the container.
docker container start flask_postgresql_container
Let's check the API. You should receive the following response right now.
Great.
Now our Flask application is connected to PostgreSQL databases.
In this tutorial, we have learned a lot of docker fundamental concepts including images, containers, volume, and network.
I’m sure you could dockerize your flask application now.
Also along with this tutorial, I show you that setting up a docker container sometimes could take time.
We need to rewrite several commands whenever we update the images or manage our docker container.
On the small number of apps, it's not gonna be an issue, but on a large scale, it won't be practical.
In the next tutorial, I will show you how to use docker-compose to simplify the container's creation.
See you in the next articles. Thanks for reading.
Source code: Here….…