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 Dockerfile
is a specification for building a Docker image. We’re going to write a Dockerfile
, use the Dockerfile
to 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 Dockerfile
and 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 FROM
directive 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 FROM
directive takes the form of <image>:<tag>
. In this case our image is ubuntu
and our tag is 20.04
. When Docker sees ubuntu:20.04
, it will look on Docker Hub for an image called ubuntu
that’s tagged with 20.04
.
RUN
RUN apt update && apt install -y sbcl
The RUN
command in a Dockerfile
simply 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 update
command is a command that downloads package information. If we were to skip the apt update
command, we would get an error that says Unable to locate package sbcl
when we try to install sbcl
. So in other words, running apt update
makes our package manager aware of what packages are available to be installed.
The apt install -y sbcl
command 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 -y
part of apt install -y sbcl
means “don’t give me a yes/no prompt”. If we were to leave off the -y
we’d get an “are you sure?” prompt which would be no good because the Dockerfile
isn’t executed in an interactive way that would actually allow us to respond to the prompt.
WORKDIR
WORKDIR /usr/src
The WORKDIR /usr/src
directive 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/src
and /usr/src
is your working directory. Similar idea here.
Listing our existing images
Before we use our Dockerfile
to 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 ls
command:
$ docker image ls
Listing our existing containers
In addition to the docker image ls
command 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 build
command to build our image. The --tag lisp
part says “give the resulting image a tag of lisp
“. The .
part says “when you look for the Dockerfile
to 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 ls
command 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 run
command is what creates a container from the image. The /bin/bash
argument says “the thing you should run on this container is the /bin/bash
program”.
Viewing our new container
Now that we’ve invoked the docker run
command, 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 sbcl
command 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 rmi
part stands for “remove image” and the -f
flag stands for “force”.
$ docker rmi -f <image id>
Recap
You’ve completed this exercise. You’re now capable of the following things:
- Writing a
Dockerfile
that 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.