Friday 11 November 2016

Docker Tag Re-Assignment and the "latest" Tag

Docker Tag Re-Assignment and the „latest“ Tag

Introduction

The Docker latest tag can be a bit of mystery.

The confusion is mostly based on the legitimate assumption that an image tagged “latest” is the last and therefore newest image added to a given repository.
This assumption, legitimate or not, is definitely wrong. The tag “lastest” is just a token like “0.1.1” or “iojdfh”.

The only thing that makes "latest" special is that Docker assumes it as a default value for its “docker commit” or “docker tag” commands in case you do not specify a tag explicitely.

The following links cover this in great detail.


Nothing left to add to these.

What I want to shed some light on here, is:
  • how Docker treats tags as pointers to images
  • how Docker distinguishes between creating and re-assigning tags

As always, if you know all that then don’t waste your time and stop reading now.
If you are not so sure, keep going. I admit that some details of tagging have been a surprise to me.

Setup

Let’s start out with creating a setup just rich enough to see the mechanics.
Creating a repository containing two versioned images will just do it.

Please note upfront:
  • I’m on Windows 10, running my docker in Vagrant powered CentOS 7 VirtualBox
  • I’m working locally, not pushing to or pulling from Docker Hub (except when running the base image)
  • I’m not using a dockerfile but create my images by committing containers

Now let’s create the images:

#
# Run Container based on base image „centos“:
$ docker run -it centos /bin/bash
#

This will start an interactive container running a bash shell and You will find yourself within this shell.
Create a file “/test.sh”, e.g. using vi, and enter this content:

#
#!/usr/bin/env bash
echo "Hello, I am version 01"

Now exit the container and commit it to a version 1 image:

#
$ docker commit -a "volker.koster@mt-ag.com" -m "Added /test.sh" \
-c 'CMD ["/bin/bash", "/test.sh"]' 333ba1982dbe vkoster/versionen:v01
#

Things to note here:
  • 333ba1982dbe is the container’s id
  • The --change option makes this container an executable that just runs the /test.sh file
  • vkoster/versionen is the name of the repository for our images
  • v01 is our version tag
Had we not specified the version tag, docker would have assigned “latest” as a default tag. Told differently, docker did not assign the “latest” tag because we specified a tag explicitely.

Now list the images and run a container to see if it works:

#
$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
vkoster/versionen     v01                 51e388437466        26 seconds ago      196.7 MB
$ docker run vkoster/versionen:v01       
Hello, I am version 01
#
(Omitting the "v01" tag now, would have caused an error, because Docker would then assume "lates", which is not present)

Image works. Let’t tag it as “latest”:

#
$ docker tag vkoster/versionen:v01 vkoster/versionen:latest
$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
vkoster/versionen     latest              51e388437466        10 minutes ago      196.7 MB
vkoster/versionen     v01                 51e388437466        10 minutes ago      196.7 MB
#

We now have one repository containing one image referenced by two tags.

Now let's create version 2 of this image.

#
$ docker run -it vkoster/versionen /bin/bash
#


(Now it is ok to omit the tag: Docker assumes "latest", which is now present)

Within the running container, edit the /test.sh file like so:
#
#!/usr/bin/env bash
echo "Hello, I am version 02"
#

Save the file, exit the container and again commit it to an image:
#
$ docker commit -a "volker.koster@mt-ag.com" -m "Changed /test.sh" \
-c 'CMD ["/bin/bash", "/test.sh"]' 5f1f1063fd2a vkoster/versionen:v02
#
List the images and run the new version, just to be sure.
#
$ docker images -a
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
vkoster/versionen     v02                 435bb586c058        5 minutes ago       196.7 MB
vkoster/versionen     latest              51e388437466        57 minutes ago      196.7 MB
vkoster/versionen     v01                 51e388437466        57 minutes ago      196.7 MB
# …and run the image:
$ docker run vkoster/versionen:v02
Hello, I am version 02
#
We still have one repository, now containing two images.
As was expected and covered in the links above, the “latest” tag did not move but still references the first image.

Now we can play around with the tags a bit.

Questions

Question: what will happen, if we try to tag the new image with the “latest” tag? 
Obviously there cannot be two “latest” tags in one repo.

Tag the new image with “latest” and display the results:
#
$ docker tag vkoster/versionen:v02 vkoster/versionen:latest
$ docker images –a
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
vkoster/versionen     latest              435bb586c058        9 minutes ago       196.7 MB
vkoster/versionen     v02                 435bb586c058        9 minutes ago       196.7 MB
vkoster/versionen     v01                 51e388437466        About an hour ago   196.7 MB
#

As it worked, this is what happened:
  • we tried assign the “latest” tag
  • Docker recognizes that the repository already contains the tag “latest”
  • therefore, the tag is not created but simply re-assigned to point to the new image
  • there is only one pointer left, “v01”, to point to the first image

Question: Are all tags treated like this or is the “latest” tag special?

This works for all tags. Again, the tag “latest” is in no way special.
You can try this yourself by re-tagging  “v01” or “v02”.

Question: What happens when we remove the last tag from an image?
#
$ docker tag vkoster/versionen:latest vkoster/versionen:v01
$ docker images -a
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
vkoster/versionen     latest              435bb586c058        57 minutes ago      196.7 MB
vkoster/versionen     v01                 435bb586c058        57 minutes ago      196.7 MB
vkoster/versionen     v02                 435bb586c058        57 minutes ago      196.7 MB
<none>                <none>              51e388437466        About an hour ago   196.7 MB
#

Docker re-assigned the pointer with no problem at all, leaving our fist image “naked”.
This image can no longer be referenced via the repository.

Takeway

The results can be summed up like this:
  • tags are just pointers to images
  • when tagging, docker checks, if the respective tag is already present within the repository
    • if the tag is not present, it is created, pointing to the respective image
    • if the tag is present, it is simply re-assigned from one image to another
  • this works for all tags; there is no special treatment for “latest” whatsoever