Different ways to auto-generate Docker image tags

Various ways to auto-generate Docker image tags and use latest tag

Tagging Docker images is important to keep track of versions of the service running and to easily roll back in case of faulty behavior of the application. The version strategy which is the most clear and understandable is tagging image with version of the application for example

dejanstojanovic/sampleservice:latest
dejanstojanovic/sampleservice:v1.0
dejanstojanovic/sampleservice:v2.0
    

As much as this approach is clean for understanding when pulling from he repository, it is not easy to automate it. For continuous build triggered by a change in source control, you need a unit auto generated value. One of these values could be

  • GUID
  • Git commit hash
  • Timestamp

All of these identifiers have their pros and cons and we'll discuss them.

GUID

Generating unique identifier with bash is super simple. You just need one line of code and you can use it as a variable in you image build script

tag=$(cat /proc/sys/kernel/random/uuid)
echo $tag

    

This will result in getting a value similar to this

d20acfe8-6156-46f2-aee8-af50573e9e4b

Although it is very easy to get a unique identifier which you can use to tag your image after each build, they are completely unclear and reveal no info about the image. Another downside is that these values are pretty long, so it is not that convenient to use them for tagging images, but it is still there as an option.

Git commit hash

Every commit in Git source control has it's own unique identifier. You can use this one to tag your image. This way you will know the code changes deployed with the image.

dejan@debian9:~$ mkdir github
dejan@debian9:~$ cd github/
dejan@debian9:~/github$ git clone --single-branch -b master https://github.com/dejanstojanovic/dotnetcore-console-sample
Cloning into 'dotnetcore-console-sample'...
remote: Counting objects: 15, done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 15 (delta 4), reused 15 (delta 4), pack-reused 0
Unpacking objects: 100% (15/15), done.
dejan@debian9:~/github$ cd dotnetcore-console-sample/
dejan@debian9:~/github/dotnetcore-console-sample$ git log -1
commit b9f8a4d4b89f896886148ca06094248b65baf26c
Author: dejanstojanovic <d.stojanovic@hotmail.com>
Date:   Thu Sep 20 10:28:31 2018 +0400

Now you get more than hash with git log, so let's just take out the hash value

git log -1 --pretty=%H
    

This will output last commit hash only

b9f8a4d4b89f896886148ca06094248b65baf26c

The complete hash is probably to long value to use as a image tag, so leth trim it and use only first seven characters

git log -1 --pretty=%h
    

This will output trimmed hash value

b9f8a4d

Using Git commit hash is pretty convenient because from the tag you can easily get the comments on what is the latest change that triggered build and pushed image to the image repository. How ever, this requires from you to have the repository conned locally on your build machine.

In case you decide to do the whole code clone and build inside the intermediate container, this approach will not work unless you manage to pull out the docker build output, which I unfortunately could not make work and since I always use intermediate container this is not an option for me.

Timestamp

This option uses the current date and time on the build machine in a format YYYYmmddHHMMSS

timestamp=$(date +%Y%m%d%H%M%S)
echo $timestamp
    

Pretty easy to use and it tells you when was image built which at the same time can be the time changes were push to the specific branch of the remote repository. Does not provide exact commit signature hash lige git commit hash but it is not that hard to find it depending on the time.

Tag latest

Not in all cases, but in most you want that your latest built image to ge taged with latest tag so when you execute your CD script you always get the newest image to deploy. I will use a small .NET Core project for a walk through on how to use latest tag for the images you built last.

So nothing fancy in code, just an output message so that we can indicate that different images are user to run container. 

using System;

namespace SampleConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World from v1.0");
        }
    }
}

    

The complete solution code is in github so that I can clone the code repository and build it for the image. The public repository URL is https://github.com/dejanstojanovic/dotnetcore-console-sample

I prefer using intermediate container to build the solution. For me it is a lot cleaner than cloning the repository on the build machine. 

FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src
RUN git clone --single-branch -b master https://github.com/dejanstojanovic/dotnetcore-console-sample
RUN cd dotnetcore-console-sample
RUN dotnet publish "./dotnetcore-console-sample/SampleConsoleApp/SampleConsoleApp.csproj" --configuration=Release --runtime=linux-x64 --output=/app

FROM microsoft/dotnet:2.1.401-sdk AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "SampleConsoleApp.dll"]
    

This way, all the temporary operations live int intermediate container and they are removed once the build process is done leaving the build host clean without any code or temp files except the result image that was built.

For the tagging, i decided to use timestamp for the simplicity reasons because this is not the focus. Our focus now is to tag every last build image with latest tag.

!/bin/bash

image="dejanstojanovic/sampleservice"

#get timestamp for the tag
timestamp=$(date +%Y%m%d%H%M%S)

tag=$image:$timestamp
latest=$image:latest

#build image
sudo docker build -t $tag .

#push to dockerhub
sudo docker login
#sudo docker login -u username -p password
sudo docker push $image

#remove dangling images
sudo docker system prune -f

    

So we build our image with the timestamp tag, but attach additional tag latest to the image upon build. After the script is execute we should have the image of this sample application listed with two tags.

REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
dejanstojanovic/sampleservice   latest              b317b0191f95        4 hours ago         1.8GB
dejanstojanovic/sampleservice   20180920102541      b317b0191f95        4 hours ago         1.8GB
microsoft/dotnet                2.1.401-sdk         bde01d9ed6eb        3 weeks ago         1.73GB

And if we run the image with or without the tag we will have our application message displayed in the console. 

dejan@debian9:~$ sudo docker run dejanstojanovic/sampleservice
Hello World from v1.0
dejan@debian9:~$ sudo docker run dejanstojanovic/sampleservice:20180920102541
Hello World from v1.0
dejan@debian9:~$ sudo docker run dejanstojanovic/sampleservice:latest
Hello World from v1.0

Now we want to create another image with updated code. To keep things simple I just updated the message to print out v2.0 on the screen in the message instead of v1.0. 

using System;

namespace SampleConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World from v1.0");
        }
    }
}

    

This code is committed to local git repository and pushed to the remote one so that we can clone it again the temporary container and build from it. Now we just need to execute again our bash we used to build and tag image and wait for it to finish the job for us.

Once the script executes there will be one more image id for the same repository with two tags. One tag is the timestamp taken during the build and the other one is latest tag.

REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
dejanstojanovic/sampleservice   20180920103213      0c680c286601        4 hours ago         1.8GB
dejanstojanovic/sampleservice   latest              0c680c286601        4 hours ago         1.8GB
dejanstojanovic/sampleservice   20180920102541      b317b0191f95        4 hours ago         1.8GB
microsoft/dotnet                2.1.401-sdk         bde01d9ed6eb        3 weeks ago         1.73GB

Now to check if our latest is indeed the latest one with updated code, we will run this image with and without tags. 

dejan@debian9:~$ sudo docker run dejanstojanovic/sampleservice
Hello World from v2.0
dejan@debian9:~$ sudo docker run dejanstojanovic/sampleservice:latest
Hello World from v2.0
dejan@debian9:~$ sudo docker run dejanstojanovic/sampleservice:20180920102541
Hello World from v1.0
dejan@debian9:~$ sudo docker run dejanstojanovic/sampleservice:20180920103213
Hello World from v2.0

This simply shows that our updated code is pulled if we run image without tags, which means tag latest is used.

How do you do image tagging in your scripts? 

Feel free to share in comments below

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

.NET

read more

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

Comments for this article