Post

Docker pt 1: Create a Docker Image (DevOps the Hard Way series)

Docker pt 1: Create a Docker Image (DevOps the Hard Way series)

So far in the DevOps the Hard Way series, the focus has been on building the cloud infrastructure that is required to run and store containerized software. On the other hand, this next pair of posts will focus on preparing the software that will be run on said infrastructure.

While containerized software can strongly benefit both software developers and system operators, this section is about implementing containerization rather than the reasoning for doing so.

Since it has been decided in this scenario that the Uber API software should be containerized, the Docker platform is introduced into the workflow. Per the Docker website:

Docker is an open platform for developing, shipping, and running applications.

The Dockerfile

While building a containerized image for the Uber API, we start with a Dockerfile, which is a text file containing a list of individual docker commands. Each command in the file builds on the previous one, in order to define a software container image. The author of the Devops the Hard Way repository provides the following Dockerfile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM python:latest

RUN mkdir /build
WORKDIR /build

COPY app /build

COPY app/requirements.txt /build

RUN pip install -r requirements.txt

EXPOSE 5000

CMD [ "python", "app.py" ]

Understanding the Dockerfile

Below is a line-by-line breakdown of the file, including command descriptions from the Dockerfile reference page.

FROM

1
FROM python:latest

The FROM instruction initializes a new build stage and sets the base image for subsequent instructions.

In this first line, the base image is set to the latest version of the official python Docker image.

That image provides a standardized, portable, self-contained Python runtime environment. Since the Uber API to be containerized is coded in Python, the official Python Docker image is an intuitive choice of base image to start the build stage FROM.

The rest of the commands in the Dockerfile “build up” a customized container image step-by-step, adding more to the container image with each command.

RUN

1
RUN mkdir /build

The RUN instruction will execute any commands to create a new layer on top of the current image. The added layer is used in the next step in the Dockerfile.

The RUN command in this Dockerfile adds a /build directory to the base python container image.

WORKDIR

1
WORKDIR /build

The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile.

COPY

1
2
3
COPY app /build

COPY app/requirements.txt /build

The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .

These two lines tell Docker to copy the specified local files into the /build directory inside the new container image. When working with this Dockerfile, it is assumed by its author that the app directory from this GitHub link (which contains the standard, non-containerized Uber API) is saved locally in the same directory as Dockerfile.

At this point, the built-up image is:

  • the official Python image, with an added /build directory, containing:

RUN

1
RUN pip install -r requirements.txt

The RUN instruction will execute any commands to create a new layer on top of the current image. The added layer is used in the next step in the Dockerfile.

Next, the pip command is run to install all of the python packages required by the Uber API. That way, when containers are eventually created from this image, they will already have both the Uber API and its dependencies pre-installed and ready to run.

EXPOSE

1
EXPOSE 5000

The EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime.

This line specifies that the container is exposing TCP port 5000 to the container runtime. As a result, the containerized software is network-accessible from outside the container via that port, e.g. from a client computer’s web browser via http://hostname:5000.

CMD

1
CMD [ "python", "app.py" ]

The CMD instruction sets the command to be executed when running a container from an image.

This last line of Dockerfile ensures that the containerized API is automatically started up as soon as a container is run from this image.

Creating the Docker image

With the Dockerfile and a copy of the Uber API saved locally, we are ready to build a container image for the Uber API.

1
2
$ ls
app   Dockerfile

docker build

We build the image using the Docker cli:

1
$ docker build -t uberapp .
  • the -t option is for “tag,” used to name the image/repository for later reference
  • uberapp is the value for the above option
  • . specifies that the Dockerfile to reference during build is in the current directory

This can take some time as it involves some downloading and automated installation. Once the command completes, we can also verify the image using the Docker cli.

1
2
3
4
$ docker image ls

REPOSITORY   TAG       IMAGE ID       CREATED              SIZE
uberapp      latest    113aa98018a5   About a minute ago   1.05GB

As we can see, a new container image with a tag of uberapp was successfully created and is about 1GB in size.

In the next post, we will start working with our new container image, using it to start up a container, and saving it to the Amazon Elastic Container Registry created earlier in this series.

This post is licensed under CC BY-NC-SA 4.0 by the author.