Dockerfile tutorial

Level 1 - FROM, RUN, #, MAINTAINER

In this section we will cover the most important instructions: FROM and RUN. We will also see how to use the docker build command and how to specify the maintainer of the Dockerfile and how to insert comments.

Dockerfile instructions

All Dockerfile instructions look like this:

INSTRUCTION arguments

Instructions are not case sensitive, but we recommend to use capital letters.

The FROM instruction

The first instruction of every Dockerfile needs to be the FROM instruction

FROM image

It sets the base image for subsequent instructions.
Example:

FROM ubuntu

In this example, we chose ubuntu as our base image. ubuntu is a “General use Ubuntu base image” provided by the Docker team. You can find a list of available images from the command line by using the docker search command.
Example:

root@precise64:/home/vagrant/dockerfiles# docker search centos
Found 14 results matching your query ("centos")
NAME                             DESCRIPTION
centos
backjlack/centos-6.4-x86_64
creack/centos
mbkan/lamp                       centos with ssh, LAMP, PHPMyAdmin(root password 'toor' and MySQL root password 'sysadmin'). Auto starts sshd, MySQL and Apache. Just launch us...
zenosslabs/centos
slantview/centos-chef-solo       CentOS 6.4 with chef-solo.
tchap/centos-epel                The official centos image having EPEL added among its repositories.
backjlack/centos                 This repository contains the following images: Centos 5.9 (more to be added soon)
oss17888/centos6.4
markl/centos
troygoode/centos-node-hello
austin/centos-base
estrai/centos32                  Centos 5.9 32-bit based on an OpenVZ image.
comodit/centos

So let’s say you want to use centos as you base image, you can for instance use the following line:

FROM centos

You can also browse available images from Docker and the community online: index.docker.io

The RUN instruction

The RUN instruction will execute any commands on the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
Layering RUN instructions and generating commits conforms to the core concepts of Docker where commits are cheap and containers can be created from any point in an image’s history, much like source control.

RUN command

RUN command is equivalent to the docker commands: docker run image command + docker commit container_id, Where image would be replaced automatically with the current image, and container_id would be the result of the previous RUN instruction.
Example:

RUN apt-get install -y memcached

As we saw earlier, we need to have the FROM instruction before any RUN instruction, so that docker knows from which base image to start running the instruction on. For instance:

FROM ubuntu
RUN apt-get install -y memcached

This example creates an image with memcached installed on the ubuntu image. It is the equivalent to the following command lines:

root@precise64:/home/vagrant/dockerfiles# docker run ubuntu apt-get install -y memcached
[…]
[=> container id is 9fb69e798e67]
root@precise64:/home/vagrant/dockerfiles# docker commit 9fb69e798e67
6742949a1bae

docker build

Once you have your Dockerfile ready, you can use the docker build command to create your image from it. There are different ways to use this command:

  1. If your Dockerfile is in your current directory you can use docker build .
  2. From stdin. For instance: docker build - < Dockerfile
  3. From GitHub. For instance: docker build github.com/creack/docker-firefox
    In this last example, docker will clone the GitHub repository and use it as context. The Dockerfile at the root of the repository will be used to create the image.

Let’s run our last Dockerfile example.

root@precise64:/home/vagrant/dockerfiles# cat Dockerfile
FROM ubuntu
RUN apt-get install -y memcached
root@precise64:/home/vagrant/dockerfiles# docker build .
Uploading context 20480 bytes
Step 1 : FROM ubuntu
Pulling repository ubuntu
Pulling image 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c (precise) from ubuntu
Pulling image b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc (quantal) from ubuntu
Pulling b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc metadata
Pulling b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc fs layer
Downloading 10.24 kB/10.24 kB (100%)
Pulling 27cf784147099545 metadata
Pulling 27cf784147099545 fs layer
Downloading 10.24 kB/10.24 kB (100%)
Pulling 27cf784147099545 metadata
Pulling 27cf784147099545 fs layer
Downloading 94.86 MB/94.86 MB (100%)
 ---> 8dbd9e392a96
