Docker allows you to build containers using a Dockerfile. The Dockerfile describes a base image for the build using the FROM
instruction. FROM
implicitly uses a image registry from which the base image is pulled. This can be docker.io
or some other (perhaps internal) registry.
The additional layers of a Docker container are created with directives within the Dockerfile. The RUN
directive is used to run commands in running image. Extra packages can be installed using the RUN
instruction and the Linux distribution’s package installation tool. For Fedora and Red Hat Enterprise Linux this tool is yum
. Scripts and other content can be added to the layer by using the ADD
instruction from local directories or a URL.
Once you’ve added the required additional layers to your base image to make your specific application, you can create an image and add it to a registry for re-use.
These three instructions are the basics for building containers using the Dockerfile. A simple example:
FROM fedora
RUN yum install -y gcc
ADD ./myprogramfiles.tar /tmp
Two Approaches to Image Building
There are two approaches to building Docker images.
Consider the following example: an administrator would like to deploy a new simple web site using Docker container technology.
The administrator decides that the image needs three components:
- Debian base image
- Apache Web server
- Web site content
The administrator can build the image in one of the two following ways:
- Interactively, by launching a BASH shell under Debian to apt-get install Apache and its dependencies, and then save the image
- Create a Dockerfile that builds the image with the web site included
The first approach involves the administrator using the Docker CLI to instantiate the base image, install the Apache web server, and then create a reusable image for later use with the web site content. In this scenario, the base Debian + Apache image can be used as a base for any project that requires those tools.
The second approach involves building a Dockerfile that uses the base Debian image, installs the needed Apache packages, and then adds the necessary content. This ensures that the entire web site is complete in one build. The image created by this build will only serve a single web site and content changes would require a rebuild.
Interactively Building a Debian Container
There is an official image called debian
(the latest Debian version) in the public Docker registry. For more information on this image and the options available, check the repository page.
To run a container with an interactive shell, run the following Docker command on the BHost VPS:
docker run -it debian bash
Then from with the docker shell environment start building your customised image
apt-get update
apt-get upgrade
apt-get install apache2 php5
apt-get clean
exit
We now save the container as a base image in our local repository for future use using docker commit [imagename] [userspace]/debian-php
Check you now have the two Debian images docker images
. Now we can use our own image as the basis of a website. Here is a Dockerfile to do this
## Use the image we just created
FROM [userspace]/debian-php
MAINTAINER [yourname]
# Add the tar file of the web site
ADD website_content.tar /tmp/
# Docker automatically extracted. So move files to web directory
RUN mv /tmp/mysite/* /var/www/html && chown -R www-data:www-data /var/www/html
COPY httpd-foreground /usr/local/bin/
EXPOSE 80
CMD ["httpd-foreground"]
You can use this simple Dockerfile as a template for building other web sites. This and the other two files required to build this tutorial can be downloaded from this GitHub directory https://github.com/blackdoginet/BHost-docker-tutorials/tree/master/createcontainer
The Docker build context passed to the daemon requires both the Dockerfile and the content for the site. The path for this build is ., but in practice you should create separate build contexts (directory) for each container.
docker build -rm -t mysite .
docker run -d -p 80:80 mysite
You should now be able to visit your site at your hosts IP address
Using a Dockerfile to Build a DEBIAN Container
The administrator may decide that building interactively is tedious and error-prone. Instead the administrator could create a Dockerfile that layers on the Apache Web server and the web site content in one build.
A good practice is to make a sub-directory with a related name and create a Dockerfile in that directory. E.g. a directory called mongo may contain a Dockerfile for a MongoDB image, or a directory called httpd may container an Dockerfile for an Apache web server. Copy or create all other content that you wish to add to the image into the new directory. Keep in mind that the ADD directive context is relative to this new directory.
mkdir httpd
cp mysite.tar httpd/
Create the Dockerfile in the httpd directory. This Dockerfile will use the same base image as the interactive command debian:
FROM debian
MAINTAINER A D Ministator email: This email address is being protected from spambots. You need JavaScript enabled to view it.
# Update the image with the latest packages (recommended)
RUN apt-get update && apt-get upgrade -y && apt-get clean
# Install Apache Web Server
RUN apt-get install -y apache2 && apt-get clean
# Add the tar file of the web site
ADD mysite.tar /tmp/
# Docker automatically extracted. So move files to web directory
RUN mv /tmp/mysite/* /var/www/html
COPY httpd-foreground /usr/local/bin/
EXPOSE 80
CMD ["httpd-foreground"]
Build this Dockerfile from the new httpd directory and run it:
docker build -rm -t newsite httpd/
docker run -d -P newsite
The container build process builds a series of temporary image layers based on the directives in the Dockerfile. These temporary layers are cached so if you make modifications to the content tarball, it won’t completely rebuild and update the Debian image. Since each directive is a new layer, you could reduce the number of layers by combining the RUN apt-get
directives into a single RUN
directive:
RUN apt-get update && apt-get upgrade -y && apt-get clean
Planning your layers will determine how many layers need to be recreated on each build of the container.
Which Approach is Right?
The approach to building images depends on why you are building the image.
Prototyping and Troubleshooting
If prototyping and trouble shooting then you probably want to do an interactive, *inside the container*
approach. Using this approach you can take notes of the history of commands used that make sense and what external files may be missing or need changes. These can be ADDed to the Dockerfile.
Complete Satisfactory Single Build
If you are satisfied with a specific image that has been built using the interactive approach and you believe it might be reused elsewhere, then it is recommended to use the single Dockerfile approach that builds it all in one build.
Now you know how to build and experiment with your own images take a look at some examples on Docker Hub and Git Hub to see just what can be accomplished within a docker container.
Note:
Each RUN
command in effect opens up a new bash shell in your image at root level i.e. / so if you want to issue consecutive commands in the same directory either
- specify the directory implicitly in each
RUN
command,
or
- chain commands using the operating systems method e.g. && for Debian with a \ character to show new lines
or
- specify a
WORKDIR
for the remaining commands