Flask and Docker: Simplify Your Container Creation with Docker Compose
What is docker-compose, and why should we use it?
With docker, we could easily develop, ship, and deploy our app using docker command.
But when we work with a lot of services together, managing containers using the docker command is no longer practical.
It's hard to remember all the configurations we used for each container. That’s why we need docker-compose.
Docker-compose keeps our container configuration named “docker-compose.yaml”. Not only keep it, but we could also use the file configuration to create and manage the containers.
Docker composes structure.
This is the basic structure of docker-compose files.
version: 'version'
services:
sample_service:
...
volumes:
sample_volume:
...
networks:
sample_network:
...
Version is what version of the docker-compose file we used. The current version when this article was created is 3.8.
Service is the container's configuration. Here we describe all of our container’s configurations including the container names, the image we use, the environment, etc.
Volumes, we could declare our volumes here.
Networks containing the network configuration.
When we execute the docker-compose file, all the containers, volumes, and networks will be configured and created.
Simple Examples.
Let's create a docker-compose file to manage nginx server containers.
Create a file named “docker-compose.yaml” and write the following codes.
version: '3.8'
services:
nginx_server:
image: nginx:latest
container_name: nginx_server
ports:
- protocol: tcp
target: 80
published: 8080
environment:
NGINX_PORT: 80
To create a container from docker-compose files, run the following command.
docker compose create
It will create the nginx web server containers.
Now run the container.
docker compose start
The container will be started.
Try to check using the docker container list command.
As you can see, there is a service run on our local using port 8080. Let's check it.
Yup, it's working.
What if we want to stop the container? Run the following command.
docker compose stop
It will stop all the services we created using the docker-compose files.
What if we want to update the container, for example, we want to change the forwarded port from 8080 to 80?
Just run “docker compose down” to stop and delete the container with all the dependencies (networks and volumes). Then use “docker compose create” and “docker compose start” to recreate and start the service.
Stop and delete the containers.
docker compose down
Now let's update the docker-compose files. Update these lines:
...
target: 80
published: 80
...
Recreate and start the containers.
docker compose create
docker compose start
Perfect.
Docker compose reduce the number of commands we used to manage our containers.
With the small number of services, you won't see the benefit, but it will really help when we deal with several services.
Let's increase the number of our nginx web servers.
Shut down the services, and update the docker files into this :
version: '3.8'
services:
nginx_server:
image: nginx:latest
container_name: nginx_server
ports:
- protocol: tcp
target: 80
published: 80
environment:
NGINX_PORT: 80
nginx_server2:
image: nginx:latest
container_name: nginx_server2
ports:
- protocol: tcp
target: 80
published: 8088
environment:
NGINX_PORT: 80
nginx_server3:
image: nginx:latest
container_name: nginx_server3
ports:
- protocol: tcp
target: 80
published: 8087
environment:
NGINX_PORT: 80
Re-create and start the services.
As you can see, three are 3 nginx services. We could easily run and manage them with a single command using docker-compose.
Docker Compose for Flask and PostgreSQL Apps.
This time, we are going to create a docker-compose file for Flask-PostgreSQL applications. We are not going to make it from scratch. Instead, I’m will use the code from my previous tutorial about Flask and Docker.
If you haven’t seen my previous tutorial, I would recommend you to see it here: Flask and Docker: An Intro for Containerization.
But if you don't want to do it, it's okay, you could download the source code here.
This is what the code base looks like.
To run the program, you need to execute several commands:
Connect to the database using PgAdmin.
Run this query to create tables and insert some data.
It should be working now.
Let’s take a look at the code. As you can see, there are 2 docker files in our project.
One for the Flask application (flask_postgresql > Dockerfile).
FROM python:3.11.1-slim-bullseye
WORKDIR /app
COPY . .
RUN pip3 install -r requirements.txt
ENV PYTHONUNBUFFERED=1
ENV DB=flask_postgresql
ENV DB_USER=root
ENV DB_PASSWORD=root
ENV HOST=flask_postgresql_db_container
ENV PORT=5432
EXPOSE 5000
CMD ["python3", "main.py"]
And the other one for the database images (postgresql_db > Dockerfile).
FROM postgres:latest
ENV POSTGRES_USER=root
ENV POSTGRES_PASSWORD=root
ENV POSTGRES_DB=flask_postgresql
EXPOSE 5432
Now, we want to move the Dockerfile and the container configurations into docker-compose files. First, create the configuration for the database service.
Stop and remove all the Flask-PostgreSQL services we created.
docker container stop flask_postgresql_container
docker container stop flask_postgresql_db_container
docker container rm flask_postgresql_container
docker container rm flask_postgresql_db_container
docker rmi flask_postgresql_image
docker rmi flask_postgresql_db_image
docker network rm flask_postgresql_network
docker volume rm flask_postgresql_volumes
Create a new folder named flask_postgresql_with_compose.
Create a docker-compose file with the following structure.
version: '3.8'
services:
...
volumes:
...
networks:
...
Now let's add the database configuration.
version: '3.8'
services:
flask_postgresql_db_container:
container_name: flask_postgresql_db_container
image: postgres:latest
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: root
POSTGRES_DB: flask_postgresql
ports:
- protocol: tcp
target: 5432
published: 5433
volumes:
- type: volume
source: flask_postgresql_volume
target: /var/lib/postgresql/data
networks:
- flask_postgresql_network
volumes:
flask_postgresql_volume:
name: flask_postgresql_volume
networks:
flask_postgresql_network:
name: flask_postgresql_network
driver: bridge
Here we will create a container named flask_postgresql_db_container.
The database service required persistent storage to store the data, that's why we also need to create a volume.
We are also creating a network so the flask app could connect to the database services.
Create and start the container.
docker compose create
docker compose start
Make sure the container is running.
docker ps -a
Perfect.
Next. Let’s create a service for the flask application.
It’s not like when we build the database service, we can't just use python images to build the Flask application services.
For the Flask application, we need to create a custom image. We have to copy our app into the image and build them.
Docker-compose provides build attributes. It allows us to build the image based on a certain dockerfile before using it to create our service/container.
Let’s create a service for the Flask application. Add the following code to the docker-compose files.
services:
...
flask_postgresql_container:
container_name: flask_postgresql_container
build:
context: ./
dockerfile: Dockerfile
image: flask_postgresql_image:latest
ports:
- protocol: tcp
target: 5000
published: 5000
networks:
- flask_postgresql_network
environment:
PYTHONUNBUFFERED: 1
DB: flask_postgresql
DB_USER: root
DB_PASSWORD: root
HOST: flask_postgresql_db_container
PORT: 5432
...
Take a look at the build attributes.
...
build:
context: ./
dockerfile: Dockerfile
image: flask_postgresql_image:latest
...
context is the position of the docker files.
dockerfile is the dockerfile names.
image is the image name we want to use when we build the docker images.
Don't forget to copy all the Flask application files, and put them into the flask_postgresql_with_compose folders.
Create and start the services.
docker compose down
docker compose create
docker compose start
Go back to PgAdmin and run the queries to create the table and insert some data.
Check the apps.
Fantastic. It's working.
That’s how we dockerize Flask and PostgreSQL using docker-compose.
Quick tips, instead of using “docker compose create” and “docker compose start”, you could use “docker compose up -d” to create and start the containers.
Thanks for reading my articles.
You can get the source code here.
Leave a comment or clap if you like it 👏.