Where are Docker Images, Containers and Volumes Stored on the Linux Host System?
Want to know where Docker images, containers and volumes are located?
In a typical Linux environment, you can find the Docker image and container data in:
/var/lib/docker/
If your server is running out of space, you should definitely take a look into this directory.
Primarily, all Docker related entities are located at /var/lib/docker
. But let us look into it more specifically, with the Alpine image and container as a hands-on example.
Docker images location
Whenever you use the docker pull
command or run docker-compose up -d
to prepare the launch of applications, this is where images are stored on an Ubuntu server:
/var/lib/docker/overlay2
Here, Overlay2 is the default Docker storage driver on Ubuntu. You can confirm this by running the docker info
command and looking for the Storage Driver:
...
Storage Driver: overlay2
...
If this is different than yours, then you're using a different storage driver for Docker. Likewise, the directory location would be named as per the same storage driver. Availability of the storage driver depends upon kernel support.
Specific image locations
If you are looking for the locations of specific images, you can use the inspect command on Docker for the pulled image.
Say, for example, I've pulled the alpine image with docker pull alpine
. Run the following command to inspect it:
avimanyu@iborg-desktop:~$ docker inspect alpine
Once you run the command, you'll notice three fields inside the Data
subsection under GraphDriver
:
...
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/64c9c0cf8c9cfb0e2168071df0652a317d49f58a68fe86e4a9a9a525ab9e365e/merged",
"UpperDir": "/var/lib/docker/overlay2/64c9c0cf8c9cfb0e2168071df0652a317d49f58a68fe86e4a9a9a525ab9e365e/diff",
"WorkDir": "/var/lib/docker/overlay2/64c9c0cf8c9cfb0e2168071df0652a317d49f58a68fe86e4a9a9a525ab9e365e/work"
},
...
All the above directory paths are the physical locations of the alpine image on the host system. Do take a note of the large hash named directory in the three fields above: 64c9c0cf8c9cfb0e2168071df0652a317d49f58a68fe86e4a9a9a525ab9e365e
.
In total, there are actually four types of fields:
LowerDir: These are the read-only layers of an overlay filesystem. For docker, these are the image layers assembled in order.
UpperDir: This is the read-write layer of an overlay filesystem. For docker, that is the equivalent of the container specific layer that contains changes made by that container.
WorkDir: This is a required directory for overlay, it needs an empty directory for internal use.
MergedDir: This is the result of the overlay filesystem. Docker effectively chroot's into this directory when running the container.
Quoted from this reference (good for further reading).
Docker containers' location
Like images, containers are also stored inside the same storage driver based directory.
/var/lib/docker/overlay2
Specific container locations
If you are looking for the locations of specific containers, you can again use the inspect
command on the running container.
Say, for example, I've run the alpine container with docker run -ti -d alpine
. When you run docker ps
, you'll see that it's running:
avimanyu@iborg-desktop:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb341d6a28fa alpine "/bin/sh" 6 seconds ago Up 5 seconds confident_banzai
Here, the container has been randomly named confident_banzai
. So let's inspect it:
avimanyu@iborg-desktop:~$ docker inspect confident_banzai
Once you run the above command, you'll notice all the four fields mentioned earlier inside the Data
subsection under GraphDriver
. These directories are where the container data is physically located on your host system:
...
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/d734685e284c92bdcb6063ac292a48813f30f4b0b2dd6fa2882279c569e506a3-init/diff:/var/lib/docker/overlay2/64c9c0cf8c9cfb0e2168071df0652a317d49f58a68fe86e4a9a9a525ab9e365e/diff",
"MergedDir": "/var/lib/docker/overlay2/d734685e284c92bdcb6063ac292a48813f30f4b0b2dd6fa2882279c569e506a3/merged",
"UpperDir": "/var/lib/docker/overlay2/d734685e284c92bdcb6063ac292a48813f30f4b0b2dd6fa2882279c569e506a3/diff",
"WorkDir": "/var/lib/docker/overlay2/d734685e284c92bdcb6063ac292a48813f30f4b0b2dd6fa2882279c569e506a3/work"
},
"Name": "overlay2"
},
...
Reference for further reading.
The above directories are the physical locations of your container data inside the host system. Remember the large hash-named directory: 64c9c0cf8c9cfb0e2168071df0652a317d49f58a68fe86e4a9a9a525ab9e365e
from the Docker Images section? The directory under it is called diff
, as you can see in the LowerDir
section after :
, which is now a mount point for the container - fetched from the base image UpperDir
!
These directories will continue to be available even after you stop the container. So, the complete path which is common between the image (MergedDir
, UpperDir
and WorkDir
) and the container (LowerDir
mount point) is:
/var/lib/docker/overlay2/64c9c0cf8c9cfb0e2168071df0652a317d49f58a68fe86e4a9a9a525ab9e365e/
The purpose of the image is contiguous after assigning itself to the container upto the LowerDir
level, which is why the four fields are allocated and based on a different directory (with a new hash) because of the dynamic nature of the latter, which becomes:
/var/lib/docker/overlay2/d734685e284c92bdcb6063ac292a48813f30f4b0b2dd6fa2882279c569e506a3/
Docker volumes location
Unlike Docker images and containers, the physical locations for volumes is pretty straightforward. Volumes are located at:
/var/lib/docker/volumes/
Specific Volume Locations
In this case, there are two types primarily. One is regular Docker volumes and the other is bind mounts.
Docker Volumes
If you are looking for the locations of specific volumes, you can use the docker volume ls
command first and check the volume name or ID.
For example, I've run the alpine container with the following command with a volume:
avimanyu@iborg-desktop:~$ docker run -ti -d --name alpine-container -v test-data:/var/lib/app/content alpine
Now, a volume named test-data
will automatically get created. Let's now create a file named test.md
inside this location:
avimanyu@iborg-desktop:~$ docker exec alpine-container sh -c "touch /var/lib/app/content/test.md"
Verify the file has indeed been created:
avimanyu@iborg-desktop:~$ docker exec -ti alpine-container sh
/ # ls /var/lib/app/content/
test.md
/ # exit
When you run docker volume ls
, the volume named test-data
would be listed:
avimanyu@iborg-desktop:~$ docker volume ls
DRIVER VOLUME NAME
local d502589845f7ae7775474bc01d8295d9492a6c26db2ee2c941c27f3cac4449d1
local e71ee3960cfef0a133d323d146a1382f3e25856480a727c037b5c81b5022cb1b
local test-data
Finally, you can confirm the actual location of the file on your host system:
avimanyu@iborg-desktop:~$ sudo ls -l /var/lib/docker/volumes/test-data/_data
total 0
-rw-r--r-- 1 root root 0 Oct 6 23:20 test.md
Therefore, the path for the mounted volume is always located inside a directory named _data
inside the respective volume directory.
You can also check such paths the Docker way by using the docker volume inspect
command followed by the volume name or ID and looking into the Mountpoint
parameter within the output:
avimanyu@iborg-desktop:~$ docker volume inspect test-data
[
{
"CreatedAt": "2021-10-06T23:20:20+05:30",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/test-data/_data",
"Name": "test-data",
"Options": null,
"Scope": "local"
}
]
Bind Mounts
Locations of bind mounts is pretty obvious and even more straightforward because you mount the volume directly from a host side location:
avimanyu@iborg-desktop:~$ mkdir /home/avimanyu/test-data
avimanyu@iborg-desktop:~$ docker run -ti -d --name alpine-container -v /home/avimanyu/test-data:/var/lib/app/content alpine
In this case, a bind mounted volume named test-data
will become available on the container side as /var/lib/app/content
.
Summary
In this quick tutorial, I've taken a generic Linux based approach to show the physical locations of Docker images, containers and volumes residing on your Linux server (Ubuntu 20.04 in this case) at the host level.
If you want to share any feedback, comment or suggestion towards this approach, please leave your thoughts in the comment section below.