Creating Containers with Docker
Last updated on 2024-11-26 | Edit this page
Overview
Questions
- How do you create new Docker images?
Objectives
- Explain how a Dockerfile is used to create Docker images
- Create a Dockerfile to run a command
- Use
docker build
to create a new image - Update a Dockerfile to run a Python script
Introduction
In the previous episode, we used a Docker image to run a Docker container. We briefly covered how images are used to make a container, but where does the Docker image come from? In this episode, we will create and use Dockerfiles to make a new image, and use that image to start a Docker container.
TODO Might be a good spot for a visual.
Dockerfiles
A Dockerfile is a plain text file that includes instructions for making a Docker image. Dockerfiles can be very short or very long, depending on how complicated the Docker image is going to be. A minimal Dockerfile would have two pieces of information:
- The base image to start from, and
- What to do when the container starts running
The first point (the base image) may seem a little odd, as it appears we are actually building an image from…another image? And that is exactly what we are doing!
Callout
It is possible for you to start from an operating system image (e.g. from an ISO file), but there are a lot of Docker images already available for whichever operating system you want to use. But let us not make even more work for ourselves. It’s turtles all the way down and that’s OK.
Dockerfile gross anatomy
The general structure of a Dockerfile is a series of keywords followed by some information. For the minimal Dockerfile we are going to build, we need to include commands to accomplish the two points we mentioned above (identify the base image and do something when the container starts):
- The
FROM
command is followed by the name of the image to start from and the version number of that image. When we use the Dockerfile to build the Docker image, our computer will start by downloading a copy of that base image, and adding to based on whatever subsequent commands we provide in the Dockerfile. - The
CMD
command tells the container what to do when it starts running. In some cases, it will start an application, like we saw with the OpenRefine image in the previous episode. TheCMD
command can also do things like run analyses based on data passed to the container.
For this episode, we will start by creating a Dockerfile with only these two commands:
FROM python:3.9
CMD ["python", "--version"]
TODO: Where do we want to be making this file? Is the home directory OK?
Creating Dockerfiles
As mentioned above, Dockerfile are plain text files, so we need to use a text editor to create them. In the virtual machine where we are working, the nano text editor will work for us. To create the Dockerfile, start by opening up the command line terminal again (or opening a new tab if the terminal is already running) and running the following:
nano Dockerfile
This command will do two things: first, it creates an empty text file
called “Dockerfile” and, second, it opens the file in the nano text
editor. We will add those two lines, as well as a comment for each line.
Comments are useful for anyone who will need to look at the Dockerfile
in the future (this usually means you!). The comment character,
#
, tells the computer to ignore any text that comes to the
right of the #
, as it is for human eyes only. In the nano
text editor, add the following:
FROM python:3.9 # use the python base image, version 3.9
CMD ["python", "--version"] # on container start, print the version of python
Which should look something like this in your terminal:
Once you have that typed in, you can save and close the file. To do
this, first hold down the Control/Command key and press the letter “O”
key (this is often written as ^O
) and press “Enter” to
confirm the save to the file called “Dockerfile”. Second, to exit the
nano editor, hold down the Control/Command key and press the letter “X”
key (^X
). If you are curious about what was saved to the
Dockerfile, you can run the command cat Dockerfile
on the
terminal command line and it will print the contents of the file to the
screen.
Creating images from Dockerfiles
We have now created the Dockerfile, and there is one last step
necessary to make the Docker image from that Dockerfile. To make the
Docker image, we use the docker build
command and provide
it with the name of the image. In the terminal command line, run the
following command:
docker build -t vboxuser/python-text .
Breaking down the command into the component parts:
-
docker build
is the base command telling our computer to build a Docker image -
-t
indicates we are going to “tag” this image with a label -
vboxuser/python-test
provides the name of the repository (vboxuser
) and the name of the image (python-test
). This convention, using the repository name and the image name, is like using a person’s full name (family name and given name), rather than just someone’s given name. Just using an image name alone, without a repository name, would be like referring to “Mohamed” or “Maria” and expecting other people to know exactly who you are referring to. -
.
is just a dot telling your computer where the Dockerfile is located. In the command line interface, the dot is directory where you are running the command. TODO: Might be a good spot to link the LC Shell lesson here. If the Dockerfile was somewhere other than the folder your command line terminal is currently running in, you would replace the dot with that location. For example, if the Dockerfile was located on the Desktop, we would update our command todocker build -t vboxuser/python-text ~/Desktop
(where the dot.
is replaced with~/Desktop
).
TODO Explain commands. Note how no new file is created in our directory, it gets created…somewhere, though?
docker build -t ...
docker image ls
Challenge 1: Updating our analogy
In the previous episode, a couple of different analogies were introduced to explain the relationship between a Docker image and a Docker container. Pick one of those analogies and update it to also include the Dockerfile.
TODO: Update these analogies with Dockerfiles.
- To use an analogy from architecture, images are the blueprints and containers are the actual building.
- An image is a recipe, say, for your favorite curry, while the container is the actual curry dish you can eat.
- “Think of a container as a shipping container for software - it holds important content like files and programs so that an application can be delivered efficiently from producer to consumer. An image is more like a read-only manifest or schematic of what will be inside the container.” (from Jacob Schmitt)
- If you are familiar with object-oriented programming, you can think of an image as a class, and a container an object of that class.
Starting containers
TODO This is review.
docker run ...
Confirm it ran and quit
docker ps -a
Challenge 2: Update base image
- Update the Dockerfile to have a base image that includes Python version 3.12 (instead of Python version 3.9)
- Build the image
- Start the container to confirm it is using Python version 3.12
To change the base image, update the information passed to the
FROM
command. That is, open the Dockerfile and change this
line:
FROM python:3.9
to
FROM python:3.12
Copying files into the image
TODO Add flavor text about why we might do this.
COPY ...
See https://stackoverflow.com/questions/32727594/how-to-pass-arguments-to-shell-script-through-docker-run and https://www.tutorialspoint.com/how-to-pass-command-line-arguments-to-a-python-docker-container
for example of passing arguments to a script. Passing arguments might be too much.
Challenge 3: Copy a script to run in the container
There is a script (make this a print("Hello World!")
python script) you want to include
TODO: Insert solution
Key Points
- Dockerfiles include instructions for creating a Docker image
- The
FROM
command in a Dockerfile indicates the base image to build on - The
CMD
command in a Dockerfile includes commands to execute when a container starts running - The
COPY
command in a Dockerfile copies files from your local machine to the Docker image so they are available for use when the container is running