A quick guide to writing a Dockerfile and building a Docker image
6 minutes
Introduction
A Dockerfile is a text document that contains simple instructions for building Docker images from scratch. During build time, the command docker build
tells Docker to build the image by following the commands (instructions) specified in the Dockerfile.
The instructions in the Dockerfile may include installing dependencies, copying files, setting environment variables, exposing ports, and few more. Each Dockerfile instruction contributes to the creation of Docker image that can be used to create containers.
In this article, we will go through the steps of building a Dockerfile and creating a Docker image from CLI.
Why do we need Dockerfile?
We need a Dockerfile to build docker image from the given instructions from it. By providing instructions in a Dockerfile, it acts as a recipe for building a Docker image. These instructions lets you define environment and configuration of the container within which the application will run.
Essentially, a Dockerfile specifies a set of guidelines about structure of image, dependencies and how the application should behave within the container.
Moreover, A Dockerfile imparts developers to have a complete control over the application runtime environment and ensures all requirements are meet for running container applications.
Prerequisites
The only prerequisite for Dockerfile is Docker is installed in your system. Follow this guide if Docker is not installed in your system.
Creating a Dockerfile
Let’s find out how to create a Dockerfile and write instructions in it. We will create a dockerfile for a Python application and will have the following points.
- The Dockerfile will define environments for a Python-based flask web application.
- The instructions in the Dockerfile will maintain a logical step-by-step order.
- The instructions in the Dockerfile will use the existing standard instructions like
FROM
,ENV
,EXPOSE
, and many more.
Let's name our web application flask-app. The Dockerfile and the codes/structure for the Flask web application are available on GitHub. For reference, the structure of the web application is given below.
As shown above, the folder for the flask application(flask-app
) encapsulates the Dockerfile, dependencies, and other resources for Docker to build image by reading instructions from the Dockerfile.
The Dockerfile reference for the flask application is listed next.
# Starting point, a base image
FROM python:3.8
# Working directory for the web app
WORKDIR /usr/src/app
# Copy all the files to the container
COPY . .
# Install web application dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Web app port number that the container should expose
EXPOSE 5000
# Run the web application
CMD ["python", "./app.py"]
Dockerfile instructions
The instructions that you write in the Dockerfile start with a specific word(in capital letters) that dictates how to build a Docker image. The Dockerfile instructions we used in the Dockerfile are:
FROM
The Dockerfile FROM
instruction specifies the base image for the new image. All the subsequent instructions from the Dockerfile will be executed on this base image.
WORKDIR
Define the working directory and it is used in conjunction with subsequent RUN
, CMD
, ENTRYPOINT
, COPY
, and ADD
instructions.
COPY
Copy files, directories, and any other resources to the Docker image.
RUN
This instruction is used to execute commands.
EXPOSE
The EXPOSE
instruction is used to inform users about the ports the application is listening on.
CMD
It provides a default command to run along with parameters if any for the container.
The second part of the instructions in a Dockerfile are similar to the Linux commands. For example, the Dockerfile syntax to create a folder in a WORKDIR
say /usr/src/app is:
...
...
WORKDIR /usr/src/app
RUN mkdir -p image
...
...
There are 18 Dockerfile instructions and are:
FROM, MAINTAINER, RUN, CMD, ENTRYPOINT, ADD, COPY, EXPOSE, ENV, VOLUME, WORKDIR, USER, ARG, ONBUILD, STOPSIGNAL, LABEL, HEALTHCHECK, SHELL.
Any of these commands or instructions in a Dockerfile are invoked by the user on the CLI to assemble an docker image.
Create Docker image
Once you complete writing instructions in the Dockerfile and compiled codes, and other resources needed by the application - build Docker image with the docker build command. The image build process will start from the first line by pulling the python:3.8
image which is known as Dockerfile base/parent image and will proceed sequentially one by one.
Run the following command to builld docker image. You can view the output of the image build process on the screen. If everything goes fine, your docker image from Dockerfile should be ready!
$ cd ~/flask-app
$ ~/flask-app$ docker build .
[+] Building 521.2s (10/10) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 340B 0.0s
=> [internal] load metadata for docker.io/library/python:3.8 7.0s
=> [auth] library/python:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/4] FROM docker.io/library/python:3.8@sha256:6ea16099cac9f66419d1fc3a63aaa9d783214e8e38d2a1c0db2bfb0852ef9b7d 504.5s
=> => resolve
....
....
....
Run the following docker images command and check if it shows your image.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 07ff569194e1 2 weeks ago 83.2MB
Each instruction in the Dockerfile corresponds to an image layer and is stacked on top of each other to form the final Docker image. An image layer is the fundamental building block of a Docker image and there can be many image layers in a Docker image.
Docker starts to build from Dockerfile by taking python:3.8
as the base image and then creating an intermediary image for every instruction it executes. Docker adds the build files from the intermediary step as another layer on top of the base image.
Create container
The docker image is now ready to be used as a container. To create a container from the above Docker image, use the following docker run command with image ID as an argument.
$ docker run 07ff569194e1
* Serving Flask app 'app'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://172.17.0.2:5000
Press CTRL+C to quit
Point your web browser to the URL displayed on the screen to access the web application.
Tag a Docker image
It gets difficult to identify an image when you are working with a large number of them. Docker provides a option to tag an Docker image with names of your choosing. Let's tag the Docker image that we have created with the following command.
$ docker build . -t yourusername/flask-app
Run the docker images command and verify the tagged name associated with the image.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
yourusername/flask-app latest e85b2852ee8c 8 minutes ago 83.2MB
Push Docker image to Docker Registry
The Docker image that you have created previously is stored in your local system. This implies that you cannot access or use it from other work stations. You must push the Docker image to a Docker registry in order for it to be used elsewhere.
Docker images are stored in a Docker registry. Docker Hub is one of the well-known Docker registries. To push Docker images to Docker Hub, you'll need an account. Create an Docker hub account if you don't have the one.
Once you have created your account, Login to the docker hub by providing your user name and password/token.
$ docker login
Re-tag the previous docker image with your docker hub user name and a tag.
$ docker tag yourusername/flask-app yourdockerhubusername/flask-app:v1
Finally push the image to the Docker hub.
$ docker push yourdockerhubusername/flask-app:v1
You can now run the Docker container by using the pushed docker image from anywhere.
$ docker run yourdockerhubusername/flask-app:v1
Conclusion
The article briefly describes a Dockerfile structure and how to start writing a Dockerfile. Moreover,the article also shows how to build docker image, tag a docker image and push the image to the Docker hub. More references in the Dockerfile can be found on Docker's online documentation.