Packaging your software
Estimated reading time: 7 minutes
It all starts with a Dockerfile.
Docker builds images by reading the instructions from a Dockerfile. This is a text file containing instructions that adhere to a specific format needed to assemble your application into a container image and for which you can find its specification reference in the Dockerfile reference.
Here are the most common types of instructions:
||Defines a base for your image.|
||Executes any commands in a new layer on top of the current image and commits the result.
||Sets the working directory for any
||Copies new files or directories from
||Lets you define the default program that is run once you start the container based on this image. Each Dockerfile only has one
Dockerfiles are crucial inputs for image builds and can facilitate automated, multi-layer image builds based on your unique configurations. Dockerfiles can start simple and grow with your needs and support images that require complex instructions. For all the possible instructions, see the Dockerfile reference.
Docker images consist of read-only layers, each resulting from an instruction in the Dockerfile. Layers are stacked sequentially and each one is a delta representing the changes applied to the previous layer.
Here’s a simple Dockerfile example to get you started with building images. We’ll take a simple “Hello World” Python Flask application, and bundle it into a Docker image that can test locally or deploy anywhere!
Let’s say we have a
hello.py file with the following content:
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!"
Don’t worry about understanding the full example if you’re not familiar with Python, it’s just a simple web server that will contain a single page that says “Hello World”.
If you test the example, make sure to copy over the indentation as well! For more information about this sample Flask application, check the Flask Quickstart page.
Here’s the Dockerfile that will be used to create an image for our application:
# syntax=docker/dockerfile:1 FROM ubuntu:22.04 # install app dependencies RUN apt-get update && apt-get install -y python3 python3-pip RUN pip install flask==2.1.* # install app COPY hello.py / # final configuration ENV FLASK_APP=hello EXPOSE 8000 CMD flask run --host 0.0.0.0 --port 8000
We start by specifying the syntax directive. It pins the exact version of the Dockerfile syntax we’re using:
As a best practice, this should be the very first line in all our Dockerfiles as it informs BuildKit the right version of the Dockerfile to use.
Next we define the first instruction:
FROM instruction sets our
base image to the 22.04 release of Ubuntu. All following instructions are
executed on this base image, in this case, an Ubuntu environment. The notation
ubuntu:22:04, follows the
name:tag standard for naming docker images. When
you build your image you use this notation to name your images and use it to
specify any existing Docker image. There are many public images you can
leverage in your projects. Explore Docker Hub
to find out.
# install app dependencies RUN apt-get update && apt-get install -y python3 python3-pip
RUN instruction executes a shell
command in the build context. A build’s context is the set of files located in
the specified PATH or URL.
In this example, our context is a full Ubuntu operating system, so we have
access to its package manager, apt. The provided commands update our package
lists and then, after that succeeds, installs
pip, the package
manager for Python.
# install app dependencies line. This is a comment. Comments in
Dockerfiles begin with the
# symbol. As your Dockerfile evolves, comments can
be instrumental to document how your dockerfile works for any future readers
and editors of the file.
Starting your Dockerfile by a
#like regular comments is treated as a directive when you are using BuildKit (default), otherwise it is ignored.
RUN pip install flask==2.1.*
RUN instruction requires that we’ve installed pip in the layer
before. After applying the previous directive, we can use the pip command to
install the flask web framework. This is the framework we’ve used to write
our basic “Hello World” application from above, so to run it in Docker, we’ll
need to make sure it’s installed.
COPY hello.py /
Now we use the
COPY instruction to
hello.py file from the local build context into the root directory
of our image. After being executed, we’ll end up with a file called
inside the image.
ENV instruction sets a Linux
environment variable we’ll need later. This is a flask-specific variable,
that configures the command later used to run our
Without this, flask wouldn’t know where to find our application to be able to
EXPOSE instruction marks that
our final image has a service listening on port
8000. This isn’t required,
but it is a good practice, as users and tools can use this to understand what
your image does.
CMD flask run --host 0.0.0.0 --port 8000
CMD instruction sets the
command that is run when the user starts a container based on this image. In
this case we’ll start the flask development server listening on all addresses
To test our Dockerfile, we’ll first build it using the
docker build command:
$ docker build -t test:latest .
-t test:latestoption specifies the name (required) and tag (optional) of the image we’re building.
.specifies the build context as the current directory. In this example, this is where build expects to find the Dockerfile and the local files the Dockerfile needs to access, in this case your python application.
So, in accordance with the build command issued and how build context works, your Dockerfile and python app need to be in the same directory.
Now run your newly built image:
$ docker run -p 8000:8000 test:latest
From your computer, open a browser and navigate to
You can also build and run using Play with Docker that provides you with a temporary Docker instance in the cloud.
If you are interested in examples in other languages, such as Go, check out our language-specific guides in the Guides section.build, buildx, buildkit, getting started, dockerfile