Writing your first Dockerfile

Every Docker-based environment starts with Dockerfile. Dockerfile is a format description of how to create a Docker image. You can think about the Docker images in a similar way to how you would think about images of virtual machines. It is a single file (composed of many layers) that encapsulates all system libraries, files, source code, and other dependencies that are required to execute your application.

Every layer of a Docker image is described in the Dockerfile by a single instruction in the following format:

INSTRUCTION arguments

Docker supports plenty of instructions, but the most basic ones that you need to know in order to get started are as follows:

To properly illustrate the typical structure of Dockerfile, let's assume that we want to dockerize the built-in Python web server available through the http.server module with some predefined static files that this server should serve. The structure of our project files could be as follows:

.
├── Dockerfile
├── README
└── static
├── index.html
└── picture.jpg

Locally, you could run that Python's http.server on a default HTTP port with the following simple command: 

python3.7 -m http.server --directory static/ 80

This example is of course, very trivial, and using Docker for it is using a sledgehammer to crack a nut. So, just for the purpose of this example, let's pretend that we have a lot of code in the project that generates these static files. We would like to deliver only these static files, and not the code that generates them. Let's also assume that the recipients of our image know how to use Docker but don't know how to use Python.

So, what we want to achieve is the following:

With all these requirements, our Dockerfile could take the following form:

# Let's define base image.
# "python" is official Python image.
# The "slim" versions are sensible starting
# points for other lightweight Python-based images
FROM python:3.7-slim

# In order to keep image clean let's switch
# to selected working directory. "/app/" is
# commonly used for that purpose.
WORKDIR /app/

# These are our static files copied from
# project source tree to the current working
# directory.
COPY static/ static/

# We would run "python -m http.server" locally
# so lets make it an entry point.
ENTRYPOINT ["python3.7", "-m", "http.server"]

# We want to serve files from static/ directory
# on port 80 by default so set this as default arguments
# of the built-in Python HTTP server
CMD ["--directory", "static/", "80"]

Let's take a look at how to run containers in the next section.