Skip to content

lesson-02

Forward

So far we have been using container images downloaded from Docker's public registry.

One of the key success factors for Docker among competitors was the possibility to easily create, customize, share and improve container images cooperatively.

This lab covers this feature in detail.

The Web Terminal

If you want to take advantage of the interactive, hands-on nature of these labs, you'll need to either already have a web terminal connection available or fire one up yourself.

Instructions for that can be found here.

Exercise 1 - Starting from scratch

If we want to start from scratch, let's build the ingredients for our container image.

Create a hello world script

mkdir docker-workspace
cd docker-workspace
echo -e '''#!/bin/sh
echo "hello, world $@"
''' > hello.sh

Create your Dockerfile

A Dockerfile is a special file that instructs the docker build command on how to build an image

echo -e '''FROM scratch
ADD hello.sh /hello.sh
''' > Dockerfile

You should now have in your directory two files, Dockerfile and hello.sh

Build your image

docker build -t hello .

The output should be similar to:

Sending build context to Docker daemon 3.072 kB
Step 1/2 : FROM scratch
 --->
Step 2/2 : ADD hello.sh /hello.sh
 ---> 03899b124d13
Successfully built 03899b124d13
Successfully tagged hello:latest

The Dockerfile used is very simple:

  FROM scratch
  ADD hello.sh /hello.sh
  • FROM scratch instructs the Docker build process to use an empty image as the basis to build our custom container image

  • ADD hello.sh /hello.sh adds the file hello.sh to the container's root path /hello.sh.

Exercise 2 - Viewing images

Let's go over viewing docker images

List available docker images

Run the command docker images to display images that we have built.

Running the above command should display image information similar to:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              fcb780e01f47        5 minutes ago       35B

Here's a quick explanation of the columns shown in that output:

  • Repository - a name associated to this image locally (on your computer) or on a remote repository. Our current repository is local and the image is called hello
  • Tag - indicates the version of our image, Docker sets the latest tag automatically if none is specified
  • Image ID - unique image ID
  • Size - the size of our image is very small (~35 bytes)

NOTE: Docker images are quite different from virtual machine image formats.

Since Docker does not boot any operating system, but simply runs Linux processes in isolation,

we don't need any kernel-level objects or drivers to ship with an image,

so the size can potentially be as tiny as just a few bytes!

Exercise 3 - Running our image

Let's go over running our image, i.e. invoking our image as a container ...

Run the newly-built image

docker run --rm hello /hello.sh

As you'll note, trying to run our newly built image will result in an error similar to one of the following (depending on your version of Docker):

write pipe: bad file descriptor

or

standard_init_linux.go:211: exec user process caused "no such file or directory"

This is because our container is empty.

There is no shell, so the script won't be able to start!

Let's fix that by changing our base image to busybox, as it contains a proper shell environment ...

Exercise 4 - Rebuilding the image

Time to rebuild our docker image.

Recreate your Dockerfile using busybox as your base image

echo -e '''FROM busybox
ADD hello.sh /hello.sh
RUN chmod +x /hello.sh
''' > Dockerfile

Build your container again

docker build -t hello .

The output should be similar to:

Sending build context to Docker daemon  6.144kB
Step 1/3 : FROM busybox
 ---> be5888e67be6
Step 2/3 : ADD hello.sh /hello.sh
 ---> Using cache
 ---> a54d28b10018
Step 3/3 : RUN chmod +x /hello.sh
 ---> Using cache
 ---> befa8400f441
Successfully built befa8400f441
Successfully tagged hello:latest

Again, the Dockerfile used is very simple:

  FROM busybox
  ADD hello.sh /hello.sh
  RUN chmod +x /hello.sh
  • FROM busybox instructs the Docker build process to use the busybox public docker image as the basis to build our custom container image

  • ADD hello.sh /hello.sh adds the file hello.sh to the container's root path /hello.sh.

  • RUN chmod +x /hello.sh sets the execution bit on the hello.sh script to make it executable.

Listing the image should show that image ID and size have changed.

List available docker images

Running docker images should produce output similar to:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              2a56d704ff5b        43 seconds ago      1.22MB
<none>              <none>              f94453b3174d        9 minutes ago       34B
busybox             latest              be5888e67be6        2 weeks ago         1.22MB

We should be able to run our container now.

Run your rebuilt image

docker run --rm hello /hello.sh  <%= $env:Username %>

Output should be similar to:

hello, world <%= $env:Username %>

Exercise 5 - Versioning your image

Let's roll out a new version of our script

Modify your hello world script

echo -e '''#!/bin/sh
echo "hello, world $@"
echo "I am a new image"
''' > hello.sh

We don't need to update our Dockerfile, as it references the same script.

We just have to rebuild the image.

Build your image again, this time with a new tag

docker build -t hello:v2 .

Run your v2 image

docker run --rm hello:v2 /hello.sh <%= $env:Username %>

Output should be similar to:

hello, world <%= $env:Username %>
I'm a new image

Exercise 6 - Entry points

We can improve our image by supplying an entrypoint.

This will set the default command executed if none is specified when starting the container.

Define an entrypoint for your image

echo -e '''FROM busybox
ADD hello.sh /hello.sh
RUN chmod +x /hello.sh
ENTRYPOINT ["/hello.sh"]
''' > Dockerfile

Build a new version of your image

docker build -t hello:v3 .

We should now be able to run the new image version without supplying additional arguments

Run your v3 image

docker run --rm hello:v3

Output should be similar to:

hello, world
I am a new image

What happens if you pass an additional argument as in previous examples?

These will be passed to the ENTRYPOINT command as arguments.

Run your v3 image with arguments

docker run --rm hello:v3 testing

Read more: