Docker Images Under the Hood
Ever since I have heard about containers technology, I have had a foggy understanding of Docker images. The terms layered-architecture, and multi-layer build have never made much sense to me, like I could comfortably write a dev-docker image or a deployment docker image, however I was never satified, sense my mental model of how it all works under-the-hook was not fully constructed.
File-system mounts:
Before we dive deeper into our topic, we must build a good understanding of what are file-system (FS) mounts and how they work. If you are already comfortable with these concepts please feel free to move to the next section.
Unlike on Windows where disk-partitions would have letters names, like :C and :D. On Unix (and Unix-like) operating systems, An installation would have a single root (/), and all the partitions would be mounted (attached) to one of its directories, forming a tree-like structure.
When we need access a file-system, for example a flash-drive or a remote directory(for example NFS). We must first mount it onto our file-system tree. Before we could access its content. However the mounting part must happen on an existing directory, whose contents will be shadowed by the mounted fs. Where we won’t have access to it until that fs is detached (unmounted).
Lets have a visual example since it would make it easier to digest:
- Here’s our file system hierarchy before mounting.
/
/ \
etc mount
| |
vim a
- and we want to mount the follwing fs under the mount directory.
N
/ | \
H W L
- After mounting, the hierarchy looks like this:
/
/ \
etc mount
| / | \
vim H W L
We can see that the new file system is mounted under the /mount directory. However, its original content (or namespace) is shadowed by the attached file system and won’t be accessible until the file system is unmounted.
Union-Mounts:
Union mounts are a special type of mount, where they do the exact opposite of what regular mounts do, instead of shadowing and hiding the older namesapce with the newer one. It would merge both (or all of them when more than two dirs are mounted) namespaces (content), by showing a combination of both file-systms.
The basic idea of using unions-mounts, is to have a root or basic read-only, and lay on top of it multiple layers(over-lays) or simply directories where you make modifications.
Let’s use a visual example as we did with regular mounts:
- Here’s our root file system:
/
/ \
etc mount
| / \
vim L j
- We want to mount the following file system onto /mount:
R
/ / \ \
A L' K j
- The union mount of these would look like this:
\
/ \
etc mount
| / | \
vim A L' K
Notice how L and L' (a modified version of L) are merged. Since the root file system is considered read-only, the mounted directory’s content takes precedence. This is the general concept of union mounts.
Tieing Everyting back to Images:
We can say that Docker images are simply a READ-ONLY root (minimal Linux file systems), and each command in the docker file, is an overlay (modification) layered on top of the file-system. And Building an image from a Dockerfile is essentially performing union mounts on top of the root file system.
This is far from the whole story of docker iamges, but it is a great abstraction to have in mind.
Last words:
This article does not try to explain word-for-word or line-for-line the implementation of Docker imagaes, where is it provides a high-level understanding and concepts that the framework was built upon, this most likely the first article in a series that would explore containers in great detials.
References
- Union mounts in practice
- The concept of union mounts
- Unix and Linux System Administration Handbook