One of the powerful things about Docker is that it is possible for someone to use Docker every day without ever having to create their own custom container. In today's article, we are going to explore a few uncommon ways to build a Docker container.
The docker build
command has many options that can be considered uncommon or only used for special situations. In this article, we are specifically going to focus on different ways to provide the docker build
command a source or context to build from.
To explain this better, let's first explore the traditional build approach.
Traditional Approach
The traditional build approach essentially consists of executing the docker build
command within a directory that contains a Dockerfile
. Let's see this approach in action with the below example.
$ docker build -t automatron . Sending build context to Docker daemon 4.368MB Step 1/9 : FROM ubuntu:14.04 ---> 3f755ca42730 Step 2/9 : RUN apt-get update --fix-missing && apt-get -y upgrade && apt-get -y install python-pip python-dev nmap curl libffi-dev build-essential libssl-dev ---> Using cache ---> 901e767bce5a Step 3/9 : ADD requirements.txt / ---> Using cache ---> d8e0c2f89a72 Step 4/9 : RUN pip install --upgrade setuptools ---> Using cache ---> d62382ab676f Step 5/9 : RUN pip install -r /requirements.txt ---> Using cache ---> cca17f716d3d Step 6/9 : RUN pip install honcho ---> Using cache ---> 62293cc90b19 Step 7/9 : ADD . / ---> Using cache ---> 808d0bdf961d Step 8/9 : RUN find -name "*.sh" -exec chmod 755 {} \; ---> Using cache ---> 353248eb9652 Step 9/9 : CMD honcho start ---> Using cache ---> 0c650b43b3d4 Successfully built 0c650b43b3d4 Successfully tagged automatron:latest
During the docker build
execution shown above, we specify two options. The first being the -t
flag; as we explored in an earlier article, the -t
flag is used to "tag" or name the resulting image. In the example above, we simply named the container automatron
.
The second option is .
; this option is the context or source that the docker build
command should use during the build. By specifying .
, we are specifying that Docker should execute the build using the current working directory as the context. What this means is that docker build
will look for a Dockerfile
(the instruction file for building containers) within the specified directory.
If we were to execute this command from one directory higher, our command would look like the following example:
$ docker build -t automatron automatron/ Sending build context to Docker daemon 4.368MB Step 1/9 : FROM ubuntu:14.04 ---> 3f755ca42730 Step 2/9 : RUN apt-get update --fix-missing && apt-get -y upgrade && apt-get -y install python-pip python-dev nmap curl libffi-dev build-essential libssl-dev && rm -rf /var/lib/apt/lists/* ---> Using cache ---> 901e767bce5a Step 3/9 : ADD requirements.txt / ---> Using cache ---> d8e0c2f89a72 Step 4/9 : RUN pip install --upgrade setuptools ---> Using cache ---> d62382ab676f Step 5/9 : RUN pip install -r /requirements.txt ---> Using cache ---> cca17f716d3d Step 6/9 : RUN pip install honcho ---> Using cache ---> 62293cc90b19 Step 7/9 : ADD . / ---> Using cache ---> 808d0bdf961d Step 8/9 : RUN find -name "*.sh" -exec chmod 755 {} \; ---> Using cache ---> 353248eb9652 Step 9/9 : CMD honcho start ---> Using cache ---> 0c650b43b3d4 Successfully built 0c650b43b3d4 Successfully tagged automatron:latest
The commands above should be familiar to anyone who regularly builds custom Docker containers. However, the approach above is not the only way we can pass context to the docker build
command.
Building From a Git Repository
In the above example, we built a container for the open-source project Automatron. Since this is a project hosted on GitHub and this project contains a Dockerfile
in its top level directory, we can streamline this docker build
process by building directly from the Git repository.
$ docker build -t automatron https://github.com/madflojo/automatron.git Sending build context to Docker daemon 1.938MB Step 1/9 : FROM ubuntu:14.04 ---> 3f755ca42730 Step 2/9 : RUN apt-get update --fix-missing && apt-get -y upgrade && apt-get -y install python-pip python-dev nmap curl libffi-dev build-essential libssl-dev ---> Using cache ---> 956f75f19219 Step 3/9 : ADD requirements.txt / ---> Using cache ---> 23a02980ee87 Step 4/9 : RUN pip install --upgrade setuptools ---> Using cache ---> 36069877f17b Step 5/9 : RUN pip install -r /requirements.txt ---> Using cache ---> 083745ce4316 Step 6/9 : RUN pip install honcho ---> Using cache ---> 2bd024e0890d Step 7/9 : ADD . / ---> 58b5b6d021c7 Removing intermediate container d3b2db67817f Step 8/9 : RUN find -name "*.sh" -exec chmod 755 {} \; ---> Running in 5e0d91149c94 ---> 53f04392979a Removing intermediate container 5e0d91149c94 Step 9/9 : CMD honcho start ---> Running in 9cd301a364cf ---> fb62cbb68063 Removing intermediate container 9cd301a364cf Successfully built fb62cbb68063 Successfully tagged automatron:latest
In the first example, the traditional build method. We had a copy of the Automatron project cloned to our local system. When we executed the build, we did so using a local directory. In the example above, building from a Git repository. We simply use the Git repository URL as the context for the docker build
command.
When executed in this manner, Docker will clone the remote Git repository and perform the build using the cloned repository as its context.
!Sign up for a free Codeship Account
Understanding Build Context
When talking about Docker builds, context means the source directory used when building the container. To explain this a bit better, let's look at the docker build
output.
Step 3/9 : ADD requirements.txt / ---> Using cache ---> 23a02980ee87 Step 4/9 : RUN pip install --upgrade setuptools ---> Using cache ---> 36069877f17b Step 5/9 : RUN pip install -r /requirements.txt ---> Using cache ---> 083745ce4316
In both the traditional and Git examples, these lines were part of the build output. These are Docker build steps that are specified within the Automatron Dockerfile
.
The first step (step 3 of 9) is ADD requirements.txt /
. This step will add the requirements.txt
file into the Docker container image being built.
In the first example, the traditional local directory approach. The requirements.txt
was copied from the local directory (the context directory) into the Docker container. This is the type of functionality we are used to with a basic build.
Where the second example -- the Git example -- differs is that the Git repository is used as the context directory. What this means is that when the ADD
instruction executed, it added the requirements.txt
file from the Git repository itself, not the local directory.
To explain this a little better, even if I have a requirements.txt
file in the current working directory, the requirements.txt
that is added will not be from my local directory, but rather the requirements.txt
hosted on the Git repository.
This is an important concept to understand not only for this article, but when building Docker containers in general. As many times when troubleshooting why the ADD
or COPY
instructions fail, it is often they are trying to reference something outside of the build context.
Building From a Tar File
In addition to building containers using a remote Git repository, the docker build
command is also able to take remote TAR files as build context.
Let's take a look at this in action to get a better understanding.
$ docker build -t automatron http://example.com/automatron.tar.gz Step 1/9 : FROM ubuntu:14.04om remote url: http://example.com/automatron.tar.gz [==================================================>] 2.418MB/2.418MB ---> 3f755ca42730 Step 2/9 : RUN apt-get update --fix-missing && apt-get -y upgrade && apt-get -y install python-pip python-dev nmap curl libffi-dev build-essential libssl-dev && rm -rf /var/lib/apt/lists/* ---> Using cache ---> 901e767bce5a Step 3/9 : ADD requirements.txt / ---> Using cache ---> 67206f314a21 Step 4/9 : RUN pip install --upgrade setuptools ---> Using cache ---> ea61de8843be Step 5/9 : RUN pip install -r /requirements.txt ---> Using cache ---> bdefd81afb47 Step 6/9 : RUN pip install honcho ---> Using cache ---> 16c4ca480eca Step 7/9 : ADD . / ---> Using cache ---> 8cce790d2b46 Step 8/9 : RUN find -name "*.sh" -exec chmod 755 {} \; ---> Using cache ---> 3a9f60aadff7 Step 9/9 : CMD honcho start ---> Using cache ---> 7e95852e0e16 Successfully built 7e95852e0e16 Successfully tagged automatron:latest
The above docker build
execution is similar to the Git example except for one difference. Rather than the target context being a Git repository, it is a remote TAR file. I am specifying that the TAR file is remote because the docker build
command (at the time of this article) does not support using a local TAR file as the build context.
What it does support is downloading a TAR file via HTTP, extracting that TAR, and using its contents for the build context directory. In the example above, the TAR file was compressed using gzip
; the docker build
command currently supports both the bzip
and gzip
compression formats.
Summary
In this article, we explored three different ways to provide build context to the docker build
command. These methods can be useful when the container to be built is provided via a TAR or Git repository, as executing the builds by specifying the remote location can save several execution steps.