Generic Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

While working with Docker containers, we often need to create various persistent objects, such as volumes and images. By default, these objects occupy disk space from the boot disk. This default configuration might cause some significant data issues, such as low disk space for other applications or data loss in case of hardware failure.

In this tutorial, we’ll discuss how to configure the Data Root Directory in a Docker. This allows us to change the image installation directory and mitigate the problems mentioned above.

2. Setting up an Example

Let's create a few persistent Docker objects to use as an example.

First, we'll pull the NGINX and Redis images:

$ docker image pull nginx
$ docker image pull redis

Let's verify they're pulled ok:

$ docker image list 
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    76c69feac34e   2 weeks ago   142MB
redis        latest    c2342258f8ca   2 weeks ago   117MB

Next, we'll create a volume and find its mount point:

$ docker volume create dangling-volume

$ docker volume inspect dangling-volume -f '{{ .Mountpoint }}'
/var/lib/docker/volumes/dangling-volume/_data

Finally, let's create a sample file inside a /var/lib/docker/volumes/dangling-volume/_data directory:

$ echo "Dangling volume" | sudo tee /var/lib/docker/volumes/dangling-volume/_data/sample.txt

$ sudo cat /var/lib/docker/volumes/dangling-volume/_data/sample.txt
Dangling volume

In the next section, we’ll see how to change the Docker Root Directory to store such persistent objects at a different location.

3. Changing the Image Installation Directory

In Docker, the image installation directory is denoted by the DockerRootDir property. We can find its value using the info child command:

$ docker info -f '{{ .DockerRootDir }}'
/var/lib/docker

In this example, the /var/lib/docker directory from the boot disk represents the Docker Root Directory.

Now, let's discuss the various methods to change this default root directory.

3.1. Using the Daemon Configuration File

We can change the default root directory by updating the daemon configuration file. The default location of this configuration file on Linux is /etc/docker/daemon.json.

So, let's create a new directory and configure it as the root directory by editing the daemon configuration file:

$ mkdir -p /tmp/new-docker-root
$ sudo vi /etc/docker/daemon.json

Then we edit the file so it has a data-root pointing to the newly created directory. When we’ve saved it:

$ sudo cat /etc/docker/daemon.json
{ 
   "data-root": "/tmp/new-docker-root"
}

Finally, we must restart the docker service and check the updated root directory using the info child command:

$ sudo systemctl restart docker
$ docker info -f '{{ .DockerRootDir}}'
/tmp/new-docker-root

Now, we can see that Docker Root Directory is set to /tmp/new-docker-root.

3.2. Restoring the Default Configuration

In the previous section, we changed the default configuration by updating the daemon configuration file. However, we must restore it to the previous state before moving to the next section.

First, we reset the settings to default by removing the daemon configuration file and /tmp/new-docker-root directory:

$ sudo rm /etc/docker/daemon.json
$ sudo rm -rf /tmp/new-docker-root/

Next, we must restart the docker service for changes to take effect:

$ sudo systemctl restart docker

Finally, we can verify that the Docker Root Directory is set to its default location:

$ docker info -f '{{ .DockerRootDir}}'
/var/lib/docker

3.3. Using the systemd Configuration File

Similarly, we can also modify the systemd configuration of the docker service to achieve the same result. Docker uses the/lib/systemd/system/docker.service unit file to store its configuration. Let's look at how to update this file.

First, we'll create a new directory and update the ExecStart property from the /lib/systemd/system/docker.service file:

$ mkdir -p /tmp/new-docker-root/
$ sudo vi /lib/systemd/system/docker.service

Now, the updated file looks like this:

$ grep ExecStart /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --data-root /tmp/new-docker-root -H fd:// --containerd=/run/containerd/containerd.sock

In this example, we have configured the Docker Root Directory using the –data-root /tmp/new-docker-root property.

Next, we must reload the unit file and restart the docker service for changes to take effect:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

Finally, let's check the updated data root directory using the info child command:

$ docker info -f '{{ .DockerRootDir}}'
/tmp/new-docker-root

Here, we can see that the data root directory is pointing to the /tmp/new-docker-root location.

3.4. Limitation

In the previous sections, we saw how to change the Docker Data Root directory. However, just changing the data root properly is not sufficient. Because this configuration doesn't locate previously created persistent objects.

To understand this, let's list the images and volumes:

$ docker image list
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

$ docker volume list
DRIVER    VOLUME NAME

As we can see, Docker is unable to locate images and volumes from the previous data root directory.

4. Migrating the Persistent Objects

For a complete solution to changing our persistent object location, we may also wish to migrate the existing objects.

4.1. Copying Data Using the rsync Command

rsync is a command line utility that copies and synchronizes files and directories in an efficient way. We can use this command to copy the contents from the /var/lib/docker directory:

Let's copy the data using the rsync command and restart the docker service:

$ sudo rsync -aqxP /var/lib/docker/ /tmp/new-docker-root
$ sudo systemctl restart docker

In this example, we have used the following:

  • a option to enable the archive mode
  • q option to suppress non-error messages
  • x option to avoid crossing a filesystem boundary while copying directories recursively
  • P option to preserve partially copied files/directories

Now, let's list the images and volumes:

$ docker image list
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    76c69feac34e   3 weeks ago   142MB
redis        latest    c2342258f8ca   3 weeks ago   117MB

$ docker volume list
DRIVER    VOLUME NAME
local     dangling-volume

As we can see, Docker is now able to identify the previously created persistent object.

4.2. Restoring the Default Configuration

First, let's stop the docker service and remove the –data-root property from the /lib/systemd/system/docker.service unit file:

$ sudo systemctl stop docker 
$ sudo vi /lib/systemd/system/docker.service

After modification, the unit file looks like this:

$ grep ExecStart /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Now, we'll reload the unit file, restart the docker service, and check the updated data root directory:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

$ docker info -f '{{ .DockerRootDir}}'
/var/lib/docker

5. Conclusion

In this article, we saw how to change the image installation directory in Docker by configuring the data-root property.

First, we used the daemon configuration file to change the Docker Root Directory. Next, we discussed how to achieve the same result using the systemd unit file. Then, we discussed the limitation imposed by these methods.

Finally, we discussed how to overcome these limitations by migrating persistent objects.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Generic footer banner
Comments are closed on this article!