How to Build and Run Your Docker Image

Written by: Kiley Nichols
8 min read

In this article, I’ll show you how to build and run a Docker image. Docker is a valuable tool for developing and deploying applications. It can seem complicated when you’re first getting started, so I’ll map out the process step-by-step for you. I’ll be using Python code examples, but you can easily adapt this tutorial to your language of choice. 

Install Docker

If you want to follow along, you’ll need a system with Docker installed on it. For a Windows or macOS desktop, you can download and install the program from the Docker Desktop website. With Linux, you can install it using the package manager for your distribution. I’ll be using examples from the Linux command line, but they’ll be simple enough that you can adapt them to Windows or Mac. 

You’ll also need a text editor for editing your Dockerfile. 

Docker "Hello There"

You’ll be running Python inside your Docker containers, but you don’t need Python installed on your development system. That’s your first lesson! You can use Docker to run software that isn’t installed on the host system. 

Start with an empty directory and create your first Dockerfile. A Dockerfile contains a list of directives describing how to build your image. 

Create a text file named Dockerfile with these contents. 

from python:latest

CMD [ "python", "-c", "print('Hi there!')"]

The first line tells Docker which image to start building with. Your Dockerfile will always start with a FROM line. Over at Docker Hub, you can find images with almost any Linux distribution and with almost any software package ready to use. In this case, we’re using the lightweight Alpine Linux distribution with the latest version of Python installed and ready to go. 

The second line contains the command that Docker will run by default when this image is loaded. When you use CMD, you pass it an array. The first is the executable, and the rest are the arguments it will pass to Python. You’re running Python with a one-line program. The image puts Python in the search path, so you can call it without worrying about where it’s located. 

The -c argument tells Python that the code you want executed follows. Note that “-c print(‘Hi there!’)” wouldn’t work. Each string must be its own item in the array. 

Build Your Docker Image

Now, build your image. 

$ docker build -t hello_there .

Sending build context to Docker daemon  2.048kB

Step 1/2 : from python:latest

 ---> a3fe352c5377

Step 2/2 : CMD [ "python", "-c", "print('Hi there!')"]

 ---> Running in 3977b48d8273

Removing intermediate container 3977b48d8273

 ---> ebc23857ffda

Successfully built ebc23857ffda

Successfully tagged hello_there:latest

$

Docker build is the command for building an image. It expects to find a file named Dockerfile in the working directory. The second argument, -t, is a tag to use to refer to the image. 

As you can see, Docker prints out each directive in your Dockerfile. Once it’s done, the image is placed in your local Docker repository. 

Run Your Docker Image

Let’s run it. 

$ docker run hello_there

Hi there! 

Docker run creates a container using your image. Pass it the name you used in the build step. There it is. Your first Docker image, running in a container! 

A More Practical Image

Passing your Python code to Python on the command line isn’t how you would normally structure an application, so it isn’t how you want to build an image either. Let’s make this a bit more practical. 

First, put the print statement in a Python source file name hello_there.py

#!/usr/bin/env python3

print('hello there!')

Now, update the Dockerfile so it can use this source file. 

from python:latest

COPY hello_there.py /

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

The COPY directive tells Docker to copy the source file into the root of your image. 

Docker doesn’t accept relative paths that point outside of the build folder. In other words, ../path/to/stuff won’t work. So if you’re going to check your code into source control and run it on a different system, it’s easiest to work with the folder that contains your Dockerfile and build from there. 

COPY Customizes Images

You can COPY anything into an image. It will copy in any file, so instead of Python source, you could add jar files, compiled code, or webpages into your image. You could copy a directory full of HTML files into the NGINX image and build yourself a web server. 

Here’s an example from the NGINX documentation. 

FROM nginx

COPY static-html-directory /usr/share/nginx/html

COPY will copy the contents of a directory if you pass a directory name. It doesn’t copy the name, though, so the contents of static-html-directory are placed in /usr/share/nginx/html. This image will run as a web server even without adding a new CMD because it will inherit the one specified in FROM image. 

A Better "Hello There"

Let’s get back to our image. 

$ docker build -t hello_there .

Sending build context to Docker daemon  3.072kB

Step 1/3 : from python:latest

 ---> a3fe352c5377

