Building the container

We will use the docker build command to create the container. In a Terminal window, change into the directory with the Dockerfile and run the following command:

docker build .

You should see output that looks something like the following:

Sending build context to Docker daemon    107kB
Step 1/9 : FROM alpine
---> 76da55c8019d
Step 2/9 : RUN apk update
---> Running in f72d5991a7cd
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/community/x86_64/APKINDEX.tar.gz
v3.6.2-130-gfde2d8ebb8 [http://dl-cdn.alpinelinux.org/alpine/v3.6/main]
v3.6.2-125-g93038b573e [http://dl-cdn.alpinelinux.org/alpine/v3.6/community]
OK: 8441 distinct packages available
---> b44cd5d0ecaa
Removing intermediate container f72d5991a7cd

Each step in the Dockerfile will be reflected by output of what's happening when Docker is building the image at that step, and with more complex Dockerfiles, the output can be quite extensive. As it finishes its build process, it will report an overall success or failure, and will also report the container IDs:

Step 8/9 : ENTRYPOINT python3
---> Running in 14c58ace8b14
---> 0ac8be8b042d
Removing intermediate container 14c58ace8b14
Step 9/9 : CMD /opt/exampleapp/exampleapp.py
---> Running in e769a65fedbc
---> b704504464dc
Removing intermediate container e769a65fedbc
Successfully built 4ef370855f35

When we build the container without any other information, it makes an image locally that we can play with (it has an ID), but it doesn't have a name or a tag. When you are choosing a name, you will generally want to consider where you are hosting your container images. In this case, I am using CoreOS's Quay.io service, which offers free hosting for open source container images.

To tag the image that we just created, we can use the docker tag command:

docker tag 4ef370855f35 quay.io/kubernetes-for-developers/flask

This tag contains three relevant parts. The first quay.io is the container registry. The second (kubernetes-for-developers) is the namespace for your container, and the third (flask) is the name of the container. We did not specify any specific tag for the container, so the docker command will use the latest.

You should use tags for releases or other points in time in your development that you want to be able to jump back to easily and leverage latest to represent your most recent development work, so let's also tag this as a specific version:

docker tag 4ef370855f35 quay.io/kubernetes-for-developers/flask:0.1.0

When you share an image with someone else, it is a very good idea to be explicit about which image you are working with. As a general rule, consider only using the code yourself, and whenever you share the image with any other people, use an explicit tag. The tag does not have to be a version, and although there are limits on its format, it can be nearly any string.

You use the docker push command to transfer the image to the container repository once it's been tagged. You will need to log in to your container repository first:

docker login quay.io

And then you can push the image:

docker push quay.io/kubernetes-for-developers/flask

The push refers to a repository, [quay.io/kubernetes-for-developers/flask]:

0b3b7598137f: Pushed
602c2b5ffa76: Pushed
217607c1e257: Pushed
40ca06be4cf4: Pushed
5fbd4bb748e7: Pushed
0d2acef20dc1: Pushed
5bef08742407: Pushed

latest: digest: sha256:de0c5b85893c91062fcbec7caa899f66ed18d42ba896a47a2f4a348cbf9b591f size: 5826

You will generally want to build your container with a tag from the start, rather than having to do the additional commands. To do that, you can add the tag information with the -t <your_name> option to the build command. For the examples in this book, I am using the name kubernetes-for-developers, so the command I have been using to build the example is:

docker build -t quay.io/kubernetes-for-developers/flask .

If you are following along with this example, use your own value where the preceding command has quay.io/kubernetes-for-developers/flask .. You should see output that looks as follows:

Sending build context to Docker daemon    107kB
Step 1/9 : FROM alpine
---> 76da55c8019d
Step 2/9 : RUN apk update
---> Using cache
---> b44cd5d0ecaa
Step 3/9 : RUN apk upgrade
---> Using cache
---> 0b1caea1a24d
Step 4/9 : RUN apk add python3
---> Using cache
---> 1e29fcb9621d
Step 5/9 : RUN mkdir -p /opt/exampleapp
---> Using cache
---> 622a12042892
Step 6/9 : COPY . /opt/exampleapp/
---> Using cache
---> 7f9115a50a0a
Step 7/9 : RUN pip3 install -r /opt/exampleapp/requirements.txt
---> Using cache
---> d8ef21ee1209
Step 8/9 : ENTRYPOINT python3
---> Using cache
---> 0ac8be8b042d
Step 9/9 : CMD /opt/exampleapp/exampleapp.py
---> Using cache
---> b704504464dc
Successfully built b704504464dc
Successfully tagged quay.io/kubernetes-for-developers/flask:latest

Take a moment to read through that output, and notice that in several places it reports Using cache. You may have also noticed that the command was faster than the first time you built the image.

That is because Docker attempts to reuse any layers that haven't changed so that it doesn't have to recreate that work. Since we just did all of those commands, it can use the layers from the cache it made while creating the previous image.

If you run the docker images command, you should now see it listed:

REPOSITORY                                TAG       IMAGE ID      CREATED          SIZE
quay.io/kubernetes-for-developers/flask 0.1.0 b704504464dc 2 weeks ago 70.1MB
quay.io/kubernetes-for-developers/flask latest b704504464dc 2 weeks ago 70.1MB

As you continue with using container images to house and deploy your code, you will likely want to automate the process of creating the images. As a general pattern, a good build process would be:

  • Get the code from source control
  • docker build
  • docker tag
  • docker push

This is the process we are using in these examples, and you can automate these commands with whatever tooling is most comfortable for you. I recommend you set up something that can be run on a command line quickly and consistently.