Persisting data using Docker Volume and Bind Mount


Objectives

Learn how Docker persisting data.

Tech Stack

Persisting data

The container’s filesystem

When a container runs, it uses the various layers from an image for its filesystem. Each container also gets its own “scratch space” to create/update/remove files. Any changes won’t be seen in another container, even if they’re using the same image.

Container volumes

Volumes provide the ability to connect specific filesystem paths of the container back to the host machine. If you mount a directory in the container, changes in that directory are also seen on the host machine. If you mount that same directory across container restarts, you’d see the same files. Check out the official documentation for a more detailed explanation.

Persist todo data

By default, the todo app stores its data in a SQLite database at /etc/todos/todo.db in the container’s filesystem. It’s simply a relational database that stores all the data in a single file. While this isn’t the best for large-scale applications, it works for small demos.

- Create a volume and start the container

docker volume create todo-db
          

- Stop and remove the todo app container once again, as it is still running without using the persistent volume in the prevous blog post.

- Start the todo app container, but add the --mount option to specify a volume mount. Give the volume a name, and mount it to /etc/todos in the container, which captures all files created at the path.

docker run -dp 127.0.0.1:3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
          

- Verify that the data persists

- Dive into the volume

Use the inspect command to find out where Docker stores your data when using a volume.

docker volume inspect todo-db
          

You should see something like this in your console:

Docker volumes vs. Bind Mounts

Docker provides volumes and bind mounts, two mechanisms for persisting data in your Docker container. Check out a more detailed comparison in this blog post.

Bind Mounts

Bind mounts will mount a file or directory on to your container from your host machine, which you can then reference via its absolute path.

Docker Volumes

Docker volumes are completely handled by Docker itself and therefore independent of both your directory structure and the OS of the host machine. When you use a volume, a new directory is created within Docker’s storage directory on the host machine, and Docker manages that directory’s contents. Volumes are easier to back up or migrate than bind mounts.

Using Bind Mounts

A bind mount is another type of mount, which lets you share a directory from the host’s filesystem into the container. When working on an application, you can use a bind mount to mount source code into the container. The container sees the changes you make to the code immediately, as soon as you save a file. This means that you can run processes in the container that watch for filesystem changes and respond to them.

Development containers

Using bind mounts is common for local development setups. The advantage is that the development machine doesn’t need to have all of the build tools and environments installed. With a single docker run command, Docker pulls dependencies and tools.

- Run your app in a development container

docker run -dp 127.0.0.1:3000:3000 \
            -w /app --mount type=bind,src="$(pwd)",target=/app \
            node:18-alpine \
            sh -c "yarn install && yarn run dev"
        

When reviewing the Docker log, you will likely come across something similar to the following output. This is due to the inclusion of nodemon in the shipped application, which serves as a convenient monitoring script for Node.js app development purposes. Check out the nodemon official documentation for more information.

docker logs -f CONTAINER_ID
          
$ nodemon src/index.js
            [nodemon] 2.0.20
            [nodemon] to restart at any time, enter `rs`
            [nodemon] watching path(s): *.*
            [nodemon] watching extensions: js,mjs,json
            [nodemon] starting `node src/index.js`
            Using sqlite database at /etc/todos/todo.db
            Listening on port 3000
            

- Develop your app with the development container

In the src/static/js/app.js file, on line 109, change the “Add Item” button to simply say “Add” (You can change whatever you want, but we are just changing the text of the button for this example):

- {submitting ? 'Adding...' : 'AddItem'}
+ {submitting ? 'Adding...' : 'Add'}

Each time you make a change and save a file, the nodemon process restarts the app inside the container automatically and bind mount persist your data.

Conclusion

Although Docker provides two mechanisms for persisting data in your Docker container, Volumes are the preferred mechanism for persisting data generated by and used by Docker containers.Volumes have several advantages over bind mounts:

  • Volumes are easier to back up or migrate than bind mounts.
  • Volumes can be more safely shared among multiple containers.
  • New volumes can have their content pre-populated by a container.

Source