Exercise 2: Docker images

This exercise starts off with exploring a Docker image’s history and ends with your first Docker image on the Docker Hub. Let’s get started!

Join the chat room for this exericse: https://gitter.im/atbaker/oscon-exercise-2


Remember, you will need to reference the Docker documentation to work through these exercises.


The next two exercises deal with Dockerizing some Python apps, but you don’t need to know much Python to complete them.

Anatomy of an image

Docker images are just portable, saved states of Docker containers. Images are how you move your Dockerized applications from your development machine to the world.

Let’s examine one of the Docker images we used in the last exercise, atbaker/nginx-example. Look at the commands used to create that image with the docker history command.


The docker history command uses this basic syntax:

docker history IMAGE_NAME

If you’re curious about how Docker images work, you can read more about it here: https://docs.docker.com/introduction/understanding-docker/#how-does-a-docker-image-work

Meet our Flask app

Flask is a lightweight Python web framework. In this exercise, we’re going to add a Dockerfile to a Flask application to help us build a Docker image for it.

I have already written the Flask app for you, so you should start by cloning the git repository at https://github.com/atbaker/docker-flask. You can do this with git clone if you have git installed, or by clicking the “Download ZIP” button on GitHub.


If you want, you can run this app through your laptop’s native Python installation first just to see what it looks like. Run sudo pip install -r requirements.txt and then run python app.py.

You should then be able to open a web browser, go to http://localhost:5000, and see the message Hello! I am a Flask application.

This is totally optional - but some people like to see what the app’s supposed to do before they try to Dockerize it.

Creating a Dockerfile

A Dockerfile is a special file in your source code that tells Docker how to build an image for your application.

Most commands in a given Dockerfile are used to install dependencies for your application, like OS packages and programming language libraries.

Other commands specify default docker run options for containers created from that image, like the default command that should be run in that container or the default ports to expose to the host.

Every Dockerfile needs a base image to build off of. While you can choose plain Linux distributions (like Ubunutu) as your base image, it’s usually more efficient to pick a base image which already has some of your application’s dependencies installed.

Docker maintains a library of official base images for various programming languages and server applications that save you the trouble of installing them manually.

Find the official Python Docker image in the list of official base images linked above. Read through the “How to use this image” section.

Following the instructions on the official Python image, complete the Dockerfile in your clone of the atbaker/docker-flask repo. You should use the python:3-onbuild base image. You won’t need to add any more commands to the Dockerfile - just complete the three stubbed out already.


You may also find the Docker User Guide’s section on “Building an image from a Dockerfile” to be useful: https://docs.docker.com/userguide/dockerimages/#building-an-image-from-a-dockerfile

When you’re done, you can try building your Docker image with the docker build command:

docker build -t flask-app .


Be sure to pass that -t option to your docker build command. This tells Docker what to name the image created at the end of the build process.

When Docker can successfully build your Dockerfile, test it by starting a new container from your new image using the docker run command. Don’t forget to include the port forwarding options you learned about in the last exercise.

If you did everything right, you should be able to see Hello! I am a Flask application when you visit your container in your web browser.


If you get stuck, you can reference the solution branch of the docker-flask repository on GitHub: https://github.com/atbaker/docker-flask/tree/solution

Pushing to the Docker Hub

The Docker Hub is sort of like the GitHub of Docker images. It’s the main place people store their Docker images in the cloud.

Before we can take our Dockerized Flask app to another computer, we need to push it up to the Docker Hub so that we (or other people) can pull it down on other machines.

First, create an account on the Docker Hub if you haven’t already - it’s free: https://hub.docker.com/account/signup/

Then, login to that account by running the docker login command on your laptop.

We’re almost ready to push our Flask image up to the Docker Hub. We just need to rename it to our namespace first.

Using the docker tag command, tag the image you created in the previous section to your namespace. For example, I would run:

docker tag flask-app atbaker/flask-app

flask-app is the tag I used in my docker build commands in the previous section, and atbaker/flask-app is the full name of the new Docker image I want to push to the Hub.

All that’s left to do is push up your image:

docker push atbaker/flask-app

Go to your profile page on the Docker Hub and you should see your new repository listed: https://registry.hub.docker.com/repos/

Congrats! You just made your first Docker image and shared it with the world!

In the next section, you will learn how to use Docker to run a more complex web application. When you’re ready, move on to Exercise 3: Full stack Docker!