Docker for dummies… Part-II 🐳 🧠💡

Docker Volumes 🚀 and their Usage 🔓

Momal Ijaz
AIGuys
9 min readSep 24, 2022

--

This is the second article of the “Docker for dummies… 🐳 🧠💡” series, in which I will explain docker’s what, why, and how in simpler steps. By end of reading this series, you would be able to know what docker is, why you need to dockerize your projects and how you can do that!

Each article is structured in a stand-alone intuitive way, so that you can read just this article only, to find what you might be looking for.

Credits: Maximilian Schwarzmüller, Docker Udemy Guide’22

Docker in Action!!

Pre-req: Basic familiarity with docker, images, and containers.

Understanding the problemo first 🚩 …

Live code updates 🔥 and Inter-container data exchange 📦

Okay, the subtitles might be scary… “Live code updates and inter-container data exchange”😳…. like what on earth are we talking about??

But let’s take a step back to understand the problem first and then we will how docker is helping us solve it….. using the features mentioned in the subtitle!

Problemo 1: App data loss 💾

So, let’s say you have an application (a node application), that you have dockerized and run in a container… sweet! If you don't know how to do that, check out my first article of this series on dockerizing a hello world node-app.

Now, your app is collecting some data from the user, using a form on a webpage and you are saving that to a text file. Sweet!

But you accidentally shut down the container and when you restart it… all the data that the user entered earlier is GONE! 🤯 No…. you needed to store all data that was ever filled into the form by the user… but apparently, whenever you are spinning up a new container, it is starting fresh and app data is not surviving the container’s shutdown or restart.

This is common docker container behavior. Whenever you spin up a new container it always starts fresh and any data that you want to store permannently cannot survive container shut down or restart…. aka its lost!

Reflecting permanent AppData loss across container shutdowns!

Problemo 2: Live coding changes ✨

To understand the second problem, say we have a node app running in a container. Now the code of your app is baked into the image, your container is running on. If you ever make any changes to your code on your local file system, you should not expect those changes to be reflected in the dockerized app.

Docker containers run on images, which are read-only so no changes can be made to an image, once it is built. Dah!!! now you have to rebuild the image to reflect that tiny change you made in your code to be reflected in the dockerized app. That is the only way, to keep your dockerized app updated…..so tedious!

Live code changes you do on your filesystem are not reflected in dockerized running apps in containers. You have to rebuild image and run a new container on that updated iamge everytime you make any change to you code.

Live coding updated failure in Docker

Types of Data 💽 🗄️ 💾

So now you understand the problem we will be solving.

a. We want our live code changes to be reflected in an app already running in a docker container, to avoid image re-building to reflect the latest code changes.

b. We want our app data to be not lost, as the container shutdowns and restarts again.

These two problems can be efficiently solved using DOCKER Volumes ❤️.

Before diving just quickly understand the type of data your docker container has, to understand the functionality of volumes better.

Types of data in a Docker Container

Application data is the code and its dependencies, that needs to survive a container shutdown and as it is baked into the image while we build it, it is not impacted if we shut down or restart a container, running on top of that image. But it is read-only hence we cannot change it once the image is built.

Temporary data is local variables and temp app data, that is stored in containers’ local RAM and is lost when the app ends aka container is stopped or removed. These variables are not needed after an app ends running so we are good.

The final type of data is more important. It is the data generated by our app running in the container, and we want this data to stay around after the app stops running, like feedback collected from a user using a web app or user entering his / her sign-up / login info on a web page, we don't want to lose this type of data. If we store it in a container file system, it will be lost after the container stops or is removed. Hence, we need to store this kind of data in docker volumes.

Docker Volumes ❤️

I put a heart next to it! Because I love how simply docker volumes are useful and help us solve important afore-mentioned development problems.

Docker Volumes are nothing but folders on your local file system, that is synced and mapped to folders inside a container.

These volumes are going to make our lives easier now by helping us solve the problems we discussed above!

There are three types of Docker Volumes:

Types of Docker Volumes

Why do we have three types and what is their usage? Let’s learn by doing!

Demo App 📱

Let’s consider a demo app to understand the usage of docker volumes fully.

We have a node app, which collects feedback from users and saves it in a folder named feedback on your local file system. If that file exists already, it redirects you to a page that says, the file exists, try another name!

The folder structure of the demo app

The app comprises three main folders. feedback, pages, and public. Feedback is an empty folder, pages contain redirection HTML pages, and the public has a CSS styling sheet. package.json comprises code dependencies and server.js is the main application file.

Now you don’t need to write this node application, you can just download it and copy it into a folder of your choice to follow along. The main focus is on dockerizing this application using volumes.

Dockerize your project 🐳

