Flask + Vue + MySQL on Docker. Part III — Let’s Dockerize

Rapando Sam
7 min readSep 22, 2019

--

Photo by frank mckenna on Unsplash

In Part I, we set up the database and the API. In Part II we set up the front end UI and used it to view the quotes in the database and add new quotes. Now lets dockerize. We will do it using the same steps.

If you are not farmiliar with docker or docker-compose, please refer to the links in Part I.

The code for this tutorial is hosted at GitHub

Create a MySQL container with our db and table

In the root folder (project) create a file and call it docker-composer.yml and Add the following code.

./docker-compose.yml

In the following code, we have created a service called db. This will be the database container. We are telling docker-compose to build an image from mysql version 5.7

The volume line copies the contents of db folder to /docker-entrypoint-initdb.d. All sql files in the folder are run. Therefore the database, table and the data in db/init.sql will be created in the container.

Next we are instructing docker-compose to always restart the container when we rebuild it.

The environment section sets environment variables in the container. For more information on this please read here. Because we are specifying the name of the database here, it will be created when the container is created. Therefore the first two lines in db/init.sql do not matter. Comment them out or remove them.

Create a PHPMyAdmin service to access the database

We can use PHPMyAdmin to access and manage our database in the container.

Update the docker-compose.yml to:

docker-compose.yml with phpmyadmin service

The last line in the phpmyadmin service has ports set to 8080:80. The first port is the port on the host computer. The second port is the port that the service is running on in the container. This means that if I go to localhost:8080 on my laptop, I should be able to access localhost (port 80) in the container where phpmyadmin will be running.

Let us build. Run the following command:

docker-compose up — build

After images are downloaded and the build is complete, go to localhost:8080 on your laptop and login to phpmyadmin with the details set in the environment section of the db service.

Logging into phpMyAdmin
The sample data

Note that on the left side we have the quotes_db. In the quotes_db we have one table ‘quote’ and in it we have one quote. All this data is in a docker container!.

Containerize the Flask API and run it with Nginx

Cd into the api folder and in it create the following Dockerfile file.

api/Dockerfile

In this dockerfile we are using a Python 3.7.2 image. In the second line we are setting our working directory to /app and in the next line we are copying our project to the work directory. Line 4 installs packages from requirements.txt into our container and the last line instructs how the app should be run using uwsgi.

In the same api folder, add a .dockerignore file. It specifies which files/ folders that should not be copied to our working directory. It works like .gitignore for git.

api/.dockerignore

Let us now add the api service to docker-compose.yml. An important thing to note now is that, we are going to run the api instance on port 9000 inside the container but we will be accessing it on our host machine (outside the container) on port 8000.

We are setting build to ./api because our Dockerfile is inside the api folder. After specifying where docker-compose should build from, we are (optionally) naming the container api. The volumes directive specifies that we mount the ./api folder to /app. Remember in our API’s Dockerfile we specified the work directory as /app. Under Expose directive we have chosen port 9000. Remember that inside the container, the api will be running on port .

Next we create app.ini in the api directory. This basically defines the socket that Nginx will use to serve the Flask API.

Note that we are still using port 9000.

Next, let us set up Nginx. In the project root folder, create nginx folder and in it add the following nginx.conf file.

nginx/nginx.conf

In this conf file we are listening to port 8000 and directing it to api:9000. This is because containers use the service name as the host name. In the docker-compose file, the api service is called ‘api’ and it is running on port 9000. Therefore to access it within the container, we go to api:9000.

Next, lets create the nginx/Dockerfile to build the nginx image.

nginx/Dockerfile

In the Dockerfile above we are building from the latest nginx image. We then remove the default nginx conf file and replace it with our own nginx.conf

We can then add a nginx service to our project docker-compose.yml

docker-compose.yml

In the nginx service section we have ports 8000:8000. This means that when we access localhost:8000 from our laptop, it will route the request to port 8000 in the container. Remember in the nginx/nginx.conf, requests to port 8000 are routed to port 9000 in the container where our Flask API runs.

Next we edit the db url inside api/db.py to match the environment variables in our db service in docker-compose.yml

db_url = “mysql+pymysql://dbuser:dbpassword@db/quotes_db”

Note that under host name I have put db. Remember the service name is used as the host name within the containers so instead of localhost we can use db.

Press Ctrl+C/ Ctrl+D to stop the process on your terminal and run docker-compose down to stop the MySQL and PHPMyAdmin containers we created before. Now you can run docker-compose up — build again. To check the logs in a cleaner way run

docker-compose up — build -d && docker-compose logs — tail=all -f

You should now be able to access the API on localhost:8000

Our API running on 8000 on our local laptop but port 9000 in the container.

Containerize the Vue Front End app and run it with Nginx

For a comprehensive guide on how to do this, please watch this video.

I will do a summary though. Inside the ui folder add the following Dockerfile

ui/Dockerfile

In the Dockerfile we have two sections. The first part builds the Vue app. The second part copies the built app in dist folder to /usr/share/nginx/html which is the folder nginx serves its files from. For those using httpd (apache) this is the equivalent of /var/www/html.

Next, in the ui folder, create a .dockerignore. We obviously don’t want to upload the node_modules folder

ui/.dockerignore

Now we can serve the UI app using nginx. We will use port 8001 from the laptop (externally) and port 80 internally (in the container).

Update your docker-compose.yml file to look like this.

docker-compose.yml

Note that after the api service I have added the ui service. We are exposing port 80 for this because it will be running it from Nginx’s default folder. Let’s not tell Nginx to serve the app. Update the nginx/nginx.conf file to serve the Vue app.

nginx/nginx.conf

We have added a server block to serve the Vue app. Now let’s allow requests from outside the container (from the laptop basically). Update the nginx service in docker-compose.yml file to look like this.

final docker-compose.yml

Note that we have added this under ports: — “8001:80”. This means that, when we visit localhost:8001 on our laptop, it will be routed to localhost within the container where our UI app runs.

Important

Next, we need to change the urls where we are accessing our api. Change localhost:5000 to localhost:8000 in both src/Home.vue and src/NewQuote.vue. This is because, the api can be accessed on port 8000.

Now let’s run our container again.

When we go to localhost:8001, we can view and even add a new quote!

The UI running on Nginx inside the container
Adding a new quote
The quote is visible on the UI

Let us check the db using PHPMyAdmin. Let’s go to localhost:8080

Confirming if the quote really went to the db *wink*

And that is how to run a MySQL database, PHPMyAdmin database manager alongside Flask and Vue (served by Nginx) using Docker and Docker-compose.

Hopefully this has been an informative tutorial.

Cheers!

Feel free to ask any question through the comments.

--

--