Step 2 : RUN apt-get install -y memcached
 ---> Running in dedc7af62d9f
Reading package lists...
Building dependency tree...
The following extra packages will be installed:
  libclass-isa-perl libevent-2.0-5 libgdbm3 libswitch-perl netbase perl
  perl-modules
Suggested packages:
  libcache-memcached-perl libmemcached perl-doc libterm-readline-gnu-perl
  libterm-readline-perl-perl make libpod-plainer-perl
The following NEW packages will be installed:
  libclass-isa-perl libevent-2.0-5 libgdbm3 libswitch-perl memcached netbase
  perl perl-modules
0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 8070 kB of archives.
After this operation, 32.8 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu/ precise/main libgdbm3 amd64 1.8.3-10 [35.3 kB]
Get:2 http://archive.ubuntu.com/ubuntu/ precise/main netbase all 4.47ubuntu1 [15.0 kB]
Get:3 http://archive.ubuntu.com/ubuntu/ precise/main libclass-isa-perl all 0.36-3 [11.9 kB]
Get:4 http://archive.ubuntu.com/ubuntu/ precise/main libevent-2.0-5 amd64 2.0.16-stable-1 [127 kB]
Get:5 http://archive.ubuntu.com/ubuntu/ precise/main perl-modules all 5.14.2-6ubuntu2 [3369 kB]
Get:6 http://archive.ubuntu.com/ubuntu/ precise/main perl amd64 5.14.2-6ubuntu2 [4417 kB]
Get:7 http://archive.ubuntu.com/ubuntu/ precise/main libswitch-perl all 2.16-2 [19.2 kB]
Get:8 http://archive.ubuntu.com/ubuntu/ precise/main memcached amd64 1.4.13-0ubuntu2 [75.3 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 8070 kB in 7s (1136 kB/s)
Selecting previously unselected package libgdbm3.
(Reading database ... 7545 files and directories currently installed.)
Unpacking libgdbm3 (from .../libgdbm3_1.8.3-10_amd64.deb) ...
Selecting previously unselected package netbase.
Unpacking netbase (from .../netbase_4.47ubuntu1_all.deb) ...
Selecting previously unselected package libclass-isa-perl.
Unpacking libclass-isa-perl (from .../libclass-isa-perl_0.36-3_all.deb) ...
Selecting previously unselected package libevent-2.0-5.
Unpacking libevent-2.0-5 (from .../libevent-2.0-5_2.0.16-stable-1_amd64.deb) ...
Selecting previously unselected package perl-modules.
Unpacking perl-modules (from .../perl-modules_5.14.2-6ubuntu2_all.deb) ...
Selecting previously unselected package perl.
Unpacking perl (from .../perl_5.14.2-6ubuntu2_amd64.deb) ...
Selecting previously unselected package libswitch-perl.
Unpacking libswitch-perl (from .../libswitch-perl_2.16-2_all.deb) ...
Selecting previously unselected package memcached.
Unpacking memcached (from .../memcached_1.4.13-0ubuntu2_amd64.deb) ...
Setting up libgdbm3 (1.8.3-10) ...
Setting up netbase (4.47ubuntu1) ...
Setting up libclass-isa-perl (0.36-3) ...
Setting up libevent-2.0-5 (2.0.16-stable-1) ...
Setting up perl-modules (5.14.2-6ubuntu2) ...
Setting up perl (5.14.2-6ubuntu2) ...
update-alternatives: using /usr/bin/prename to provide /usr/bin/rename (rename) in auto mode.
Setting up memcached (1.4.13-0ubuntu2) ...
Starting memcached: memcached.
Setting up libswitch-perl (2.16-2) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place
 ---> 1dcfa24c8ca6
Successfully built 1dcfa24c8ca6

You can see your newly created image 1dcfa24c8ca6 in the ouput of docker images:

