A Docker “hello world” app

by Jason Swett,

What we’re going to do

In this tutorial we’re going to illustrate what I consider to be Docker’s central and most magical ability: to let you run software on your computer that you don’t actually have installed on your computer.

The specific software we’re going to run is the Lisp REPL (read-evaluate-print loop). The reason I chose Lisp is because you’re unlikely to happen to have Lisp already installed. If I had chosen to use a language that you might already have installed on your computer, like Ruby or Python, the illustration would lose much of its sizzle.

Here are the steps we’re going to carry out. Don’t worry if you don’t understand each step right now because we’re going to be looking at each step in detail as we go.

1. Add a Dockerfile
2. Build an image from our Dockerfile
3. Run our image, which will create a container
4. Shell into that container
5. Start a Lisp REPL inside the container
6. Run a Lisp “hello world” inside the REPL
7. Exit the container
8. Delete the image

Prerequisites

Before you follow this tutorial you’ll of course have to have Docker installed. You might also like to get familiar with basic Docker concepts and terminology.

Adding a Dockerfile

A Dockerfileis a specification for building a Docker image. We’re going to write a Dockerfile, use the Dockerfileto build a custom image, create a container using the image, and finally shell into the container and start the Lisp REPL.

First I’m going to show you the Dockerfileand then I’ll explain each individual part of it.

# Dockerfile

FROM ubuntu:20.04

RUN apt update && apt install -y sbcl

WORKDIR /usr/src

FROM

FROM ubuntu:20.04

The FROMdirective tells Docker what image we want to use as our base image. A base image, as the name implies, is the image that we want to use as a starting point for our custom image. In this case our base image is just providing us with an operating system to work with.

The FROMdirective takes the form of <image>:<tag>. In this case our image is ubuntuand our tag is 20.04. When Docker sees ubuntu:20.04, it will look on Docker Hub for an image called ubuntuthat’s tagged with 20.04.

RUN

RUN apt update && apt install -y sbcl

The RUNcommand in a Dockerfilesimply takes whatever it’s given and runs it on the command line.

In this case the command we’re running is apt update && apt install -y sbcl. The &&in between the two commands means “execute the first command, then execute the second command if and only if the first command was successful”. Let’s deal with each of these commands individually.

The apt updatecommand is a command that downloads package information. If we were to skip the apt updatecommand, we would get an error that says Unable to locate package sbclwhen we try to install sbcl. So in other words, running apt updatemakes our package manager aware of what packages are available to be installed.

The apt install -y sbclcommand installs a package called sbcl. SBCL stands for Steel Bank Common Lisp which is a Common Lisp compiler. (Common Lisp itself is a popular dialect of the Lisp language.)

The -ypart of apt install -y sbclmeans “don’t give me a yes/no prompt”. If we were to leave off the -ywe’d get an “are you sure?” prompt which would be no good because the Dockerfileisn’t executed in an interactive way that would actually allow us to respond to the prompt.

WORKDIR

WORKDIR /usr/src

The WORKDIR /usr/srcdirective specifies which directory to use as the working directory inside the container. Imagine being logged into a Linux machine and running cd /usr/src. After running that command, you’re “in” /usr/srcand /usr/srcis your working directory. Similar idea here.

Listing our existing images

Before we use our Dockerfileto build our image, let’s list our existing Docker images. If this is your first time doing anything with Docker then the list of existing images will of course be empty.

In any case, let’s run the docker image lscommand:

$ docker image ls

Listing our existing containers

In addition to the docker image lscommand which lets us list any images we have, there’s an analogous command that lets us list our containers.

$ docker container ls

Building our image

We can use the docker buildcommand to build our image. The --tag lisppart says “give the resulting image a tag of lisp“. The .part says “when you look for the Dockerfileto build the image with, look in the current directory”.

$ docker build --tag lisp .

After you run this command you’ll see some entertaining output fly across the screen while Docker is building your image for you.

Confirming that our image was created

Assuming that the build was successful, we can now use the docker image lscommand once again to list all of our existing images, which should now include the image we just built.

$ docker image ls

You should see something like the following:

REPOSITORY   TAG      IMAGE ID       CREATED          SIZE  
lisp         latest   91f4fa2a754a   11 minutes ago   140MB

Creating and shelling into a container

Run the following command, which will place you on the command line inside a container based on your image. You should of course replace <image id>with the image id that you see when you run docker image ls.

$ docker run --interactive --tty <image id> /bin/bash

The docker runcommand is what creates a container from the image. The /bin/bashargument says “the thing you should run on this container is the /bin/bashprogram”.

Viewing our new container

Now that we’ve invoked the docker runcommand, we have a new container. Open a separate terminal window/tab and run docker container ls.

$ docker container ls

You should see a new container there with an image ID that matches the ID of the image you saw when you ran docker image ls.

CONTAINER ID   IMAGE          COMMAND       CREATED         STATUS
5cee4af0cfa9   91f4fa2a754a   "/bin/bash"   4 seconds ago   Up 3 seconds

Poking around in our container

Just for fun, run a few commands in the container and see what’s what.

$ pwd    # show the current directory
$ ls -la # show the contents of the current directory
$ whoami # show the current user

Running the Lisp REPL

Finally, let’s run the Lisp REPL by running the sbclcommand inside our container.

$ sbcl

Once you’re inside the REPL, run this piece of “hello, world!” Lisp code.

(format t "hello, world!")

Exiting the container

Press CTRL+D to exit the Lisp REPL and then CTRL+D again to exit the container. The container will delete itself once exited.

Deleting the image

Run the following command to delete the image.
The rmipart stands for “remove image” and the -fflag stands for “force”.

$ docker rmi -f <image id>

Recap

You’ve completed this exercise. You’re now capable of the following things:

  • Writing a Dockerfilethat specifies an operating system to use and some software to install
  • Listing Docker images and containers
  • Building Docker images
  • Shelling into a container
  • Using the software that was installed on the container

If you possess these capabilities and have at least a little bit of a grasp of the underlying concepts, then you’re well on your way to being able to use Docker to accomplish real work.

Leave a Reply

Your email address will not be published. Required fields are marked *