Version sticker - accetto/xubuntu-vnc GitHub Wiki

Version Sticker

Updated: 2020-10-10

Introduction

I've introduced the concept of Version Sticker in August 2019, when I've begun to use build hooks on Docker Hub. I've published the first docker images with version stickers in the beginning of September 2019.

This article describes the idea and its implementation in my docker images.

Concept

The concept of version sticker is simple:

Version sticker is a string that unambiguously identifies the version of a docker image within a group of docker images.

Rules

The following rules apply to version sticker values:

  1. The version sticker value is a string literal, built from the versions of the essential applications installed in the image. Other optional parts may also be added.

  2. The version sticker value is all lower case and it may contain only characters from the regex character class [a-b0-9_-.].

  3. The version sticker value must be persisted inside the docker image at least once in an immutable form.

Implementation

I have implemented version stickers in all images built from the following GitHub repositories:

The images themselves can be downloaded from my Docker Hub repository. The version sticker implementation in all of them is identical.

Generating version sticker value

The actual version sticker value is generated by the script version_sticker.sh, which internally uses the script version_of.sh.

Both scripts are stored in the image's startup folder, which is defined by the environment variable STARTUPDIR with the default value of /dockerstartup.

version_of.sh

This script expects a single argument and its value is used for selecting one of the predefined applications. The selected application is asked for its version information and then the pure version number is extracted using grep.

The selection keys are hard-coded, but some flexibility is achieved by supporting multiple selection keys per application.

For example, there are firefox | fox keys for the Firefox web browser, chromium | chromium-browser | chromiumbrowser | chrome keys for the Chromium Browser and so on.

Error messages thrown when the requested application is not available are suppressed.

The script is intended to be used by the other script, but it can be also useful separately. It makes checking of application versions really easy. For example:

/dockerstartup/version_of.sh firefox

### result
69.0.2

version_sticker.sh

If this script is executed inside a container without an argument, then it returns the current version sticker value of the container. This value is newly calculated and it is based on the current versions of the essential applications in the container.

The current version sticker value will differ from the persisted value (see below), if any of the included application has been updated to another version.

For example, executing the script inside a container created from the image accetto/xubuntu-vnc-firefox will currently return the following value:

/dockerstartup/version_sticker.sh

### result
ubuntu18.04.3-firefox69.0.2

However, the script recognizes two more arguments.

If it is called with the argument -v (lower case v), then it prints out verbose versions of the essential applications that are included in the version sticker value.

For example, for the container from above the output will currently look like this:

/dockerstartup/version_sticker.sh -v

### result
Ubuntu 18.04.3
Firefox 69.0.2

If the script is called with the argument -V (upper case v), then it prints out verbose versions of some more applications.

For example, for the container from above the output will currently look like this:

/dockerstartup/version_sticker.sh -v

### result
Ubuntu 18.04.3
Mousepad 0.4.0
VIM 8.0
TigerVNC 1.9.0
curl 7.58.0
Git 2.17.1
jq 1.6
Firefox 69.0.2

Version sticker persistence

In my images are the version sticker values persisted in two places:

  • in the image LABEL called version-sticker
  • in the environment variable called VERSION_STICKER

Both values are set during the image building through the build argument ARG_VERSION_STICKER. Its value is set from the script variable VERSION_STICKER, initialized in the env hook script.

The version sticker value can be easily checked also without creating a container by inspecting the docker image itself. For example:

docker inspect accetto/xubuntu-vnc-firefox:latest

The label values can be checked also online by using some services, for example MicroBadger.

Usage

I use version stickers for several purposes:

  • during image building for testing the new image before pushing it into repository
  • during image building for creating an archive copy of the new image
  • for badges in README files

Using version sticker during building

After a docker image is build by the build hook script and before it's pushed into the repository by the push hook script, it's tested by the test hook script. The concept is pretty simple.

The test hook script creates a container and gets the expected version sticker value from its environment variable VERSION_STICKER. Then it gets the actual version sticker value by executing the script version_sticker.sh inside the container.

Both values are then compared and if they match, the test hook script returns 0. It means success and the new image is pushed into the repository. Otherwise the script returns 1 and the build pipeline is interrupted.

If the test has succeeded, then also an additional archive copy of the new image could be pushed into the repository. The copy's tag value would include the version sticker value.

For example, for the image from above the following image tags would be pushed into the repository:

accetto/xubuntu-vnc-firefox:latest
accetto/xubuntu-vnc-firefox:ubuntu18.04.3-firefox69.0.2

Only the latest image would be overwritten after releasing a new image version.

Important note

Automatic archiving can cause image pollution on Docker Hub. Therefor it should be used only if there is a reason for it, e.g. needing older images for testing.

After using it for some time to prove the concept, I've removed it from my repositories in October 2020.

Using version sticker for badges

Version stickers carry useful information and it make sense to display them as badges in README files. Because the version sticker values do not change after images are built, using static badges is sufficient.

I currently use static badges from badgen.net, but other badge providers could be used as well.

util-refresh-readme.sh

Because the version stickers need to be persisted in the images, their values must be initialized in the env hook scripts. It's desirable to keep these scripts as the only place where the version sticker values must be manually updated, even if the same values have to be used in the badge hyperlinks in README files.

The utility script util-refresh-readme.sh updates the badge hyperlinks in README files by the values from env hook scripts.

The script takes a single argument - the path where to start looking for env hooks and README files. The argument is actually optional with the default value of ../docker, which fits my repositories.

The concept of the script is simple. First it looks in env hook scripts for variables named VERSION_STICKER_*. Then it uses their values for updating the related badge hyperlinks in README files.

For example, in the case of the docker image mentioned above, the script will find the following lines in the env hook script:

VERSION_STICKER_LATEST="ubuntu18.04.3-firefox69.0.2"
VERSION_STICKER_DEFAULT="ubuntu18.04.3-firefox69.0.2"
VERSION_STICKER_MULTIPROCESS="ubuntu18.04.3-firefox69.0.2"

Then it will update the following lines in the README file:

[badge-VERSION_STICKER_LATEST]: https://badgen.net/badge/version%20sticker/ubuntu18.04.3-firefox69.0.2/blue
[badge-VERSION_STICKER_DEFAULT]: https://badgen.net/badge/version%20sticker/ubuntu18.04.3-firefox69.0.2/blue
[badge-VERSION_STICKER_MULTIPROCESS]: https://badgen.net/badge/version%20sticker/ubuntu18.04.3-firefox69.0.2/blue

The script is intended for local interactive use before publishing the repository to GitHub.

One pass is enough, because the script will update all README files it finds underneath the given starting path.

However, it should be noted, that this solutions is completely dependent on the current repository structure and variable naming.

It is also important to notice, that the values of the version sticker variables in the env hook scripts must be string literals. They must not contain other variables, because those would not be expanded.