🚀Building a Two-Tier Application with Docker, MySQL, and Flask Setup.

Trushid HatmodeTrushid Hatmode
6 min read

🚀 Thrilled to share the success of a hands-on Docker project! 🐳💻 Recently, I wrapped up a hands-on experience deploying a two-tier Flask application paired with MySQL. The journey involved delving into the complexities of containerized architecture, with a special emphasis on establishing seamless communication between the front-end Flask app and the back-end MySQL database. 🛳️✨

🌠Introduction: 🌠 🚀

In this project, we will build a two-tier application using Docker for containerization, MySQL for database management, and Flask as the web framework. This setup allows for easy deployment, scalability, and efficient management of application components.

🌠Prerequisites

Before you begin, make sure you have the following installed:

  • Docker

  • Git (optional, for cloning the repository)

🌠Clone the Repository:


ubuntu@ip-172-31-39-158:~/projects$  git clone https://github.com/Trushid/two-tier-flask-app.git
Cloning into 'two-tier-flask-app'...
remote: Enumerating objects: 140, done.
remote: Counting objects: 100% (77/77), done.
remote: Compressing objects: 100% (38/38), done.
remote: Total 140 (delta 62), reused 39 (delta 39), pack-reused 63
Receiving objects: 100% (140/140), 35.15 KiB | 3.20 MiB/s, done.
Resolving deltas: 100% (69/69), done.
ubuntu@ip-172-31-39-158:~/projects$ cd two-tier-flask-app/
ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$

🌠Docker File:

  1.   # 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 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 application code
     COPY . .
    
     # Specify the command to run your application
     CMD ["python", "app.py"]
    
  2. Build the Docker Image:

     docker build -t flask-app .
    

🌠Setting Up MySQL Container:

  1. Create MySQL Container:

    • Run the following Docker command to set up a MySQL container with specified environment variables:

    • Command:-docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=test@123 -e MYSQL_DATABASE=testdb -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin --name mysql mysql:latest

        ubuntu@ip-172-31-10-226:~/projects/two-tier-flask-app$ docker images
        REPOSITORY   TAG        IMAGE ID       CREATED          SIZE
        flask-app    latest     c9619ea0fce1   12 seconds ago   389MB
        mysql        latest     a3b6608898d6   6 weeks ago      596MB
        python       3.9-slim   262f85ec54de   6 weeks ago      125MB
        ubuntu@ip-172-31-10-226:~/projects/two-tier-flask-app$ docker ps
        CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
        ubuntu@ip-172-31-10-226:~/projects/two-tier-flask-app$ docker ps -a
        CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
        ubuntu@ip-172-31-10-226:~/projects/two-tier-flask-app$ docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=test@123 -e MYSQL_DATABASE=testdb -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin --name mysql mysql:latest
        9bba086ef951fb586b9be8f487a49272298ceab95f31826d6f71b425ebd14d10
        ubuntu@ip-172-31-10-226:~/projects/two-tier-flask-app$ docker ps
        CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                                  NAMES
        9bba086ef951   mysql:latest   "docker-entrypoint.s…"   4 seconds ago   Up 3 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql
      

