Dockerfile tutorial by example
source:
Content
practices-2018/
Estimated reading time :20 Minutes
https://takacsmark.com/dockerfile-tutorial-by-example-dockerfile-best-
What is a Dockerfile and why you’d want to use
one?
A Dockerfile is a text file that defines a Docker image. You’ll use a Dockerfile to create
your own custom Docker image, in other words to define your custom environment to
be used in a Docker container.
Since this tutorial is for beginners let’s go slow and go deeper into the above definition.
Recap of Docker base terms
Let me repeat a few basic concepts to better explain. If you are absolutely new to docker,
please start with the Getting started with Docker - step by step tutorial - article on the blog. It
got 1,500 likes on Youtube from 120,000 views, so it’s not only me who says you’ll get this, so
don’t worry. :)
Docker’s main purpose is to give us run-time environments that we can re-create/reproduce
on any machine (that runs Docker). The main advantage is to avoid the situations when we
say “it worked on my machine”, because Docker containers will give us the same environment
on all machines.
In order to follow this article you need to understand the following 2 basic concepts of Docker:
Docker containers: containers are runtime environments. You usually run one main process
in one Docker container. You can think of this like one Docker container provides one service
in your project.
For example you can start one container to be your MySQL database and start another
container to be your Wordpress server and connect these containers together to get a
Wordpress project setup.
You can start containers to run all the tech you can think of, you can run databases, web
servers, web frameworks, test servers, execute big data scripts, work on shell scripts, etc.
Cloud Computing – Docker Network
1
Docker containers are started by running a Docker image. A Docker image is a pre-built
environment for a certain technology or service. A Docker image is not a runtime, it’s rather
a collection of files, libraries and configuration files that build up an environment.
The main source of Docker images online is the Docker store. You just need to search for your
preferred tech component, pull the image from the store with the docker pull command
and you are ready to start up containers.
Containers are started from images with the docker run command. An image, as you’ll see
in the videos, is a layered representation of your environment. These layers contain the files
and configuration needed by your environment.
As you start up a container with docker run, Docker will add another layer on top of your
image. While your image layers are read-only, the additional layer added by the container is
read-write.
Why and when you’d want to use a Dockerfile?
So let’s go back to the definition: A Dockerfile is a text file that defines a Docker image.
You’ll use a Dockerfile to create your own custom Docker image, in other words to
define your custom environment to be used in a Docker container.
You’ll want to create your own Dockerfile when existing images don’t satisfy your project
needs. This will actually happen most of the time, which means that learning about the
Dockerfile is a pretty essential part of working with Docker.
You’ll see in the tutorial that a Dockerfile is a step by step definition of building up a Docker
image. The Dockerfile contains a list of instructions that Docker will execute when you issue
the docker build command. Your workflow is like this:
1. you create the Dockerfile and define the steps that build up your images
2. you issue the docker build command which will build a Docker image from your
Dockerfile
3. now you can use this image to start containers with the docker run command
Advertisement
You’ll usually start searching for available Docker images on the Docker store, you’ll also find
images on github included with a good number of repos (in the form of a Dockerfile), or you
can share Docker images within your team or company by creating your own Docker Registry
(I’ll write about this in an advanced tutorial).
The definition also implies that the images that you’ll find on the Docker store are defined in
Dockerfiles. We’ll review some Dockerfiles in the first video. A Docker image is created by
building a Dockerfile with the docker build command. We’ll see examples later.
Cloud Computing – Docker Network
2
This means that technology vendors and developers usually provide one or more
Dockerfile(s) with their specific technologies. They define the steps of building the image in
the Dockerfile and they use docker build to create the Docker image.
What happens if you can’t find the exact Docker image that you need for your project? Most
images are generic and won’t cover your exact case. This is the point when you’ll create
your own Docker images.
All you need to do is to create a text file named Dockerfile (with no extension) and define
your image. You’ll see that you’ll create your own images with almost every project you start,
I usually create my own images for sandboxes and playgrounds, too.
This tutorial will teach you how to define, build and run your own images.
Dockerfile basics
In the first video you’ll find the key concepts, Dockerfile examples, I teach you how to manage
your Docker images locally and we’ll create a custom image and understand the concept of
layering.
Dockerfile example
Let’s start with an example and see what’s in a Dockerfile. I attached the below Dockerfile
from GitHub, this file is part of the official PHP image distribution on the Docker store.
You
can
access
the
file
directly
via
this
url: https://github.com/docker-
library/php/blob/f4baf0edbc4e05e241938c68bcc7c9635707583d/7.2/stretch/apache/Docker
file.
Please browse through the file, it’s enough for now if you note the key structural elements,
skim trough the comments and see how the file is built up on a high level.
<script src="https://gist-it.appspot.com/https://github.com/docker-
library/php/blob/f4baf0edbc4e05e241938c68bcc7c9635707583d/7.2/stretch/apac
he/Dockerfile"></script>
At this point I would like you to understand the following key points based on the example
file:
1. The Dockerfile is a text file that (mostly) contains the instructions that you would
execute on the command line to create an image.
2. A Dockerfile is a step by step set of instructions.
3. Docker provides a set of standard instructions to be used in the Dockerfile,
like FROM, COPY, RUN, ENV, EXPOSE, CMD just to name a few basic ones.
4. Docker will build a Docker image automatically by reading these instructions from the
Dockerfile.
Cloud Computing – Docker Network
3
So from a developer, or tech user perspective you’ll be basically describing the build
steps of your environment in the Dockerfile. Then you’ll build your image from the
Dockerfile and start up your containers.
This also implies that understanding Dockerfile instructions is not enough to create your
Dockerfile, because you need to also understand the context of the technology you are
Advertisement
building for. If, for example, you are bulding a Dockerfile to be used in a PHP project, you’ll
need to dive into PHP specific knowledge, like configuration methods, PHP extensions,
environment settings and such.
The good news is that you can save a lot of time when starting out experimenting with a new
technology, because you can use an image prepared by someone else, without understanding
the details immediately. Once you are up for some more complex stuff you can start adding
to the knowledge that you can extract and learn from other people’s Dockerfiles.
Reading Dockerfiles prepared by others is a great way to learn about technology.
Listing Docker images on your computer
Let’s do some hands-on magic. Before building your own Docker images, let’s see how to
manage images on your computer.
You can follow the video for this part at around 8:00, I’ll provide a summary here.
Use the command docker images in your terminal to list the images you currently have on
your computer. Remember that images are stored on your computer once you pull them
from a registry like the Docker store, or once you build them on your computer.
If you have not pulled any images yet, your list may be empty. This is my computer today
(please note that the list is different from the list in the video, because I’m writing this article
later in time).
Cloud Computing – Docker Network
4
These are the images that I’m currently using on my computer. I pulled most of them from
the Docker store, and I have built my own, too. The images that have a nametag in the form
of takacsmark/<image_name> are the ones that I have built from my own Dockerfiles.
Please note that I usually don’t keep all the images that I use, I try to keep everything nice and
clean, because images take up space.
It is worthwhile to check the image sizes in the picture. You’ll find that some images have a
very small footprint, like the Alpine linux image, while more complex image take up a lot of
space, like anaconda3.
Let’s create your first image
Let’s start the journey by creating a modified Alpine Linux image. We’ll take the base Alpine
image from the Docker store and modify it by installing a few Linux packages. Please execute
the following in terminal:
1. Create the Dockerfile
Create an empty directory for this task and create an empty file in that directory with the
name Dockerfile. You can do this easily by issuing the command touch Dockerfile in your
empty directory.
Congratulations, you just created your first Dockerfile! Let’s open the file in your favorite text
editor!
The Alpine image does not have git, vim and curl by default, as you can see in the video. So
let’s create a custom image from Alpine that has git, vim and curl included. This will be your
first custom Docker image.
Cloud Computing – Docker Network
5
2. Define the base image with FROM
Every Dockerfile must start with the FROM instruction. The idea behind is that you need a
starting point to build your image. You can start FROM scratch, scratch is an explicitly empty
image on the Docker store that is used to build base images like Alpine, Debian and so on.
I start my images mostly from other images. You can start you Docker images from any valid
image that you pull from public registries. The image you start from is called the base image.
In our case let’s add FROM alpine:3.4 to the Dockerfile.
Right now your Dockerfile should look like this:
FROM alpine:3.4
3. Add the lines to install packages
Please add the lines to install vim and curl like this:
FROM alpine:3.4
RUN apk update
RUN apk add vim
RUN apk add curl
Advertisement
This is not best practice, these are just a few lines to get started. Don’t worry, you’ll learn the
best practices in this article.
4. Build your image
Please run the following in terminal: docker build -t takacsmark/alpine-smarter:1.0
.
This command is structured as follows:
• docker build is the command to build a Docker image from a Dockerfile
•
-t takacsmark/alpine-smarter:1.0 defines the tag (hence -t) of the image, which will be
basically the name of the image. As the first part I put my own name takacsmark,
because I’m the maintainer of the image, then I gave it a human readable
name alpine-smarter and provided a version number 1.0.
• please note the . (dot) at the end of the line. You need to specify the directory
where docker build should be looking for a Dockerfile. Therefore . tells docker
build to look for the file in the current directory.
You should see a similar output in terminal now:
Cloud Computing – Docker Network
6
5. Enjoy the results
Docker created an image from your Dockerfile. You should see a new image in your image list
issuing docker images again.
Let’s check what’s inside our new image, let’s run the following command and check out vim
and curl: docker run --rm -ti takacsmark/alpine-smarter:1.0 /bin/sh
Right now you should be in the shell of your running container, so let issue the following
commands: vim --v and curl --version. You should be seeing the version of vim and curl
in your terminal.
We have successfully added two packages to the Alpine base image. Let’s not stop here, there
is more!
Understand image layering
If you look at the above screen shot again you can notice that docker build provided the
build output in 4 steps, namely Step 1/4, Step 2/4, Step 3/4 and Step 4/4.
Cloud Computing – Docker Network
7
At the headline of each step you can see the corresponding line in your Dockerfile. This is
because docker build executes the lines in the Dockerfile one at a time.
What is more important that with every step in the build process Docker will create an
intermediary image for the specific step. This means that Docker will take the base image
(alpine:3.4), then execute RUN apk update and then Docker will add the resulting files from
that step as another layer on top of the base image.
You can follow the concept by following the line in the output that start with ----> these lines
denote the image ids of intermediary images.
This means that the final Docker image consist of 4 layers and the intermediary layers are
also available on your system as standalone images. This is useful because Docker will use
the intermediary images as image cache, which means your future builds will be much faster
for those Dockerfile steps that you do not modify.
Let’s first see all the images that were created. Please issue the command docker images -
a in terminal.
You
this:
should
see
something
like
We used -a to list all images on your computer including intermediary images. Please note
how the image ids are the same as the ones you see during the build process.
Only RUN, COPY and ADD instructions create layers to improve build performance.
The main advantage of image layering lies in image caching.
If you build your Dockerfile again now with the same command docker build -t
Advertisement
takacsmark/alpine-smarter:1.0 ., you’ll notice that the build was almost instantaneous
and the output for every step says that the build was done from cache.
This behavior makes our lives a lot easier. Since image layers are built on top of each other
Docker will use images cache during the build process up to the line where the first change
occurs in your Dockerfile. Every later step will be re-built.
Please note that each layer only stores the differences compared to the underlying
layer. The video may be misleading from this perspective, because I interperet the sizes
in docker
images
-a differently. The
right
interpretation
is
that docker
images and docker images -a display the size of the image including the size of parent
images.
Cloud Computing – Docker Network
8
Image cache example
Let’s play with the cache a little bit. Let’s change our Dockerfile to see the behavior. Let’s
change the list line from adding curl to adding git. This is the resulting file:
FROM alpine:3.4
RUN apk update
RUN apk add vim
RUN apk add git
Let’s issue our build command again: docker build -t takacsmark/alpine-smarter:1.0
..
You’ll see that the first 3 steps run using cache and only the last step will be re-run, as shown
in the picture.
Please note that if you change an early step in the Dockerfile, for example you add one line
after apk update like this:
FROM alpine:3.4
RUN apk update
RUN apk add curl
RUN apk add vim
RUN apk add git
In this case every step after the change will be re-built. Which means that the steps to install
curl, vim and git will be run from scratch, no caching will be available beyond the point where
the change occured.
Cloud Computing – Docker Network
9
Dangling images
If you execute docker images now in terminal, you’ll see something nasty.
Our newly built image is ready to use, but the previous image that we built with curl is still
hanging around and it does not have a proper tag or name right now. (You can check the
image ids to see that this is the same image we built previously).
Docker calls such images dangling images.
You can use the following command to list dangling images:
docker images --filter "dangling=true"
I personally don’t like it when images are just hanging around without a purpose, so here is
how to remove them:
docker rmi $(docker images -q --filter "dangling=true").
Cloud Computing – Docker Network
10