Skip to content

Docker Mounts

Spring Ep edited this page Sep 25, 2020 · 2 revisions

There are 3 ways to add additional storage to Docker containers:

  1. bind mounts
  2. volumes
  3. tmpfs

When we are creating a new container, we add the option --mount type=bind OR volume OR tmpfs

For example:

docker run -d --name nginx-mount \
--mount type=bind,src=/home/spring/example.conf,dst=/etc/nginx/conf.d/default.conf \
-p 8080:80 (-p host-port:container-port)
nginx:latest (name-of-the-image:tag)

src directive points to the location on the host's file system, while dst defines where on the container's file system tree will the src be mounted. ( important: dst is a mounting point on the container)

Bind mounts

Bind mounts can be mounted as readonly, by using readonly=true. For example:

docker run -d --name nginx-mount-ro \
--mount type=bind,src=/home/spring/example.log,dst=/var/log/nginx/custom.host.access.log,readonly=true
-p 8080:80
nginx:latest

When we add the bind mount to a mounting point that already contains some files (in our case, the location for the Nginx config files already has some default values written there), bind mount will overwrite them.

Why we shouldn't use bind mounts?

Bind mounts have several disadvantages. First, they make the container dependant on the specific host's file system, which makes them difficult to be moved around. Second, if we have several instances of any DB image running with the same configuration (they share the configuration which specifies the mount point for the storage), there will be a conflict between these containers because they'll be trying to write to the same location on the host's FS.

When should we use bind mounts?

That's a good question. I'm not sure if you should use it at all. The book says:

workstations, machines with specialized concerns, or in systems combined with more traditional configuration management tooling

tmpfs

tmpfs is a memory-based filesystem. It is based on the code for ramfs that executes during the boot, but it has additional feature - it can swap less-used pages to a swap space, so it's not neccesseraly kept in RAM. This means that the size of /tmp is not limited by the size of RAM, but the size of virtual memory. (virtual memory - when kernel uses hard-disk as an extension to RAM. This is known as swap space. We can implement it as a swap file, or a swap partition.)

docker run --rm \
--mount type=tmpfs,dst=/tmp \
--entrypoint mount \
alpine:latest -v

--rm flag will cause the Docker to remove the container and to clean up the filesystem after the container exits. (By default, the container's filesystem persists even after the container exits and you retain all the data by default. For short foreground processes, it's better to remove them automatically with the --rm flag).

The docker command that we added above, has a verbose mode (-v), and it will show us additional information about the mounting points. In our case, it will show:

tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,relatime)

rw = read-write
nosuid = ignore setuid and setgid bits
nodev = no files in this filesystem tree will be interpreted as characters and block devices
noexec = none of the files in this filesystem will be executable
relatime = Update inode access times relative to modify or change time. Access time is only updated if the previous access time was earlier than the current modify or change time.

// every inode has 3 timestamps:
// 1. access time - the last time that the file was read, e.g. cat file.txt
// 2. modify time - the last time the content of the file was modified, e.g. vi file.txt
// 3. change time - the last time metadata of the file was changed, e.g. changing permissions, suid, gid,...
// we can see all these 3 timestamps with stat file.txt