Docker essentials – More work with images

Images – Messing with the stack
So we’ve had some time to digest what containers and images are.  Now let’s talk in a little greater detail about images and how they layer.  A key piece of docker is how the images stack.  For instance, let’s quickly build a container that has 3 user image layers in it.  Recall, images are the read-only pieces of the container so having 3 user layers implies that I have done 3 commits and any changes after that will be in the 4th read/write layer that lives in the container itself…

Note: Im using the term ‘user images’ to distinguish between base images and the ones that I create.  We’ll see in a minute that a base image can even have multiple images as part of the base.  I’m also going to use the term ‘image stack’ to refer to all of the images that are linked together to make a running image or container. 


I’ve highlighted each user image creation to break it out.  Essentially this is what happened…

-Ran the base CentOS image creating a container called stacking
-Created a file in the container called file1
-Committed the container to an image called local/stack:1

-Ran the user image local/stack:1 creating a container called stacking1
-Created a file in the container called file2
-Committed the container to an image called local/stack:2

-Ran the user image local/stack:2 creating a container called stacking2
-Created a file in the container called file3
-Committed the container to an image called local/stack:3

-Ran the user image local/stack:3 creating a container called stacking3
-Created a file in the container called file4

As you can see, all of the files are there from each separate container that I’ve built along the way.  Let’s look at the tree for this image and see what the image stack looks like…


Let’s also take a look at the images we created so we can see the image IDs the chain references…


So this is sort of interesting.  The base image we used to create these containers doesn’t appear to actually be the base of the image set.  I used centos:latest to make my first container but it appears that there are two other images referenced before the base that I used…


Notice how the first two containers just list the image ID and no name?  Those appear to be the base images associated with the centos image.  So it appears that even base images have base images (if that makes any sense).

Note: I had to rebuild the lab at this point so the image IDs from this point on are different than the ones shown above 

So now let’s talk about deleting images.  Docker tracks both image and container dependencies. It does this so it can enforce the golden rule of docker images. Only the topmost image (this includes a containers read/write layer if its present) can ever be removed from an image stack.  To make this more clear, lets get rid of all of the active containers so we’re left with only the images.  I’m going to use a handy command to delete all stopped containers…


So now that all of the containers are gone, I’m working with just images.  Let’s attempt and remove the image ‘local/stack:2’ from the chain…


Notice how docker reports that it untagged the image?  From what I can tell, untagged means that docker is essentially flagging an image as being deletable.  That is, once all dependencies are removed, docker will automatically clear up any untagged images.  Let’s prove this by deleting the only dependency at this point which is ‘local/stack:3’…


Ah ha!  Docker knows that since you deleted ‘local/stack:3’ there aren’t any other images that depend on ‘local/stack:2’ any more.  So when you delete the top layer image, docker takes the extra step of cleaning up any untagged images that are no longer dependencies of other images.  We can see that both local images 2 and 3 were deleted by referencing their image IDs. 

Images – Moving them around and squashing them
So now that we have some images we created, what happens when I want to share them?  Docker has the repository feature which allows you upload and download images, but let’s talk about manually moving them as this leads nicely into the last topic I want to cover in this post.

Let’s create a new container called ‘mystuff’ based off of the image local/stack:1.  We’ll add back file2 and then quit the container…


So now let’s say I’ve convinced myself here that what I’ve done is pure genius and I want to share this with my good friend Bob.  So the 4 commands I’m interested in here are import, export, load, and save.  Import and export deal with containers while load and save deal with images.  Let’s do an example of both and see what happens…


So like I said, the export works with containers so I export the container.  The save works on images so I have to specify the most recent image used to build the container.  I think we can assume that the changes I made in the container wont exist in the saved file.  Note that each file is around 130 megabytes.  That’s quite sizeable.  Let’s send them over to Bob and see what he can do with them…


Notice how Bob is importing the export of my container with the end result being a image.  Interesting.  Let’s have Bob try running the image and see what he gets…


Interesting, so all of the files I made are here and I didn’t get any prompts about having to download the base centos image which the container is based on.  Looking at the images on Bob’s machine, its pretty apparent that all of the images have been collapsed into this new image.  A view of the image tree and history confirms this…


Ok, so it looks like import and export might be a handy way to compress image stacks, but we are losing all of the information about where the data came from when we do that.  We’re also collapsing the base image into the user image at that point.   Let’s try a load on the save data I sent Bob…


Interesting.  So the loaded data seemed to preserve most of the data about the initial images.  We can see that all of the images are still broken out and linked as they were on my docker instance.  However, I seem to have lost the names and tags related to the images.  I’m wondering if this is a bug because the rest of the meta data is showing up, for instance the image history…


So I think we can summarize that export creates an image of the respective container by copying the entire file system.  In this manner, all metadata about the image stack is lost and you end up with one image on import.  This appears to be the only way to squash images together at this point.  Save exports all the information that docker has on the current image stack so on load you end up with the exact same image stack. 

I’d like to see the ability to do a couple of other things (If these exist and I’m missing it please let me know!)..

-Run a save to export everything EXCEPT the base image.  There’s a good chance that Bob already has the base image.  So it would be handy to be able to send him only the changes I’ve made on top of the base.  This would greatly reduce the file size of the save as well.  From looking at the image IDs on both my machine and Bob’s, the base images have the same ID’s so it would just be a matter of linking the user images on top of the base once Bob got the data. 

-Squash images together selectively.  Again, it would be nice to keep the base images separate but squash all of the user images (or a subset of them) together into one image. 

So there you have, more fun with docker!

5 thoughts on “Docker essentials – More work with images

  1. frequency

    Excellent !!!. I was lost in so many docs …. your posts have kick started my understanding of docker.

    It would be great if your posts were more indexed based on topic

  2. Pingback: Docker Essentials | ProgClub

Leave a Reply

Your email address will not be published. Required fields are marked *