🌠Building Flask App Image and Container:

    1. Build Flask App Image:

      • Build the Docker image for the Flask application:

      • Command:-

          docker build -t flask-app .
        
      1. Run Flask App Container:

        • Start the Flask application container, specifying the MySQL connection details:

        • Command:- docker run -d -p 5000:5000 -e MYSQL_HOST=mysql -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin -e MYSQL_DB=testdb --name flask-app flask-app:latest

        • This command runs a Docker container based on the "flask-app" image. It exposes port 5000 on the host machine, sets environment variables for MySQL connection, and names the container as "flask-app ."

        ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker ps -a
        CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
        03657e058161   mysql:latest   "docker-entrypoint.s…"   43 seconds ago   Up 42 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql
        ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker images
        REPOSITORY   TAG        IMAGE ID       CREATED              SIZE
        flask-app    latest     4a7e95497b28   About a minute ago   389MB
        mysql        latest     a3b6608898d6   6 weeks ago          596MB
        python       3.9-slim   262f85ec54de   6 weeks ago          125MB
        ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker run -d -p 5000:5000 -e MYSQL_HOST=mysql -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin -e MYSQL_DB=testdb --name flask-app flask-app:latest
        9d84155e601b8cd9558676d121a1edd71fa1ed192d9b4c2bdb8547e7b865b056
        ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker ps -a
        CONTAINER ID   IMAGE              COMMAND                  CREATED              STATUS              PORTS                                                  NAMES
        9d84155e601b   flask-app:latest   "python app.py"          11 seconds ago       Up 9 seconds        0.0.0.0:5000->5000/tcp, :::5000->5000/tcp              flask-app
        03657e058161   mysql:latest       "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql
        ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$
  1. Expose Port and Access:

    • Allow port 5000 on AWS security inbound rule.

    • Access the application using the public IP address and port number.

🌠Introducing Docker Network:

  • Create Docker Network Bridge: see the network list docker network ls

    • Establish a bridge network for communication between containers:

      * Command:- docker network create -d bridge two-tier-app-nw

      •   ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker network ls
          NETWORK ID     NAME      DRIVER    SCOPE
          df3faeb606dd   bridge    bridge    local
          faa303557216   host      host      local
          927d5c2d598d   none      null      local
          ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker network create -d bridge two-tier-app-nw
          7b29a84eb6228c85dc3f0d8a0e51775e2ffbb6b56321a1443e74e6256b3e70e0
          ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker network ls
          NETWORK ID     NAME              DRIVER    SCOPE
          df3faeb606dd   bridge            bridge    local
          faa303557216   host              host      local
          927d5c2d598d   none              null      local
          7b29a84eb622   two-tier-app-nw   bridge    local
          ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$
        

*Connect MySQL Container to Network:

  • Attach the MySQL container to the created network:

  • Command:- docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=test@123 -e MYSQL_DATABASE=testdb -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin --name mysql --network two-tier-app-nw mysql:latest

      ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=test@123 -e MYSQL_DATABASE=testdb -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin --name mysql --network two-tier-app-nw mysql:latest
      44fe2e997d8c5f0792ba58fbd46593596ea23ad36ad6df0c32d6f6012d6143c6
      ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$
    

    *Connect Flask App Container to Network:

  • Join the Flask application container to the same network

  • Command:- docker run -d -p 5000:5000 -e MYSQL_HOST=mysql -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin -e MYSQL_DB=testdb --name flask-app --network two-tier-app-nw flask-app:latest

  •   ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ docker run -d -p 5000:5000 -e MYSQL_HOST=mysql -e MYSQL_USER=admin -e MYSQL_PASSWORD=admin -e MYSQL_DB=testdb --name flask-app --network two-tier-app-nw flask-app:latest
      5bffb57e2b83a48e2d1041485c271d5df41258e69bd2b1cb0e63c6890fcacba4
      ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$
    