Step 2/3 : COPY hello_there.py /

 ---> Using cache

 ---> 1863d3f0c4eb

Step 3/3 : CMD [ "python", "hello_there.py"]

 ---> Using cache

 ---> a125be33ddea

Successfully built a125be33ddea

Successfully tagged hello_there:latest

It built successfully. 

Next, rerun it. 

$ docker run hello_there

hello there

It still works! 

So, you’ve built an image that takes a Python source file and executes it. If you want to update the code, you update hello_there.py and rebuild the image. Your Docker image is your application packaging. 

More Docker Image Changes

Let’s take this Docker application one step further. 

We’ll add the Python requests library, retrieve a webpage, and print the request status. 

#!/usr/bin/env python3

import requests

x = requests.get('https://www.google.com')

if x.status_code == 200:

 print('yay!')

else:

 print('uh-oh!')

Now, rebuild the image. 

$ docker build -t hello_there .

[sudo] password for egoebelbecker:

Sending build context to Docker daemon  3.072kB

Step 1/3 : from python:latest

 ---> a3fe352c5377

Step 2/3 : COPY hello_there.py /

 ---> 25d512ac21e5

Step 3/3 : CMD [ "python", "hello_there.py"]

 ---> Running in c9a386222569

Removing intermediate container c9a386222569

 ---> c475fe142992

Successfully built c475fe142992

Successfully tagged hello_there:latest

Finally, rerun it. 

$ docker run hello_there

Traceback (most recent call last):

  File "//hello_there.py", line 3, in 

    import requests

ModuleNotFoundError: No module named 'requests'

The script won’t run because we haven’t loaded the requests module into the Python environment. So, we need to modify the Dockerfile again. 

from python:latest

RUN pip install requests

COPY hello_there.py /

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

If you’re not familiar with pip, it’s the packaging tool for Python. We’re using it to retrieve the latest version of the requests library to call it from inside our script. 

The RUN directive in a Dockerfile runs an external program as part of the image build process. It is not related to the Docker run command you’re using to run your container. 

So, you’re telling Docker to run pip inside the python:latest container. Rerun the build with this new addition to the Dockerfile. 

$ docker build -t hello_there .

Sending build context to Docker daemon  3.072kB

Step 1/4 : from python:latest

 ---> a3fe352c5377

Step 2/4 : RUN pip install requests

 ---> Running in 0d6f466d3cb0

Collecting requests

  Downloading requests-2.25.0-py2.py3-none-any.whl (61 kB)

Collecting certifi>=2017.4.17

  Downloading certifi-2020.11.8-py2.py3-none-any.whl (155 kB)

Collecting chardet<4,>=3.0.2

  Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB)

Collecting idna<3,>=2.5

  Downloading idna-2.10-py2.py3-none-any.whl (58 kB)

Collecting urllib3<1.27,>=1.21.1

  Downloading urllib3-1.26.2-py2.py3-none-any.whl (136 kB)

Installing collected packages: certifi, chardet, idna, urllib3, requests

Successfully installed certifi-2020.11.8 chardet-3.0.4 idna-2.10 requests-2.25.0 urllib3-1.26.2

Removing intermediate container 0d6f466d3cb0

 ---> 0a5dd2d6afc4

Step 3/4 : COPY hello_there.py /

 ---> 6f743c7f6182

Step 4/4 : CMD [ "python", "hello_there.py"]

 ---> Running in 2d559f8a4b61

Removing intermediate container 2d559f8a4b61

 ---> f8203cf2687a

Successfully built f8203cf2687a

Successfully tagged hello_there:latest

Take a look at step 2 of 4 in the build output. You can see the output from pip as it collects requests and its four dependencies. 

RUN works for installing Debian packages with apt or installing RPMs with rpm or yum. You also run any other command, such as setting file permission with chmod to changing file ownership. 

Try rerunning the container. 

$ docker run hello_there

yay!

You can see that retrieving the Google search page succeeded. 

Docker Images for Easier Application Deployment

In this tutorial, you built a simple Docker image. Then you made the script easier to maintain by adding a source file to the image. Finally, you customized the image by installing additional software packages for your script. 

Docker is a powerful tool for bundling applications with their dependencies and running them on multiple platforms with no additional changes. Now that you know how to build images, start using it for your projects! 

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.