root@precise64:/home/vagrant/dockerfiles# docker images
REPOSITORY          TAG                 ID                  CREATED              SIZE
ubuntu              12.04               8dbd9e392a96        4 months ago         131.5 MB (virtual 131.5 MB)
ubuntu              12.10               b750fe79269d        4 months ago         24.65 kB (virtual 180.1 MB)
ubuntu              latest              8dbd9e392a96        4 months ago         131.5 MB (virtual 131.5 MB)
ubuntu              precise             8dbd9e392a96        4 months ago         131.5 MB (virtual 131.5 MB)
ubuntu              quantal             b750fe79269d        4 months ago         24.65 kB (virtual 180.1 MB)
<none>              <none>               1275893fed44        9 minutes ago        12.3 kB (virtual 566.4 MB)
<none>               <none>               1dcfa24c8ca6        About a minute ago   52.27 MB (virtual 183.8 MB)

Note that it does not have a name yet. Let’s name it with the command docker tag.

root@precise64:/home/vagrant/dockerfiles# docker tag 1dcfa24c8ca6 memcached
root@precise64:/home/vagrant/dockerfiles# docker images
REPOSITORY          TAG                 ID                  CREATED             SIZE
ubuntu              12.04               8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              12.10               b750fe79269d        4 months ago        24.65 kB (virtual 180.1 MB)
ubuntu              latest              8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              precise             8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              quantal             b750fe79269d        4 months ago        24.65 kB (virtual 180.1 MB)
memcached           latest              1dcfa24c8ca6        4 minutes ago       52.27 MB (virtual 183.8 MB)
<none>              <none>             1275893fed44        12 minutes ago      12.3 kB (virtual 566.4 MB)

The good news is that docker build comes with the option -t with which you can directly tag the (last) image created with the Dockerfile. So we could have used docker build -t memcached . directly.

root@precise64:/home/vagrant/dockerfiles# docker build -t memcached_new .
Uploading context 20480 bytes
Step 1 : FROM ubuntu
[…]
Step 2 : RUN apt-get install -y memcached
[…]
Successfully built 1dcfa24c8ca6
root@precise64:/home/vagrant/dockerfiles# docker images
REPOSITORY          TAG                 ID                  CREATED             SIZE
ubuntu              12.04               8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              12.10               b750fe79269d        4 months ago        24.65 kB (virtual 180.1 MB)
ubuntu              latest              8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              precise             8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              quantal             b750fe79269d        4 months ago        24.65 kB (virtual 180.1 MB)
memcached_new       latest              1dcfa24c8ca6        4 minutes ago       52.27 MB (virtual 183.8 MB)
<none>              <none>              1275893fed44        4 minutes ago      12.3 kB (virtual 566.4 MB)

Creating a memcached image with a Dockerfile

We have written almost all of it in the previous sections.

FROM ubuntu
RUN apt-get install -y memcached

But we want to ensure that the ubuntu package repository is up to date. With the command line we would do:

root@precise64:/home/vagrant/dockerfiles# echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
root@precise64:/home/vagrant/dockerfiles# apt-get update

Within the Dockerfile, we will use the RUN instruction.

RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update

So our final Dockerfile looks like this:

FROM ubuntu
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y memcached

Note that this Dockerfile would be equivalent to the following command lines:

root@precise64:/home/vagrant/dockerfiles# docker run ubuntu echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
[…]
[=> container id is 72d2a39bc64d]
root@precise64:/home/vagrant/dockerfiles# docker commit 72d2a39bc64d
d7a97544c0c7
root@precise64:/home/vagrant/dockerfiles# docker run d7a97544c0c7 apt-get update
[…]
[=> container id is 66b22a0ef7c9]
root@precise64:/home/vagrant/dockerfiles# docker commit 66b22a0ef7c9
a5f142a604b3
root@precise64:/home/vagrant/dockerfiles# docker run a5f142a604b3 apt-get install -y memcached
[…]
[=> container id is 9fb69e798e67]
root@precise64:/home/vagrant/dockerfiles# docker commit 9fb69e798e67
6742949a1bae

Let’s create our image. We will use the -t option with docker build in order to give a name to our image.

