Docker has generated alot of buzz lately and seems poised to fundamentally change how apps get deployed. With the apps I work on increasingly dependent on the environment (environmental vars, cron jobs and additional libraries) having a way of encapsulating my app and its environment is pretty appealing. With that in mind I’ve playing with docker for a little while but I found I had a hard time building a clear picture in my head of what is actually going on.
The tutorials all feel a little magical and a lot of the docs for the commands end up being stuff like “docker pull: pulls an image” which is pretty unsatisfying. So while I am still just getting started with Docker I thought I would share what I have pieced together so far and use it as an opportunity to explain this to myself as well.
The first thing to point out is that Docker is built on top of AuFS, Linux Containers (LXC), and cgroups (lots of details here). Doing some reading about those things first really helps understand what is going on.
While that is neat, I am a pretty visual person so for me to feel like I have any idea of what is going on I need to see it. So to do that I created my own image using the traditional debootstrap command:
☺ sudo debootstrap raring raring64 I: Retrieving InRelease I: Failed to retrieve InRelease I: Retrieving Release I: Retrieving Release.gpg ....
You can see it created a folder with the following sub-folders:
ls raring64/ bin dev home lib64 mnt proc run selinux sys usr boot etc lib media opt root sbin srv tmp var
Then we tar up the folder and piping it into dockers import command. This creates the image and prints out the hash id of the image before exiting:
☺ sudo tar -C raring64 -c . | sudo docker import - raring64 9a6984a920c9
If I dig I can then find those folders in the docker graph folder:
☺ sudo ls /var/lib/docker/graph/9a6984a920c9badcaed6456bfdef2f20a414b08ed09acfd9140f2124065697b2/layer bin dev home lib64 mnt proc run selinux sys usr boot etc lib media opt root sbin srv tmp var
I can then log into that image by asking docker to run interactively (-i) and give me a pseudo tty (-t). But notice the host name on the root prompt you get when you get docker to run bash (which changes each time):
☺ sudo docker run -i -t raring64 /usr/bin/env bash WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: [8.8.8.8 8.8.4.4] root@b0472d03f134:/# exit exit ☺ sudo docker run -i -t raring64 /usr/bin/env bash WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: [8.8.8.8 8.8.4.4] root@76c7860cf94e:/# exit exit
If I run some commands that change the state of that image and I want to keep them I will need to use the hash we can see in the host name to commit that change back to the graph directory. So for example, I installed git (with “apt-get install git”) and afterwards I commit the change:
☺ sudo docker commit 76c7860cf94e raring_and_git c153792e04b4
Sure enough this creates a new directory inside /var/lib/docker/graph/ that contains this difference between the original image (my raring64 image) and my new one with git:
☺ sudo ls /var/lib/docker/graph/ 27cf784147099545 9a6984a920c9badcaed6456bfdef2f20a414b08ed09acfd9140f2124065697b2 c153792e04b4a164b9eb981e0f59a82c8775cad90a7771045ba3c6daabc41f23 :tmp: 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc checksums ☺ sudo ls /var/lib/docker/graph/c153792e04b4a164b9eb981e0f59a82c8775cad90a7771045ba3c6daabc41f23/layer dev etc lib tmp usr var
It is the job of AuFS to take all the folders and files in the graph directory and sort of sum them into a single filesystem with all the files from raring64 + the new files that changed when I installed git. Docker can then use that filesystem as the base from which to run its namespaced process (similar to chroot).
All of this creates a pretty “git-like” experience where each hash represents a change set applied to a base set of files.
From here building out images takes one of two forms; give yourself an interactive bash session, make your changes and then commit them, or use a Dockerfile.
So this feels like a solid starting point in the world of Docker, and its a pretty exciting world. In fact I am looking forward to deploying my next app… how often can you say that?
Thank you for the article. It helped a lot to understand what is really going on with docker images.