🌠Inspect Network:

    • Verify the presence of both containers within the created network:

      • Command:- docker inspect two-tier-app-nw

          [
              {
                  "Name": "two-tier-app-nw",
                  "Id": "7b29a84eb6228c85dc3f0d8a0e51775e2ffbb6b56321a1443e74e6256b3e70e0",
                  "Created": "2023-12-07T13:46:21.978317078Z",
                  "Scope": "local",
                  "Driver": "bridge",
                  "EnableIPv6": false,
                  "IPAM": {
                      "Driver": "default",
                      "Options": {},
                      "Config": [
                          {
                              "Subnet": "172.18.0.0/16",
                              "Gateway": "172.18.0.1"
                          }
                      ]
                  },
                  "Internal": false,
                  "Attachable": false,
                  "Ingress": false,
                  "ConfigFrom": {
                      "Network": ""
                  },
                  "ConfigOnly": false,
                  "Containers": {
                      "44fe2e997d8c5f0792ba58fbd46593596ea23ad36ad6df0c32d6f6012d6143c6": {
                          "Name": "mysql",
                          "EndpointID": "e51466de1b304b1f61eb77e1f4b6f4c7639145f47365b846ecd4535d3889fedd",
                          "MacAddress": "02:42:ac:12:00:02",
                          "IPv4Address": "172.18.0.2/16",
                          "IPv6Address": ""
                      },
                      "5bffb57e2b83a48e2d1041485c271d5df41258e69bd2b1cb0e63c6890fcacba4": {
                          "Name": "flask-app",
                          "EndpointID": "a60b3e072f7c6ffde19412c1a6b1ba3e0bc624c7786fd4e5c5e2daa46019261f",
                          "MacAddress": "02:42:ac:12:00:03",
                          "IPv4Address": "172.18.0.3/16",
                          "IPv6Address": ""
                      }
                  },
                  "Options": {},
                  "Labels": {}
              }
          ]
          ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$
        
  • Solving MySQL Database Error:

    1. Access MySQL Container:

      • Enter the MySQL container's shell to interact with the database:

      • Command:- docker exec -it <mysql_container_id> bash

      •   ubuntu@ip-172-31-39-158:~/projects/two-tier-flask-app$ mysql -u root -h 172.18.0.1 -P 3306 -p
          Enter password:
          Welcome to the MySQL monitor.  Commands end with ; or \g.
          Your MySQL connection id is 8
          Server version: 8.2.0 MySQL Community Server - GPL
        
          Copyright (c) 2000, 2023, Oracle and/or its affiliates.
        
          Oracle is a registered trademark of Oracle Corporation and/or its
          affiliates. Other names may be trademarks of their respective
          owners.
        
          Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
        
          mysql>
        
    2. Create the messages table in your MySQL database:

      • Create a database:
        mysql>  sqlCopy codeCREATE DATABASE testdb;

        mysql>   CREATE DATABASE testdb;
        Query OK, 1 row affected (0.06 sec)

        mysql>

Select the created database:

        sqlCopy codeUSE testdb;

Now you can create your table:

        sqlCopy codeCREATE TABLE messages (
            id INT AUTO_INCREMENT PRIMARY KEY,
            message TEXT
        );

3. Insert data into the messages table:

sqlCopy codeINSERT INTO messages (message) VALUES
    ('Hello, this is a message.'),
    ('Another message here.');

4Retrieve the data from the messages table:

sqlCopy codeSELECT * FROM messages;
mysql> select * from messages;
+----+---------------------------+
| id | message                   |
+----+---------------------------+
|  1 | Hello, this is a message. |
|  2 | Another message here.     |
+----+---------------------------+
2 rows in set (0.00 sec)

🌠🌠🌠Thrilled to share that our application deployment is a success! 🎉 After overcoming a few challenges, we've got our two-tier Flask app up and running seamlessly. A huge shoutout to ME 😁 for the hard work and dedication! 🙌

Key Achievements: ✅ MySQL Container Setup ✅ Docker Image and Container for Flask App ✅ Database and Table Creation ✅ Application Deployment Success

Conclusion: This project showcases the seamless integration of Docker, MySQL, and Flask to create a two-tier application. The use of containerization simplifies deployment and management, making it an efficient solution for modern applications. By following these steps, you can replicate and customize this setup for various projects, promoting scalability and maintainability.

11
Subscribe to my newsletter

Read articles from Trushid Hatmode directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Trushid Hatmode
Trushid Hatmode

As a DevOps Engineer, I'm passionate about building and maintaining robust, efficient, and scalable infrastructure to enable seamless software delivery. With a strong foundation in C/C++, Linux, and a toolkit that spans AWS, Jenkins, Docker, Nagios, Kubernetes, YAML, Ansible, Terraform, Bash Scripting, Git, and GitHub, I'm well-equipped to tackle the challenges of modern software development and deployment.