Skip to content
Snippets Groups Projects
Commit 75bc5ca0 authored by Adam Lewenberg's avatar Adam Lewenberg
Browse files

add lesson3

parent d39239a0
No related branches found
No related tags found
No related merge requests found
......@@ -4,3 +4,4 @@
* [Prerequisites](prerequisites)
* [Lesson 1: Docker basics and running a container](lesson01)
* [Lesson 2: Introduction to Docker image builds](lesson02)
* [Lesson 3: Image layers](lesson03)
......@@ -80,3 +80,4 @@ the `CMD` directive
1. Note that the tag is `latest` (the default).
# Dockerfile
FROM debian:buster-slim
LABEL maintainer="adamhl@stanford.edu"
ADD run.sh /root/run.sh
RUN chmod a+rx /root/run.sh
CMD /root/run.sh
# Lesson 3: Image layers
1. When you run a conainera docker image is run
1. Each image consists of a sequence of file system _layers_ with the
later layers overwriting earlier ones. Each layer corresponds to an
instruction in the `Dockerfile`. Let's look at the layers. (Note: in this and
subsequent displays I leave off the CREATED column to save space).
$ docker history hello-world
IMAGE CREATED BY
f38d648975d5 /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/roo...
09b895731b10 /bin/sh -c chmod a+x /root/run.sh
07d951eff6a0 /bin/sh -c #(nop) ADD file:ae2a94e6e79a95786â¦...
34fd6d6fbb15 /bin/sh -c #(nop) LABEL maintainer=adamhl@s...
589ac6f94be4 /bin/sh -c #(nop) CMD ["bash"]
<missing> /bin/sh -c #(nop) ADD file:422aca8901ae3d869...
$ docker history debian:buster-slim
IMAGE CREATED BY
589ac6f94be4 /bin/sh -c #(nop) CMD ["bash"]
<missing> /bin/sh -c #(nop) ADD file:422aca8901ae3d869...
1. Notice that the `hello-world` image's first two layers are the same as
`debian:buster-slim`'s layers. This reflects the fact that `hello-world` starts
FROM the `debian:buster-slim` image.
1. The subsequent layers of `hello-world` each correspond to the commands
in the `Dockerfile`. Here is the Dockerfile again as a reminder:
# Dockerfile
FROM debian:buster-slim
LABEL maintainer="adamhl@stanford.edu"
ADD run.sh /root/run.sh
RUN chmod a+x /root/run.sh
CMD /root/run.sh
1. When you create a running Docker container using `docker run` the
Docker system loads your image with each layer being _read-only_ with a
final, new layer being added. This last layer is writable. Let's try it.
$ docker run --rm --name=fuzzle busybox /bin/sh -c "sleep 10000" &
$ docker exec -ti fuzzle /bin/sh (we "login" to the running container)
/ # cd /root; ls
~ # date > date.txt; ls -l
-rw-r--r-- 1 root root 0 Jan 16 03:56 date.txt
~ # cat /root/date.txt
Sat Jan 16 03:57:15 UTC 2021
~ # exit
1. The container is still running. Let's make sure the file we created is
still there.
$ docker exec -ti fuzzle /bin/sh
~ # cat /root/date.txt
Sat Jan 16 03:57:15 UTC 2021
~ # exit
1. However, once the container exits, that final writable layer is thrown away.
**It does not persist**. Let's see.
$ docker rm fuzzle
# You should get an error here. Why?
1. To stop a running container from the outside use the `docker kill` command.
$ docker kill fuzzle
$ docker rm fuzzle
# This last command returns an error. Why?
1. To see that the file `/root/date.txt` is really gone, let's start the
container again and look.
$ docker run --rm --name=fuzzle busybox /bin/sh -c "sleep 10000" &
$ docker exec fuzzle ls -l /root
1. Notice that we did not login to the container to do an `ls`, rather, we used
the `exec` command.
1. To reiterate, changes made to the containers top writable layer do not
persist. If you want the container to make persistent changes to files
another mechanism is needed such as mounting an external volume or writing
to some other persistent data store; more on that in a later lesson.
1. Back to layers.
1. When we looked at the history of the `hellow-world` image we saw this:
$ docker history hello-world
IMAGE CREATED BY
f38d648975d5 /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/roo...
09b895731b10 /bin/sh -c chmod a+x /root/run.sh
07d951eff6a0 /bin/sh -c #(nop) ADD file:ae2a94e6e79a95786â¦...
34fd6d6fbb15 /bin/sh -c #(nop) LABEL maintainer=adamhl@s...
589ac6f94be4 /bin/sh -c #(nop) CMD ["bash"]
<missing> /bin/sh -c #(nop) ADD file:422aca8901ae3d869...
1. Under the `IMAGE` column are hex strings. Those correspond to the
SHA256 hash of the new layer's content. (More precisely, the SHA256 hash
of the layers configuration object.)
1. Think of these hashes (roughly) corresponding to git commit hashes. The
layers and their hashes are useful for they tell Docker when a layer has
changed. Let's make a change to the Dockerfile:
# Dockerfile
FROM debian:buster-slim
LABEL maintainer="adamhl@stanford.edu"
ADD run.sh /root/run.sh
RUN chmod a+rx /root/run.sh # This is the changed line.
CMD /root/run.sh
1. Build the image and look at its history:
$ docker build . -t hello-world:v2
$ docker history hello-world:v2
IMAGE CREATED BY
0dd6cfe9bb51 /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/roo...
39085b76a64f /bin/sh -c chmod a+rx /root/run.sh
07d951eff6a0 /bin/sh -c #(nop) ADD file:ae2a94e6e79a95786...
34fd6d6fbb15 /bin/sh -c #(nop) LABEL maintainer=adamhl@s...
589ac6f94be4 /bin/sh -c #(nop) CMD ["bash"]
<missing> /bin/sh -c #(nop) ADD file:422aca8901ae3d869...
$ docker history hello-world (the old one)
IMAGE CREATED BY
f38d648975d5 /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/roo...
09b895731b10 /bin/sh -c chmod a+x /root/run.sh
07d951eff6a0 /bin/sh -c #(nop) ADD file:ae2a94e6e79a95786â¦...
34fd6d6fbb15 /bin/sh -c #(nop) LABEL maintainer=adamhl@s...
589ac6f94be4 /bin/sh -c #(nop) CMD ["bash"]
<missing> /bin/sh -c #(nop) ADD file:422aca8901ae3d869...
1. Note that the layers have the same image ID except for the layers
starting with the one we changed. The top layers ahve different id's
since, even though they are the same Dockerfile command, they derive from
the layer that changed (again, think of a git commit).
1. This has the pleasant result that if the first N Dockerfile commands do
not change but the N+1'st command _does_ change, then docker build will
use the cached layers for the first N layers and only rebuild from layer
N+1 onwards. This means rebuilds can be quite fast.
1. **Important** The image changes whenever one or more of the the
Dockerfile commaand lines change. Even adding whitespace to the line that
has no real effect can trigger a new layer.
1. What does it mean for a Dockerfile line to change? Either the line in
the Dockerfile itself changes (as we saw above) **or**, for commands that
add files from the local environment, the file being added changes. For
example, if we added a comment line to `run.sh` this counts as a change to
the `ADD run.sh /root/run.sh` line and would trigger a layer rebuild from
that layer forward.
1. A gotcha: your Dockerfile installs a package downloaded from an
external repository (like Debian). You build the image. A little while
later the package is updated in the Debian repository. You rebuild the
container again thinking the rebuild will catch this change. But is does
NOT. The docker build only notices changes to the Dockerfile itself, not
to sources external to the build environment.
1. A way around this gotcha. If you want to be sure that every time you
build your container it rebuilds each layer regardless of any changes to
the Dockerfile use the `--no-cache` option. This has the advantage of
reliability but the disadvantage that it can take significantly more time.
$ docker build . --no-cache -t hello-world:v3
1. Another advantage of Docker caching layers is that different images
built off the same layer help save space. Recall that images layers are
loaded read-only, so if two different running containers are built off the
same layer, both containers can point to the same physical file. This is
why spawning a second container running on the same image as the first can
be so quick: the base layer is already loaded into memory so all that has
to be done is add the final writable layer that is distinct for each
container.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment