Two-tier Python, Flask and MySql web application deployment using Docker compose

Two-tier Python, Flask and MySql web application deployment using Docker compose

  1. Deployment Architecture


  1. 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

  1. 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 named twotier.

  • -d bridge: This specifies the network driver to use. The bridge 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 name mysql to the container. This makes it easier to reference this container in future commands.

  • --network=twotier: This connects the container to the Docker network named twotier. This network must be created beforehand using docker network create twotier.

  • -e MYSQL_ROOT_PASSWORD=root: This sets an environment variable MYSQL_ROOT_PASSWORD within the container with the value root. 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 volume mysql-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 tag 5.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 name 2-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 named twotier. This network must be created beforehand using docker network create twotier.

  • -p 5001:5000: This publishes the container's internal port 5000 to the host machine's port 5001. It allows you to access the application running in the container via http://localhost:5001.

  • -e MYSQL_HOST=mysql: This sets an environment variable MYSQL_HOST within the container with the value mysql. Environment variables are used to configure the application inside the container.

  • -e MYSQL_USER=root: This sets the environment variable MYSQL_USER to root.

  • -e MYSQL_PASSWORD=root: This sets the environment variable MYSQL_PASSWORD to root.

  • -e MYSQL_DB=devops: This sets the environment variable MYSQL_DB to devops.

  • two-tier-app:v1: This specifies the Docker image to use for the container, in this case, two-tier-app with the tag v1. 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

LinkedIn | GitHub

Follow me for more amazing content :)