Building and publishing a Docker image

In the previous post, we pulled an image built by someone, and executed it, using commands such as:

docker run hello-world, docker run ubuntu /bin/echo hello world or the more convoluted docker run -d -p 8081:8081 -p 18078:18078 -p 18079:18079 --name nexus -v /data/nexus/nexus-data:/nexus-data sonatype/nexus3

In this post, we want to build our own image and publish it so someone else pulls it!

Docker image and how to build one?

As we already defined it,

A Docker image is an inert, immutable, file that's essentially a snapshot of a container. Images are created with the build command, and they'll produce a container when started with docker run.

In order to build a Docker image, we have to define a Dockerfile.
A Dockerfile is like a Makefile, containing build steps to build an image.

Anatomy of a Dockerfile

Let's look at a 'minimal' Dockerfile

FROM ubuntu:latest
MAINTAINER Stratus Clay "calclayer@murex.com"

You can find the code under the stash repository docker-playground

  1. The FROM step instruct Docker to inherit the base image, here ubuntu:latest, and then build on it
  2. the MAINTAINER step, well, isn't mandatory after all ;), sets the author of the generated image

That's it when it comes to the 'minimal' Dockerfile

See the Dockerfile reference and Dockerfile Best Practices for more.

Let's build it now.

Building the image

In order to build the image, all we need to do is to execute in a shell in the Dockerfile directory:

docker build -t myimage:0.0.1 .

  • The -t flag is used to tag the image. It is not mandatory, but you'll grow fond of it later on when you want to version your images.

  • Note that you can use the -f flag to point to the Dockerfile if you do not want to cd to it's directory.

  • You can attach multiple tags to the image (multiple repositories/versioning schemes...). e.g.:

docker build -t myimage:0.0.1 -t myimage:latest .

Let's list the images to see if we have what we built. To do that use the command:
docker images

REPOSITORY         TAG            IMAGE ID            CREATED             SIZE
myimage            0.0.1          b8b64829e415        2 weeks ago         126.6 MB
myimage            latest         b8b64829e415        2 weeks ago         126.6 MB

Testing the image

that's nice! Let's try to run our image now. we Can use docker run for that.
But when we execute this particular image using the command, it seems that nothing happened:

docker run myimage:0.0.1

The "issue" here, is that the image is started without terminal and keyboard redirection. (Which is how a container is usually started). But Docker is nice enough to give us flag to control that. -i -t or -it is your friend here.

So, let's run "it" again with -it ;)

docker run -it myimage:0.0.1

and now you should get a shell root access to the newly deployed container.

root@1b67d44e3d51:/#

Execute in this shell any command to prove that it does what is supposed to: (is an Ubuntu in this case):

root@1b67d44e3d51:/# cat etc/os-release
NAME="Ubuntu"
VERSION="16.04.1 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.1 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

All in all, we have with 2 lines in our Dockerfile created a new image based on a ubuntu latest (whatever that is at the moment).

Time to make our "valuable" image public for the world to see and build on!

Publishing the image

Let's try to do that without even thinking:

docker push myimage:0.0.1

The push refers to a repository [docker.io/library/myimage]
0cad5e07ba33: Preparing
48373480614b: Preparing
055757a19384: Preparing
c6f2b330b60c: Preparing
c8a75145fcc4: Preparing
unauthorized: authentication required

Hmm. Let's try to authenticate:

docker login

Login with your Docker ID to push and pull images from Docker Hub. If you don't have a  Docker ID, head over to https://hub.docker.com to create one.
Username:

OK. So here you can enter your docker hub id if you have one. (I suppose you already do now, so.)

Username: jmkhael
Password: *****************
Login Succeeded

Let's try to push our image again now:

docker push myimage:0.0.1

Darn. It still doesn't work. That is because Docker Hub needs a special tag to link images to their authors.

docker tag myimage:0.0.1 jmkhael/myimage:0.0.1

Note that we could've used this tag when building the image:
docker build -t myimage:0.0.1 -t myimage:latest -t jmkhael/myimage:0.0.1 .

and now one more time, but with the new tag:
docker push jmkhael/myimage:0.0.1

The push refers to a repository [docker.io/jmkhael/myimage]
0cad5e07ba33: Pushed
48373480614b: Pushed
055757a19384: Pushed
c6f2b330b60c: Pushed
c8a75145fcc4: Pushed
0.0.1: digest: sha256:180b69c4655a1de392ab4a7f4c18705e50874dfae7b0c5e04cfaa size: 1357

Seems better :)

docker-hub-myimage

Up next

In this post (rather long):

  1. we created an image from scratch (with 2 lines)
  2. tested it (2 command) and
  3. made it public (2 commands)

In the next post, we will build us a first microservice contained, well, in a container.