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.
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
Try the script passing a name as an argument.
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.
[+] 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:
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
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
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
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
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: