What is a Dockerfile?

Diane Khambu
5 min readMar 14, 2022
Photo by Hans Veth on Unsplash

In this article we’ll learn about Dockerfile and create a simple container based on it!

When I first saw a Docker logo 🐳 few years ago, timeline wise it was after completing graduate school, thought it was cute and clever. It must have been a buzz word then. Tried two tutorials on it just to start making hands dirty. Now have to intermittently come across tasks that involves dockerizing builds. Given I have also spent some time to learn more about it, let’s dive in to get a comprehensive overview of creation of a Dockerfile and where it stands in the world of containerization.

I am presuming you have some idea on what a Docker is. Give it a quick read if you want a primer or otherwise. Here is the git repository for the tutorial.

Let’s see a sample Dockerfile :

My current directory structure using command tree . looks like this:

.├── Dockerfile└── index.html0 directories, 2 files

In the COPY command, I copied index.html file from my current directory to container’s /usr/share/nginx/html directory. We set the path /usr/share/nginx/html as our working directory using WORKDIR command. The RUN command updates and install vim to the custom container we are making based out of image nginx:1.21.6 . The first command FROM is the base image we are using. You can see this base nginx:1.21.6 image at the official docker registry. Now, if you look at the Dockerfile of the nginx:1.21.6 image in the registry, it is using Debian operating system image version bullseye-slim .

screenshot of nginx:1.21.6’s Dockerfile

See, we are basically building on top of some other previous images. In addition we can see history of an image using docker history <image-name> command.

docker history server-1:1.0.0

image history

General pattern of docker command line is:

docker <command> <subcommand> (options)

Now that we have walked over the custom Dockerfile , let’s build an image from it:

docker image build -t server-1:1.0.0 .

-t flag is a tag consisting of name and optional tag in the form <name>:<version> . Here, we gave server-1:1.0.0 .

. is a path to a Dockerfile . Here, the Dockerfile is present in the same location as where we are running the command.

The output of the command looks something like this:

output of `docker image build` command

Now the image is ready, let’s instantiate it and make a container!

docker container run -it -d -p 80:80 --name hello-world server-1:1.0.0

-it is for interactive and pseudo TTY (terminal interacts with TeleTypewriter)

-d is for detaching the container

-p is for port. Digits before : is of host and after is that of a container. We need to expose the port in Dockerfile . In our custom Dockerfile we inherited it from the base nginx:1.21.6 dockerfile.

--name is for name of the container.

Since nginx is a web-server, if we go to https://127.0.0.1:80 in your browser, you should see your index.html page rendered:

screenshot of the localhost:80

Now let’s go inside the running container hello-world and edit the index.html file.

docker container exec -it hello-world /bin/bash

exec is for running command in the running container

/bin/bash is the path to the bash shell.

You would be in the /usr/share/nginx/html directory, the directory we set from WORKDIR command. You’ll see index.html file. Add few line using vi editor and save it.

Now when you go to the http://127.0.0.1:80 and refresh the page, the newly added contents are seen!

screenshot of the localhost:80

You can exit out of the container using exit command. You can list running containers using docker container ls . Let’s stop the container and delete it.

docker container stop hello-world
docker container rm hello-world

It’s been recommended to put the least used command such as LABEL , ENV at the top of the Dockerfile while the most used command such as COPY at the end of the Dockerfile. This way we make re-run commands from where the changes were made to be as small as possible.

In addition to the building images and creation of containers, some other useful commands are:

  • docker container top <name-of-container>: List all processes running in the container. You can think of it as a container specific version of ps aux .
  • docker container inspect <name-of-container> : Details about the container’s configuration.
  • docker container stats <name-of-container> : Performance statistics of the container.
  • docker network ls : show networks
  • docker network inspect <name-of-network> : Details about the container

This is just about creating a single container and running it. What if we have multiple containers and have dependencies between them? That’s when we have docker-compose . In the example above we do not have some kind of persistent data storage service such as postgres. The docker-compose helps us to integrate these two different images.

For production grade orchestration of these different containers, we have tools like docker’s swarm or kubernetes.

In summary, Dockerfile is a sequence of commands to create an image. From the image we can create containers.

That’s all for the article. I hope this gave you a basic understanding of a Dockerfile and how it stands in respect to orchestration tools.

Thank you for reading.

Inspiration:

You can support me on Patreon! 🦦

--

--