Now that you know how the app is working, let's start by simply dockerizing our project. For that, you need to create an empty text file with the name Dockerfile and copy the content into it.

This Dockerfile is creating a simple blueprint for running our node app, by importing from a base node image and copying package.json installing its packages in our container by running npm install, and later copying the remaining app’s coed in /app directory. Finally, we are exposing the port our node app is listening on, and setting the command needed to run our app i.e. node server.js.

Build your image 🎬

Simply build the image by running the docker build command in the working directory of your app, use -t tag with the docker build command to give your image a name. Do not ignore . in the end of cmd, it is telling the “docker build” command where is the Dockerfile to build this image.

docker build -t node_img .

Run a container

Now you can run a container on top of this image, by running “docker run “ command as below.

docker run -p 80:80 node_img

The basic command looks like the above, in which we specify the node image and the port to expose for the app to work.

We can improve it a little by using some tags of the docker run command, you can check them all by “docker run — help”.

docker run -p 80:80 --rm -d --name node_cont node_img
  • — d : this tag won’t block ur terminal after hitting enter.
  • — rm: It will delete the container after you stop it.
  • — name: used to give the container a name, node_cont.

Revisiting problem 🚩

Now if you go to localhost:80, you are going to see a running app. Yay!!!

Your app running in the docker container you just spun up!

Enter feedback and title, and save it! Now again enter the same feedback, specifically the title. It will tell you the feedback already exists. Great! That is desired behavior of our app.

Enter a feedback and save it.

Now if you stop your container, and restart it by following commands.

docker stop node_cont #stop cont node_cont
docker run -p 80:80 --rm -d --name node_cont node_img #same cmd

And try entering the same feedback, it takes it and doesn't show that it already exists!

The feedback you entered first time is gone! oh oh….😳

===> That was our App data and we wanted it to stay safe across container shutdowns!

Also, try making a small change in your node_app, like making line 15 in pages/feebdack.html from “Your Feedback” to “Your Feedback please”.

Make a small change in your code.

Now refresh the page running your app….

Did you see that change reflected? Nah…. hmmm!

Running containers don’t reflect changes we make in source code on our local file system. They are isolated. Ain’nt no body got time to rebuild a new image and re-run a new container.

DOCKER VOLUMES ❤️ to the rescue…

Let’s solve both our problems using Docker volumes now.

Inter-container data exchange

Let’s save the feedback we are getting from users across container shutdown.

We can do that by using a named volume. We can create a named volume using -v tag while running a container. The format is as follows:

docker run -v vol_name:path_in_container_filesys img_name

Here vol_name is the name of the folder created in your local file system, you don’t know its location but its names only. That is because it is managed by docker and you are not supposed to alter its contents. After the colon, we specify the path to a folder in the container’s file system, to which this folder would be mapped to.

This volume would survive even if we shut down our container, and hence when we spin up a new container with the same volume, it is gonna be able to access the app data that the previous container collected!

Let’s see it in action!!! Stop your previous container and now try running docker run with this command.

docker run -p 80:80 --rm -d --name node_cont -v feedback:/app/feedback node_img

Visit localhost:80 and enter a feedback f1.

Stop this container and re-enter the same command to spin up a new container. (*new because — rm cmd will automatically delete the previous container when you stop it).

Trying entering the same feedback again and it says it exists!! Yes…. Our app data survived across container shutdowns…. GREAT JOB! ⭐️

Live code updates

Let’s solve another problem by using Bind Mounts.

Bind mounts are also volumes, but you know where they are on your system and you can read and write into them. They are managed by you!!!

They can help us reflect on the live code changes that we make in our code in the running container. The format of the command is also similar just instead of volume name, you specify an absolute path to the folder to be mapped in the command. In our case, since we want changes in our code to be reflected in the container’s code folder, we will use these two as the source and destination folders.

docker run -v folder_path_in_your_local_filesys:folder_path_in_docker_cont node_img

Let’s see it in action!

docker run -p 80:80 --rm -d --name node_cont -v /Users/app/FEEDBACK_APP/:/app/ 
-v feedback:/app/feedback node_img

We see two -v tags in the other command the first one is for the blind mode, it is mapping the feedback app folder to the app folder in my docker containers. The second -v tag is from the previous command. With this, we are pretty much done now if you go back to making the same change in line 15 of feedback.HTML and refresh the page you will be able to see the change reflected…..Voila!!!

What we covered…

  • The problem of losing app data across container shutdowns and live code update inability.
  • What types of app data we can have?
  • Docker volumes and their types.
  • How docker volumes can help us solve this problem?

Happy Learning! ❤️

--

--

Momal Ijaz
AIGuys
Writer for

Machine Learning Engineer @ Super.ai | ML Reseacher | Fulbright scholar'22 | Sitar Player