‫Alright, in this lecture we're going to talk about image layers.
‫So this is a fundamental concept of how Docker works. It uses something called the union file system
‫to present a series of file system changes as an actual file system.
‫We're going to dive into the history and inspect commands and see how we can use them to understand
‫what an image is actually made of. We're going to learn a little bit about the copy on write concept
‫of how a container runs as an additional layer on top of an image.
‫What do I mean by image layers?
‫It's actually transparent completely to you when you're using Docker, but when you start digging into
‫certain commands, like the history command, the inspect and commit, you start to get a sense that an image
‫isn't some big blob of data that comes and goes in one huge chunk.
‫Right?
‫If you notice when we actually did Docker pulls, certain times you might see words that indicate that
‫there's something that you already have, like you've cached some part of it already, and that all comes
‫down to the fact that images are designed using the union file system concept of making layers about
‫the changes.
‫If we could quickly just look at what we have in Docker...in Docker images actually...
‫A while ago, we were playing around with the tags with Nginx. Right? We remember that the Nginx
‫image ID is the same and we had different tags for the same image name.
‫So let's do a quick docker history on nginx latest.
‫What am I looking at here?
‫This is not a list of things that have actually happened in the container because this is about an image.
‫This is actually a history of the image layers.
‫Every image starts from the very beginning with a blank layer known as scratch.
‫Then every set of changes that happens after that on the file system, in the image, is another layer.
‫You might have one layer, you might have dozens of layers and some layers maybe no change in terms
‫of the file size.
‫You'll notice on here that we actually have a change here that was simply a metadata change about
‫which command we're actually going to run. We'll cover that in a little bit when we go over the
‫Dockerfile.
‫But, for now, you can actually see that this one added a huge amount of files that was 123MB.
‫Then we made a change here and a change here and I happen to know because of Dockerfiles that these
‫are really just Dockerfile metadata information.
‫As you go up, we have some more data changes.
‫You'll see that this is actually quite different in another image.
‫So if we go to docker history mysql, it has a completely different set of image layers.
‫Let me draw this a little bit for you and maybe this will help.
‫When we start an image, when we were creating a new image,
‫we're starting with one layer. Every layer gets its own unique SHA that helps the system identify
‫if that layer is indeed the same as another layer.
‫Let's just say that at the beginning of one of yours, you might have Ubuntu at the very bottom.
‫That's the first layer in your image.
‫Then you create a Dockerfile, which adds some more files and that's another layer on top of that
‫image. Maybe we use Apt for that.
‫Then in your Dockerfile, you make an environment variable change. That together is your image.
‫OK?
‫You might have a different image that starts from debian:jessie and then on that image you may also
‫use Apt to install some stuff,
‫let's say MySQL. You might copy some files over, you might open a port.
‫So each one of these changes that you usually make in the Dockerfile, but you can also make with the
‫commit docker command that we'll check out in a minute.
‫This is also another image and those are all bundled together.
‫What happens if I have another image that's also using the same version of jessie?
‫Well, that image can have its own changes
‫on top of the same layer that I have in my cache. This is where the fundamental concept of the cache
‫of image layers saves us a whole bunch of time and space. Because we don't need to download layers we
‫already have, and remember it uses a unique SHA for each layer so it's guaranteed to be the exact
‫layer it needs. It knows how to match them between Docker Hub and our local cache. As we make changes
‫to our images, they create more layers.
‫If we decide that we want to have the same image be the base image for more layers, then it's only
‫ever storing one copy of each layer.
‫In this system, really, one of the biggest benefits is that we're never storing the same image data
‫more than once on our file system.
‫It also means that when we're uploading and downloading we don't need to upload and download the same
‫layers that we already have
‫on the other side. If you were to have your own image and it was custom that you made yourself, and then
‫you added, let's say, an Apache server on top of that as another layer in your Dockerfile, and then you were
‫to open up port 80. Then, at the very end, you actually told it to copy in the source code but you
‫actually ended up having two different Dockerfiles for two different websites, and every line in the Dockerfiles
‫were the same except for that last little bit where you copied Website A into the image and
‫then Website B, you would end up with two images. We'll show that in a minute. This makes up one image
‫and this makes up one image, but the only files that are actually stored is this one,
‫this one, this layer and then this little layer and then this little layer.
‫So we're never storing the entire stack of image layers more than once if it's really the same layers.
‫How does this work with containers?
‫If you have your image, let's say we have our Apache image, and we decide to run a container off of
‫it, all Docker does is it creates a new read/write layer for that container
‫on top of that Apache image. When we're perusing the file system and these things, all the containers
‫and the images all just look like a regular file system, but underneath the storage driver that's used
‫by Docker is actually layering, like a stack of pancakes,
‫all these changes on top of each other.
‫So if I ran two containers at the same time off of the same Apache image, container 1 and container 2
‫would only be showing, in terms of the file space, they would only be the differencing between what's
‫happened on that live container running and what is happening in the base image, which is read-only.
‫When you're running Containers and you're changing files that were coming through the image, let's
‫say I started container 3, and I actually went in and changed a file that was in this image in the running
‫container...
‫this is known as copy-on-write.
‫What that does is the file system will take that file out of the image and copy it into this differencing...
‫up here... and store a copy of that file in the container layer.
‫So now the container is really only just the running process
‫and those files that are different than they were in the Apache image.
‫If we go back to our image list and we look at these commands again, and we look at the bottom one
‫and see how the dates are different? We can actually see as this image got changed in Docker Hub and was
‫updated over time, that these changes haven't been changed
‫at the very bottom layer in four weeks and then the latest changes have been happening in the last
‫two weeks.
‫Oh by the way, don't worry about the missing part.
‫That's actually just a misnomer inside the Docker interface.
‫It doesn't mean that something's wrong or it's misconfigured. What it means is that really, this mysql
‫image right here is this image ID.
‫The other layers in the image aren't actually images themselves.
‫...
‫They're just layers inside this image,
‫and so they wouldn't necessarily get their own image ID there.
‫Personally, I think it's a little misleading in the interface to say that, but that's how they wrote it.
‫So now that we've get a sense of the history command to show us what an image might be made of, let's
‫use the inspect command.
‫What this does is this gives us all the details about the image.
‫This is basically the metadata. Remember when we talked about that an image is made up of two parts,
‫the binaries and its dependencies,
‫and then the metadata about that image? Well, inspect gives you back the metadata.
‫Besides just the basic info, like the image ID and its tags, you get all sorts of detail around how
‫this image expects to be run.
‫It actually has the option to expose these two ports inside the image so that you know when you want
‫to start it, which ports you need to open up inside your Docker host if you want it to accept connections.
‫You can actually see that environment variables were passed in, including the version of Nginx that
‫it's running and the path. You can actually see the command it will run when you start up the image by
‫default.
‫Again, a lot of these things can actually be changed like we did earlier with the docker container
‫run command.
‫But these are showing us all the defaults and some other interesting information like the author,
‫and down here at the bottom, that it's an architecture of AMD64, which is pretty much what all normal
‫PCs and Macs run on nowadays.
‫We don't really have too many 32 bit machines around, so this is just a standard 64 bit Intel architecture
‫and it's designed to run on the Linux OS.
‫Ok, a quick review.
‫So we've learned a lot about images and how they're made up, and we find out that they're actually not
‫that complex. Really, they're just a series of changes on the file system and metadata about those changes.
‫You learned that each layer has its own unique identity as a SHA.
‫They're only stored once on each system, so on each Docker daemon, each layer is only represented once
‫in the file system.
‫That gives us a lot of savings in space, as well as transfer time in sending images back and forth
‫between registries, like Docker Hub. And, really, when you start a container,
‫it's just a single layer of changes on top of an existing image.
‫So it's actually usually very small. We learned about the history and inspect commands and how they
‫can teach us what's going on inside an image and how it was made.