# Dockerizing Flask+MySQL Application Using Compose

In this blog, we are going to containerize the application we created in "[Building URL Shortener API Using Flask + MySQL](https://blog.abbasmj.com/building-url-shortener-api-using-flask-mysql)" using [docker-compose](https://docs.docker.com/compose/). First, we will learn **What is [Docker](https://docker.com)? Why do we need to use it?**

## What is Docker?
To understand what is Docker we need to know why we use Virtual Machines and what are containers? 

**VMs** are basically used to operate multiple operating systems on the same piece of hardware at the same time. Without virtualization, you would need several separate physical units of computers to run several operating systems. It is essential to use different operating systems because several services within an application may require a specific OS to run.  

VMs work great, they do exactly what they are supposed to do, But there is one problem. VMs can take up a lot of system resources because each VM runs not just a full copy of an operating system, but a virtual copy of all the hardware that the operating system needs to run. This quickly adds up to a lot of RAM and CPU cycles. That’s still economical compared to running separate actual computers, but for some applications, it can be overkill. This is where containers come into play.

**Containers** are built on top of the host Operating Systems (Typically Windows or Linux) and they share binary files, core libraries and the OS kernel with each other and the host. Sharing of the resources reduces the need to reproduce the operating system code and means that a server can run multiple workloads with a single operating system installation. Containers are thus exceptionally light. They are only megabytes in size and take just seconds to start. Compared to containers, VMs take minutes to run and are significantly larger than an equivalent container. 

![CONvsVMS.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610131650917/BoiZS-WK0.png)

Docker is a Linux utility that can efficiently create, ship, and run containers. Now, let's look at what is docker-compose. According to the official website of docker:

>Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration

In a nutshell, Compose is a tool which can be used to deploy multiple containers at the same time with a single command.

## Dockerizing Application
Now that you are all caught up let's dockerize our Flask+MySQL URL Shortener API that we built in the previous blog. If you haven't already installed them yet, download and install [Docker](https://docs.docker.com/engine/install/) and [docker-compose](https://docs.docker.com/compose/install/)

We are going to be needing two containers, one to run our Flask application and another one for our MySQL server and database. It is considered best practice to have only one service per container for various reasons like scalability and crash handling.

### Project Layout
Let's have a look at the files we are going to be creating to containerize our application.

```bash
.
├── app
│   ├── Dockerfile
│   ├── application.py
│   └── requirements.txt
├── database
└── docker-compose.yml
```

Docker requires you to store all the instructions to run an application inside a file named `Dockerfile` which is what we have in `app/` directory. Now we don't need to run any applications for the MySQL container, We only need to start the server and store the database which can be achieved directly through `docker-compose.yml` and that's why you don't see a `Dockerfile` in `database/`.

### Containerizing Flask Application
We will add instructions to run our Flask application in the *Dockerfile*. To install all the dependencies we are going to add all our python libraries to a file named *requirements.txt* so we can install them using a single command.

```
FROM python:latest
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["application.py"]
```
Instructions provided to the container to run our application:
1. First we are going to install the latest version of Python.
2. We are going to copy content from `/app` directory where our `application.py` is stored.
3. Switch to `/app` directory
4. Install libraries from requirements.txt
5. Start python CLI
6. Run application.py

That should run our flask application.

### Creating Compose file
As I mentioned above *docker-compose* is used to deploy multiple containers at once which saves us a lot of work and time. In order to use it, we need to create a file called *docker-compose.yml* where we will add instructions on how to create each container.

```YAML
version: '3'

services:
    flask-app:
        container_name: flask-app
        build: app
        restart: always
        ports:
            - '5000:5000'
        volumes:
            - ./app:/app
        networks:
            - backend

    mysql-db:
        container_name: mysql-db
        image: mysql:5.7
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_DATABASE: urlshortener
        ports:
            - '3308:3306'
        volumes:
            - ./database:/var/lib/mysql
        networks:
            - backend

networks:
    backend:

volumes:
    app:
    database:
```

A couple of things to notice here, **services** is where we define our containers. First one is *flask-app*. We are directly importing the *Dockerfile* we created in the app directory using the command `build: app` (Docker expects a "Dockerfile" in the specified directory) so we don't need to add any additional commands here. However, we are going to map a few things with our host system like *port*, we will map containers 5000 port to ours because flask runs on 5000, we will also map our *app* directory with containers. Here we are also creating a network called **backend** through which all the services will be running so we can cross-reference each service in another. 

For MySQL container since we did not create any Dockerfile, we will need to install the service manually that's why you see the line `image: mysql:5.7` which install MySQL 5.7 server on the container. Here we are also adding some environment variables for MySQL password and name of the database that we are going to be using.

In the end, we will define the directories we used and as well as networks.

Now let's run it. Before you can actually run it you need to build them using

```bash
docker-compose build --no-cache
```

If you are running for the first time you don't need *--no-cache*. Now, let us run it

```bash
docker-compose up -d
```
That should run the containers successfully, here *-d* is used to "detach" which basically lets you exit the logs after successfully deploying the containers.

We are not done yet! The MySQL server you started is quite fresh and doesn't have any tables yet. So we are going to access the bash terminal of MySQL containers, run `mysql` command and create our schema. To log in to bash terminal of the MySQL container use:

```bash
docker exec -it mysql-db bash
```
This command basically tells docker to log in to the interactable terminal (-it) of container `mysql-db` with bash

Now that you are in the container's bash terminal, let's start the MySQL CLI using

```bash
mysql -uroot -proot
```
Here my user is root by default and password we defined in docker-compose. Now, you should be able to access the databases. You can test it using

```SQL
SHOW DATABASES;
```

Now you can go ahead and finish building the schema that you want.

at this point, you should be able to access your API successfully on `http://localhost:5000`. You can test it out. Now to stop the containers you can use 

```bash
docker-compose down
```
Read the [official docs](https://docs.docker.com/compose/gettingstarted/) to see what else you can do with docker-compose. That's it for this blog, If you have any questions ask them in the comment section.

## Conclusion
In this blog, you learned about VMs, Containers and what exactly are docker and docker-compose and how to containerize a Flask API which uses MySQL in multiple containers using docker-compose. All the code used above is available at:

%[https://github.com/iam-abbas/URL-Shortener]

For the upcoming blogs, I will be showing how to implement message queues and caching layer using **Redis** in Python-Flask and how to deploy a separate container for it using compose.

 --- 

Subscribe to my newsletter if you are interested in learning more about DevOps, Frontend Development, Backend Development, Machine Learning and as well as Freelancing. Follow me on Twitter @abbasmdj.