root@precise64:/home/vagrant/dockerfiles# cat Dockerfile
FROM ubuntu
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y memcached
root@precise64:/home/vagrant/dockerfiles# docker build -t brand_new_memcached - < Dockerfile
Uploading context 2048 bytes
Step 1 : FROM ubuntu
 ---> 8dbd9e392a96
Step 2 : RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
 ---> Using cache
 ---> 913c2344b312
Step 3 : RUN apt-get update
 ---> Using cache
 ---> 0a77b6e48393
Step 4 : RUN apt-get install -y memcached
 ---> Running in d1eadc19edc6
Reading package lists...
Building dependency tree...
The following extra packages will be installed:
  libclass-isa-perl libevent-2.0-5 libgdbm3 libswitch-perl netbase perl
  perl-modules
[…]
Starting memcached: memcached.
Setting up libswitch-perl (2.16-2) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place
 ---> 782a37534312
Successfully built 782a37534312

The id of the image is 782a37534312 but it already has a name as we can verify with docker images:

root@precise64:/home/vagrant/dockerfiles# docker images
REPOSITORY            TAG                 ID                  CREATED             SIZE
memcached_new         latest              1dcfa24c8ca6        12 minutes ago      52.27 MB (virtual 183.8 MB)
brand_new_memcached   latest              782a37534312        54 seconds ago      74.7 MB (virtual 350.7 MB)
ubuntu                12.04               8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                12.10               b750fe79269d        4 months ago        24.65 kB (virtual 180.1 MB)
ubuntu                latest              8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                precise             8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                quantal             b750fe79269d        4 months ago        24.65 kB (virtual 180.1 MB)
memcached             latest              1dcfa24c8ca6        12 minutes ago      52.27 MB (virtual 183.8 MB)
<none>                <none>             1275893fed44        21 minutes ago      12.3 kB (virtual 566.4 MB)

Congratulations! You just created your first image with a Dockerfile :)

You can verify that memcached is installed in your image by running these commands:

root@precise64:/home/vagrant/dockerfiles# docker run -i -t brand_new_memcached /bin/bash
root@c28a2c4be825:/# memcached
can't run as root without the -u switch

Commenting

Code should always be commented. The same rule applies to the Dockerfile. A character # at the beginning of a line defines a comment. The comments are not exectuted. Comments are not mandatory, but we recommend using them to:

  • Give a title and/or describe the purpose of the Dockerfile
  • Give the version of your Dockerfile
  • Comment individual Dockerfile lines and instructions
So the Dockerfile to create a memcached image becomes:

# Memcached
#
# VERSION       1.0

# use the ubuntu base image provided by dotCloud
FROM ubuntu

# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update

# install memcached
RUN apt-get install -y memcached

The MAINTAINER instruction

As you could expect, the MAINTAINER instruction is used to specify name and contact information of the maintainer of the Dockerfile.
Example:

MAINTAINER Guillaume J. Charmes, guillaume@dotcloud.com

The final version of the Dockerfile becomes

# Memcached
#
# VERSION       1.0

# use the ubuntu base image provided by dotCloud
FROM ubuntu
MAINTAINER Guillaume J. Charmes, guillaume@dotcloud.com
# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update

# install memcached
RUN apt-get install -y memcached

Test your Dockerfile skills - Level 1

Questions

What is the Dockerfile instruction to specify the base image ?

What is the Dockerfile instruction to execute any commands on the current image and commit the results?

What is the Dockerfile instruction to specify the maintainer of the Dockerfile?

What is the character used to add comment in Dockerfiles?

Fill the Dockerfile

Your best friend Eric Bardin sent you a Dockerfile, but some parts were lost in the ocean. Can you find the missing parts?

# This is a Dockerfile to create an image with Memcached and Emacs installed.
#
# VERSION       1.0

# use the ubuntu base image provided by dotCloud
 ub

 E B, eric.bardin@dotcloud.com

# make sure the package repository is up to date
 echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
 apt-get update

# install memcached
RUN apt-get install -y 

# install emacs
 apt-get install -y emacs23

What's next?

In the next level, we will go into more detail about how to specify which command should be executed when the container starts, which user to use, and how expose a particular port.

Go to the next level