Let’s take a look at Bind Mounting in Docker and how persistent data works with those mounts. Bind Mounts are a little different than Docker Volumes, however the syntax to use them is quite similar. Bind Mounts are really cool since they allow local development with files on your host to update in real-time in a container. Technically, a Bind Mount is a mapping of the host files or directories into the container’s files or directories. So you can specify just a single file or an entire directory. In the background, it is like the location on the host and the location on the container is pointing to the same location on disk.
Bind Mount Example One
First, let’s create a directory on the host machine. We’ll name the directory host, then cd into that directory.
PS C:\code> mkdir host PS C:\code> cd host PS C:\code\host>
Ok, we have an empty directory of host
that we are now working in. Now let’s run a container from the alpine image, and set up a bind mount between the host and container. The bind mount syntax is in blue and the ${pwd} to the left of :
simply means, use the current working directory as the host directory. To the right of :
is the directory in the container we are mapping to.
PS C:\code\host> docker container run -it --name alpine -v ${pwd}:/container alpine
Look at how the running container has a directory named container right away. When creating a bind mount in Docker, if you specify a directory in the container that is not already there, it is created for you.
/ # ls -l total 56 drwxr-xr-x 2 root root 4096 Oct 21 09:23 bin drwxrwxrwx 1 root root 4096 Oct 23 16:24 container drwxr-xr-x 5 root root 360 Oct 23 16:29 dev drwxr-xr-x 1 root root 4096 Oct 23 16:29 etc drwxr-xr-x 2 root root 4096 Oct 21 09:23 home drwxr-xr-x 7 root root 4096 Oct 21 09:23 lib drwxr-xr-x 5 root root 4096 Oct 21 09:23 media drwxr-xr-x 2 root root 4096 Oct 21 09:23 mnt drwxr-xr-x 2 root root 4096 Oct 21 09:23 opt dr-xr-xr-x 176 root root 0 Oct 23 16:29 proc drwx------ 1 root root 4096 Oct 23 16:29 root drwxr-xr-x 2 root root 4096 Oct 21 09:23 run drwxr-xr-x 2 root root 4096 Oct 21 09:23 sbin drwxr-xr-x 2 root root 4096 Oct 21 09:23 srv dr-xr-xr-x 11 root root 0 Oct 23 16:29 sys drwxrwxrwt 2 root root 4096 Oct 21 09:23 tmp drwxr-xr-x 7 root root 4096 Oct 21 09:23 usr drwxr-xr-x 12 root root 4096 Oct 21 09:23 var
Change into the container directory and list out the files, we see there are none.
/ # cd container /container # ls /container #
Open a new instance of your terminal since the current instance is now connected to the running container. Navigate to the host directory that we created already. Note that it is empty.
PS C:\code\host> ls PS C:\code\host>
Create a file on the host machine in the host directory and note that it now exists in that host directory.
PS C:\code\host> echo 'Created on host machine!' >> file1.txt PS C:\code\host> ls Directory: C:\code\host Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 10/23/2020 12:37 PM 54 file1.txt
Navigate back to the original terminal that is still connected to the running container. List the files in that container directory.
/container # ls file1.txt /container # cat file1.txt Created on host machine!
Whoa! The file exists in the container thanks to the bind mount we had set up. That is really cool. Now let’s create another file on the container and see what happens.
/container # echo 'File created on container!' > file2.txt /container # ls file1.txt file2.txt
Navigate back to the terminal for working on the host where we can list out the files, and we can see that the file created on the container is now also present in the host.
PS C:\code\host> ls Directory: C:\code\host Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 10/23/2020 12:37 PM 54 file1.txt -a---- 10/23/2020 12:42 PM 27 file2.txt PS C:\code\host> cat file2.txt File created on container!
This is really interesting and you can start to see how this would be really beneficial to you when working with containers. You can really map anything you want from the host into the container. This concept is very helpful when you start talking about development on the host machine while running services on the container that are accessing files you may be editing on the host. As you make changes to files on the host, these are reflected in real-time within the container.
Bind Mount Example Two
The first example was as basic as we could possibly make it just to show the syntax of a bind mount and how it works. Let’s now look at an example that uses an Nginx web server in a container, that is able to serve HTML files you are editing on the local machine. Place this index.html file in the host directory like so:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Bootstrap CSS -->
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha2/css/bootstrap.min.css"
integrity="sha384-DhY6onE6f3zzKbjUPRc2hOzGAdEf4/Dz+WJwBvEYL/lkkIsI3ihufq9hk9K4lVoK"
crossorigin="anonymous"
/>
<title>Hello, world!</title>
</head>
<body class="container mt-5">
<div class="card">
<div class="card-body">
<h1 class="card-title">Hello World!</h1>
<h3 class="card-subtitle mb-2 text-muted">Docker Bind Mounts</h3>
<p class="card-text">
Now we know how to use Docker Bind Mount with the Nginx web server.
</p>
</div>
</div>
<!-- Optional JavaScript; choose one of the two! -->
<!-- Option 1: Bootstrap Bundle with Popper.js -->
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha2/js/bootstrap.bundle.min.js"
integrity="sha384-BOsAfwzjNJHrJ8cZidOg56tcQWfp6y72vEJ8xQ9w6Quywb24iOsW913URv1IS4GD"
crossorigin="anonymous"
></script>
<!-- Option 2: Separate Popper.js and Bootstrap JS
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha2/js/bootstrap.min.js" integrity="sha384-5h4UG+6GOuV9qXh6HqOLwZMY4mnLPraeTrjT5v07o347pj6IkfuoASuGBhfDsp3d" crossorigin="anonymous"></script>
-->
</body>
</html>
Confirm we have a new file in our host directory.
PS C:\code\host> ls Directory: C:\code\host Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 10/23/2020 1:21 PM 1758 index.html
First, let’s just run an Nginx container with no bind mount and see what that gives us. We can name this container nginx1.
PS C:\code\host> docker container run -d --name nginx1 -p 80:80 nginx c659e507bbc714ec3beb4e78acac2f232f9d9753614286dae143a0cc1b6a3817
Visiting the container in a browser shows us the Nginx splash screen. The container is not making any use of any files from the host machine.
Now let’s run a second container named nginx2 but this time we want to make use of a Bind Mount. Again the part of the command that specifies the bind mount is in blue.
docker> docker container run -d --name nginx2 -p 80:80 -v ${pwd}:/usr/share/nginx/html nginx
933bd7033cc370133f4b4e5475036610589e9424248d212d7d812f1c4ef7b852
We have two web servers running now. The first uses port 80 without a bind mount. The second uses port 8080 and is using a bind mount. We can see that the second web server is using the file from the localhost in the container. Very cool!
The great thing about this is that changes on the host are reflected in real-time into the container. Let’s make a change to the source code of index.html. Note the highlighted line that is changed.
<div class="card">
<div class="card-body">
<h1 class="card-title">Have A Great Day!</h1>
<h3 class="card-subtitle mb-2 text-muted">Docker Bind Mounts</h3>
<p class="card-text">
Now we know how to use Docker Bind Mount with the Nginx web server.
</p>
</div>
</div>
Reload the browser that is connected to the container, and voila, the updates happen right away.
More About Bind Mounts
- Docker Storage Bind Mounts (docs.docker.com)
- Visualstudio Docker Tutorials Use Bind Mounts (docs.microsoft.com)
- Docker Volumes Bind Mounts (codereviewvideos.com)
- Using Bind Mounts In Docker Containers (atifazad.com)
- Docker Volumes Bind Mounts And Existing Data (rakhesh.com)
- How Bind Mount Works (geekylane.com)
Bind Mounts Summary
- You Can Persist Data With Bind Mounts
- Bind Mounts map a host file or directory to a container file or directory
- This is like having two locations pointing to the same file(s)
- Bind Mounds do not use UFS and host files overwrite any in container
- You must define them during docker container run, can’t be used in a Dockerfile
- …
run -v /Users/name/folder:/path/container
(mac/linux) - …
run -v //c/Users/name/folder:/path/container
(windows) - A Bind Mount allows you to attach an existing directory on your host to a directory inside of a container
- You can use $(pwd) or ${pwd} when specifying a bind mount with the run command. This runs the shell command to print the current working directory so you don’t have to type out the entire directory path.