Two-tier Python, Flask and MySql web application deployment using Docker compose
Deployment Architecture
Prerequisites
- Docker
# Install docker
$ sudo apt-get install docker.io -y
# Allow cuurently logged user to use Docker
$ sudo usermod -aG docker $USER
# -aG = add currently logged user to docker group
- Git (For cloning the repository)
$ sudo apt install git -y
Setup of project
Clone this repository (if you haven't already)
git clone git@github.com:ojasjawale/two-tier-flask-app.git
Navigate to the project directory
Create Dockerfile in project directory
# Use an official Python runtime as the base image
FROM python:3.9-slim
# Set the working directory in the container
WORKDIR /app
# Install required packages for the system
RUN apt-get update\
&& apt-get upgrade -y\
&& apt-get install -y gcc default-libmysqlclient-dev pkg-config\
&& rm -rf /var/lib/apt/lists/*
# Copy the requirements file into the container
COPY requirements.txt .
# Install app dependencies
RUN pip install mysqlclient
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the source code
COPY . .
# Specify the command to run your application
CMD ['python','app.py']
Creating image of frontend from Dockerfile
/projects/python/two-tier-flask-app$ docker build -t two-tier-app:v1 .
Pull mysql 5.7 from dockerHub
$ docker pull mysql:5.7
Now we have total two images, frontend and database
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python 3.9-slim b97320a8c1ca 13 days ago 125MB
mysql 5.7 5107333e08a8 7 months ago 501MB
Create persistent volume for container mysql container i.e database container
$ docker volume create mysql-data
$ docker volume ls
DRIVER VOLUME NAME
local mysql-data
Create user-defined bridge network for both containers i.e two-tier-app & mysql
$ docker network create twotier -d bridge
docker network create
: This is the base command to create a new Docker network.twotier
: This is the name of the network being created. In this case, the network is namedtwotier
.-d bridge
: This specifies the network driver to use. Thebridge
driver is used to create a bridged network, which allows containers connected to this network to communicate with each other and, if configured, with the host machine.Here, we have created bridge network for both containers so that they can communicate with each other.
Now create mysql database container
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python 3.9-slim b97320a8c1ca 13 days ago 125MB
mysql 5.7 5107333e08a8 7 months ago 501MB
Image of mysql is mysql:5.7
Now create database container
$ docker run -d --name mysql --network=twotier -e MYSQL_ROOT_PASSWORD=root -v mysql-data:/var/lib/mysql mysql:5.7
Breakdown of above command,
docker run
: This is the base command to create and start a new Docker container.-d
: This option runs the container in detached mode, meaning it will run in the background.--name mysql
: This assigns the namemysql
to the container. This makes it easier to reference this container in future commands.--network=twotier
: This connects the container to the Docker network namedtwotier
. This network must be created beforehand usingdocker network create twotier
.-e MYSQL_ROOT_PASSWORD=root
: This sets an environment variableMYSQL_ROOT_PASSWORD
within the container with the valueroot
. This variable is required for the MySQL image to set the root password for the MySQL server.-v mysql-data:/var/lib/mysql
: This mounts a named volumemysql-data
to the container's/var/lib/mysql
directory. This ensures that the MySQL data is stored persistently outside the container, so data is not lost when the container is stopped or removed.mysql:5.7
: This specifies the Docker image to use for the container, in this case,mysql
with the tag5.7
. This image must be available either locally or from a Docker registry.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7c61b0814417 mysql:5.7 "docker-entrypoint.s…" About an hour ago Up About an hour 3306/tcp, 33060/tcp mysql
Create database inside container
$ docker exec -it <mysql container id or name> bash
$ docker exec -it 7c61b0814417 bash
Breakdown of above command,
docker exec
: This command is used to run a command inside a running Docker container.-it
: These are two options combined:-i
: Stands for interactive. It keeps the STDIN (standard input) open, allowing you to interact with the container.-t
: Allocates a pseudo-TTY (a terminal), providing a terminal interface to the container.
7c61b0814417
: This is the ID of the container in which you want to execute the command. Container IDs are usually unique hashes assigned by Docker when the container is created. You can also use the container name if it's easier to remember.bash
: This is the command to be executed inside the container. In this case, it starts a Bash shell, allowing you to interact with the container's filesystem and run other commands as if you were logged into a terminal session on the container.
# Now we are inside container of mysql
bash# mysql -u root -p
password:
mysql> create database devops;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| devops |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> exit # To exit from database
bash# exit
Above is to exit from container
Now create two-tier-app's (frontend's) container
$ docker run -d --name 2-tier-app --network=twotier -p 5001:5000 -e MYSQL_HOST=mysql -e MYSQL_USER=root -e MYSQL_PASSWORD=root -e MYSQL_DB=devops two-tier-app:v1
Breakdown of above command,
docker run
: This is the base command to create and start a new Docker container.-d
: This option runs the container in detached mode, meaning it will run in the background.--name 2-tier-app
: This assigns the name2-tier-app
to the container. This makes it easier to reference this container in future commands.--network=twotier
: This connects the container to the Docker network namedtwotier
. This network must be created beforehand usingdocker network create twotier
.-p 5001:5000
: This publishes the container's internal port5000
to the host machine's port5001
. It allows you to access the application running in the container viahttp://localhost:5001
.-e MYSQL_HOST=mysql
: This sets an environment variableMYSQL_HOST
within the container with the valuemysql
. Environment variables are used to configure the application inside the container.-e MYSQL_USER=root
: This sets the environment variableMYSQL_USER
toroot
.-e MYSQL_PASSWORD=root
: This sets the environment variableMYSQL_PASSWORD
toroot
.-e MYSQL_DB=devops
: This sets the environment variableMYSQL_DB
todevops
.two-tier-app:v1
: This specifies the Docker image to use for the container, in this case,two-tier-app
with the tagv1
. This image must be available either locally or from a Docker registry.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
29c083ce009f two-tier-app:v1 "python app.py" About an hour ago Up About an hour 0.0.0.0:5001->5000/tcp, :::5001->5000/tcp 2-tier-app
7c61b0814417 mysql:5.7 "docker-entrypoint.s…" About an hour ago Up About an hour 3306/tcp, 33060/tcp mysql
Now we have both of the container's running for frontend & database.
Open exposed ports in Security groups of an EC2 instance
Open Below ports in Security group of an your server,
5001
3306
Check both containers are up and running,
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
29c083ce009f two-tier-app:v1 "python app.py" About an hour ago Up About an hour 0.0.0.0:5001->5000/tcp, :::5001->5000/tcp 2-tier-app
7c61b0814417 mysql:5.7 "docker-entrypoint.s…" About an hour ago Up About an hour 3306/tcp, 33060/tcp mysql
Accessing our two-tier-app on browser
Take Public_IP
of your instance and host_port
.
URL should be like this : <IP>:5001
-> http://54.209.135.174:5001/
Trying to submit messages,
Hurray :)))
Two-Tier application is successfully running.
Running application using Docker compose
- Install docker-compose-v2
$ sudo apt install docker-compose-v2
- Create
docker-compose.yml
file in project directory.
version: '3.9'
services:
mysql: # Container 1 of database
container_name: mysql
image: 'mysql:5.7' # Base image
ports:
- '3306:3306'
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: devops
MYSQL_USER: admin
MYSQL_PASSWORD: admin
volumes:
- 'mysql-data:/var/lib/mysql' # Binding of persistent volume
networks:
- twotier # user-defined bridge network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 5
start_period: 30s
timeout: 5s
flask-app: # Container 2 of frontend
build:
context: . # Building image using Dockerfile
ports:
- '5001:5000'
environment:
MYSQL_HOST: mysql # mysql is an database container name
MYSQL_USER: admin
MYSQL_PASSWORD: admin
MYSQL_DB: devops
depends_on: # Run only of mysql container is working fine
mysql:
condition: service_healthy
networks:
- twotier
volumes:
mysql-data: # Define volume and it will create volume
networks:
twotier: # Custome network name
driver: bridge # Custome network driver type
- Run containers using
docker-compose.yml
file.
$ docker compose up -d
- Both the containers are up and running,
- Try to access application on browser,
Take Public_IP
of your instance and host_port
.
URL should be like this : <IP>:5001
-> http://54.209.135.174:5001/
- Now stop down all the containers,
$ docker compose down
And obviously after docker compose down
,
Connect with Me
Follow me for more amazing content :)