In my last “Hello Whale” post, I talked about how containers and VMs are not one in the same. Instead of pip installing various technologies on a VM (often getting more than you actually need), with Docker you can grab the specific parts you require. It’s like putting together the different pieces you need to create the perfect app to your specifications- no extra weight. But what if I told you that Docker images themselves have their own pieces?
Wait, what?
Ok what are these “layer” things?
The first time you pull an image from Docker Hub, it will look like this:
Chloes-MacBook-Pro:~ chloecondon$ docker pull registry Using default tag: latest latest: Pulling from library/registry 79650cf9cc01: Pull complete 70ce42745103: Pull complete 77edd1a7fa4d: Pull complete 432773976ace: Pull complete 3234a47fe5a9: Pull complete Digest: sha256:a3551c422521617e86927c3ff57e05edf086f1648f4d8524633216ca363d06c2 Status: Downloaded newer image for registry:latest
As you can see above, we had to wait for each pull to load. But, have you ever noticed when you’ve pulled an image for a 2nd time, some seem to already be loaded for you?
Chloes-MacBook-Pro:~ chloecondon$ docker pull registry Using default tag: latest latest: Pulling from library/registry Digest: sha256:a3551c422521617e86927c3ff57e05edf086f1648f4d8524633216ca363d06c2 Status: Image is up to date for registry:latest
Believe it or not, this isn’t witchcraft. This is part of the awesomeness that is “layers” in Docker.
If we run…
docker image history YOUR_REPO_NAME:latest
…we’ll see all the layers in this image’s history. Pretty cool huh? We can see the changes that were made, how big they are, and when they were created.
Chloes-MacBook-Pro:~ chloecondon$ docker image history registry:latest IMAGE CREATED CREATED BY SIZE COMMENT 9d0c4eabab4d 8 days ago /bin/sh -c #(nop) CMD ["/etc/docker/regis... 0 B <missing> 8 days ago /bin/sh -c #(nop) ENTRYPOINT ["/entrypoin... 0 B <missing> 8 days ago /bin/sh -c #(nop) COPY file:7b57f7ab1a8cf8... 155 B <missing> 8 days ago /bin/sh -c #(nop) EXPOSE 5000/tcp 0 B <missing> 8 days ago /bin/sh -c #(nop) VOLUME [/var/lib/registry] 0 B <missing> 8 days ago /bin/sh -c #(nop) COPY file:6c4758d509045d... 295 B <missing> 8 days ago /bin/sh -c #(nop) COPY file:286222b32843a3... 22.8 MB <missing> 8 days ago /bin/sh -c set -ex && apk add --no-cac... 5.61 MB <missing> 8 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0 B <missing> 8 days ago /bin/sh -c #(nop) ADD file:9c596c6cb8ba1d7... 4.81 MB
The beauty of layers is that it means less uploading and downloading for you. You know how much I love my visual examples! So here’s another one:
This time with 100% more pizza!
Let’s say we had a cheese pizza. We have a base layer of dough, tomato sauce, and cheese. Then I decide I want to have half of my pizza with pepperoni with it. Would I bake another pizza from scratch, make new layers, and add pepperoni to that one? Of course not! I’d just add a layer of pepperoni to half of my existing pizza. No need to go through the trouble of making a whole new base pie. As we make more changes, we create more layers.
Ok, now I want pizza.
Now, how does this work when a base image gets changed? Well, then Docker uses copy-on-write (or, “cow” ). This means it would take the changed base image and store a copy of it in the container layer. So keeping to our pizza metaphor, we would take out a slice of our pizza from the pie, add some jalapeños on top, and dip the crust in hot sauce. Now our base layer is changed, so we’d save it in its own Tupperware for later (aren’t you just loving these container metaphors?). The purpose of copy-on-write is to not create new resources unless we have to; resources can be shared between the copy and the original in the case of our cheese/pepperoni metaphor. But, when we fundamentally change the base image (by dipping the crust in hot sauce), we need to save it in its own container.
Wow I didn’t know I needed this.
Ok, but why would we want to store each layer only once? We’re saving storage space! Not only does this make our host less crowded (avoiding duplicates), but it also saves us time when we are pushing and pulling between registries. So, a container is a layer on top of an image.
https://giphy.com/gifs/dip-layer-IYgMHLSLoWtvW
docker image history 100-layer-dip:latest
The beauty of Codefresh being Docker native is that we are able to cache all the layers, making subsequent builds much faster each time you build. Why spend extra time and build from scratch with another CI when you can get up and running much faster? To learn more about Codefresh, start your free trail today (or, schedule a demo with me!) and see how much time you save.