This the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Hello World

Let’s start simple. This example exists in the basics/hello directory in the examples repo, but it’s so simple you might want to create your own version by following the instructions below.

Create a unique directory for this example, such as hello, and then change directory to it.

mkdir hello
cd hello

Important! You’ll create a unique directory for every example. A directory must contain its own distinctDockerfile as well as any other files ( symbolic links won’t work) that will need to be copied into the generated Docker image.

You’re going to write a small program – just a basic shell script to print the obligatory Hello World greeting.

Next you’ll write a short Dockerfile. You’ll use the Dockerfile to build a Docker image that incorporates your program.

Finally you’ll use the image to launch a container. Your program executes inside the container.

The container is a logical abstraction based on Linux features that simply runs the process for your program in a way that isolates it from the rest of the system.

1 - The shell script

Create a simple shell script to print a greeting.

The script will print Hello and the name supplied as the script’s first argument (defaulting to World if none).

#!/bin/sh

NAME=${1:-world}
echo "Hello, $NAME!"

Set the executable bit and run the script in your terminal.

chmod +x hello.sh
hello.sh
Hello, world!

Try the script passing a name as an argument.

hello.sh Docker
Hello, Docker!

2 - The Dockerfile

Create a Dockerfile.

FROM alpine
COPY hello.sh /
ENTRYPOINT [ "/hello.sh" ]

Build a Docker image with the following command. The trailing dot (.) indicates that the path to the Dockerfile is the current working directory.

docker build -t hello .
[+] Building 8.0s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                                 0.9s
 => => transferring dockerfile: 97B                                                                                  0.0s
 => [internal] load .dockerignore                                                                                    1.1s
 => => transferring context: 2B                                                                                      0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                                     2.6s
 => [auth] library/alpine:pull token for registry-1.docker.io                                                        0.0s
 => [internal] load build context                                                                                    0.7s
 => => transferring context: 84B                                                                                     0.0s
 => [1/2] FROM docker.io/library/alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a      2.1s
 => => resolve docker.io/library/alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a      0.3s
 => => sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a 1.64kB / 1.64kB                       0.0s
 => => sha256:b06a5cf61b2956088722c4f1b9a6f71dfe95f0b1fe285d44195452b8a1627de7 528B / 528B                           0.0s
 => => sha256:bb3de5531c18f185667b0be0e400ab24aa40f4440093de82baf4072e14af3b84 1.49kB / 1.49kB                       0.0s
 => => sha256:552d1f2373af9bfe12033568ebbfb0ccbb0de11279f9a415a29207e264d7f4d9 2.71MB / 2.71MB                       0.6s
 => => extracting sha256:552d1f2373af9bfe12033568ebbfb0ccbb0de11279f9a415a29207e264d7f4d9                            0.1s
 => [2/2] COPY hello.sh /                                                                                            0.7s
 => [3/3] RUN chmod +x /hello.sh                                                                                     1.2s
 => exporting to image                                                                                               0.6s
 => => exporting layers                                                                                              0.5s
 => => writing image sha256:35be16e40caf802a0fb0d7a09dca7bce970162b62635d870134e64b754c67967                         0.1s
 => => naming to docker.io/library/hello

What just happened?

You can see a bunch of things happened in the output. In a nutshell, the docker build command submitted the Dockerfile and the rest of the contents of the directory (anything that isn’t ignored by a .dockerignore file, if present) to the Docker daemon running on your system. Most of the output reflects the administrative details of the process used to create the final image.

An image is composed of cacheable layers. In the output that begins with => [1/3] FROM docker.io/library/alpine we can see that Docker pulled the alpine base image from the alpine repository at a remote registry (docker.io) comprised of a number of layers that will provide the Linux distribution for our program. This operating environment will run on top of the Linux kernel on your host system (if you’re running on a Mac or Windows machine, this will be in a virtual machine running on your system).

For the line of output that contains => [2/3] COPY hello.sh /, Docker executes the COPY instruction that tells the Docker daemon to copy hello.sh from the root of the build context (the set of files that the Docker CLI docker build command sent to the Docker daemon) into the root (/) of the image.

In the line that contains => [3/3] RUN chmod +x /hello.sh, Docker updates the image by running the Linux command to set the executable bit on the program. If you set the executable bit on the script when you tested it, it’s likely that the file was copied correctly with the bit set, but you shouldn’t assume this. Always ensure you set any permission bits explicitly.

The final ENTRYPOINT instruction in our Dockerfile doesn’t add any layers to the image, which is why there’s no corresponding line that says [4/4]. It adds metadata that is used to specify the process that want to execute when a container is created.

Try this

Run the docker image ls command:

docker image ls hello
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
hello        latest    1cb37f5aaa1b   2 minutes ago    5.34MB

You can confirm that the image was created, check its size (the bulk of the image comes from the Alpine Linux distribution), and note that the image ID fragment (02bcec72c45a) corresponds with the last layer that was created.

3 - Run a container

Now that you have an image, you can launch a container to run your program.

docker container run --rm hello
Hello, world!

The --rm option tells Docker to remove the container once the process running in it terminates. It’s generally a good idea to clean up resources when no longer needed.

One reason not to automatically remove a container when the running process terminates is to inspect the logs after.

docker container run --name helloctr hello

You’ll see the same the output as before. This time we gave the container a name using the --name option to make it easy to refer to it. You can inspect everything the process wrote to stdout and stderr with the docker logs command.

docker container logs helloctr
Hello, world!

The logs show the same output that was printed to the terminal.

Even though the process exited and the container is no longer usable, you can see that it still exists with the docker container ls command.

docker container ls --all
CONTAINER ID   IMAGE  COMMAND       CREATED          STATUS                      PORTS      NAMES
c038996a5e75   hello  "/hello.sh"   20 seconds ago   Exited (0) 18 seconds ago              helloctr

The --all option was needed to show containers that have exited.

You can remove the container with the docker container rm command.

docker container rm helloctr
helloctr

The output indicates the name of the container that was removed.

The program accepts a name argument. You can supply arguments to the docker run command when you run a container.

docker container run --rm hello Docker
Hello, Docker!

The original versions of the docker container commands are still available and can be used as convenient shortcuts.

docker container run   =>  docker run
docker container logs  =>  docker logs
docker container ls    =>  docker ps
docker container rm    =>  docker rm

4 - Summary

The helloworld example introduced you to the following: