Container Image Versioning

Best practices for Image Tagging

Containers are fundamental to Enterprise digital transformation using cloud-native technologies. Organizations need to build container release management, governance, and monitoring practices to effectively utilize their cloud-native infrastructure. These practices are based on the principle of identifying a changeset(s). Traditionally this has been done with application release versions. Versions yield the following benefits :

  • Track upcoming changes with a new version.
  • Build governance with changelogs of the new versions
  • Monitor the released version
  • Rollback to the older version in case of issues.

In summary, versioning provides the capability to uniquely identify service artefacts along with the corresponding features. But containers do not offer features, instead, they enable a runtime to executed the service artefacts. It is, therefore, possible to version them in a variety of ways. The article presents the various ways our customers version the images and concludes with an opinionated approach to container versioning.

Image Lookup

Identifying artefacts is fundamental to release management. The container specification defines the following attributes for identifying images. You can use either of the ways to lookup images and deploy containers.

Image IDs

Container images do not have versions, but they have unique ids known as digests. The digest is computed from the bytes in the image. Container specification provides a reference of the various supported algorithms for digest computation.

Additional to the image identification, the digest also serves the purpose of image verification. You can recalculate the digest using image data and verify that the contents have not been modified.

Image Tags

Image tags are named references to an image version at a specific point in time. Tags allow easy lookup of image revisions by using human-readable strings. But tags are mutable references, so the image represented by the tag might change over time.

Additionally, tags can be used to convey helpful information about a specific image version. It can be used to correlate the image with its underlying service artefacts. It can also be used for specifying supported architectures and applicable environments.

Container Versioning strategy

Container tags are easy to reference but are challenging to operate. The mutability of tags creates the risk of deploying wrong containers in production which can cause a myriad of issues, like releasing untested features, broken APIs, bypass security checks, productions failures, etc. Thus organizations need an effective strategy that can work for their specific use cases.

Part of an engineering team’s adoption of container technology is to determine what type of strategy they will use for image tagging. Integration with CI/CD pipelines can be made easier by deciding a strategy up-front and following that standard.

Use Image Digest

The ability to change image tags is useful and convenient in many situations, but it can also pose risks and challenges if left unmanaged. You can avoid these challenges with deterministic and repeatable image identification by using digests instead of tags.

Use GitCommit

Container images are often built using docker files kept in your source control. Every time there is a commit in the application or the docker file the image gets generated. Teams can tag the generated images using the short git hash to trace back the changes in a robust and reliable manner.

Use SemVer

Almost all applications follow Semantic Versioning, also known as SemVer, for their release management. It is ideal for distributing applications as it is widely understood. Creating docker images based on the underlying service version is a great way to identify it. You can build the following strategy :

  • major.minor.patch (e.g. 2.3.4) is an immutable tag as the service version 2.3.4 is immutable. The tag indicates the container contains only fixes that are backward compatible with 2.3 version.
  • major.minor (e.g. 2.3) is a mutable tag as there can be many 2.3.x releases. The tag indicates the container contains new features and fixes that are backward compatible with version 2.
  • major (e.g. 2) is a mutable tag as there can be many 2.x releases. The tag indicates the container provides new features and changes for a new service version.

Use Other Unique Identifiers

Unique identifiers allow users to tag each image with immutable references. There are several ways to generate unique tags for an image, this includes:

  • Datetime stamp — While used often, a lack of correlation to the included changeset(s) for that container image’s release makes other options more attractive.
  • Build ID — Using the data provided by your CICD system, the Build ID allows for a method to denote what build was responsible for that version of the container image.

Canonical Names / Rolling tags

Several teams use aliases or common names to identify images. But these tags are not descriptive and auditable. They can not get you back to a build, and the contents of the build. So, it’s hard to tell exactly what you’ll get when you pull the tag, and it could change at any time. Following are the most commonly used tag names :

  • latest: The tag implies that the image contains the most recent version of the service. The image can be potentially unstable and still undergoing testing, so it should not be used for production environments.
  • stable: The tag implies that the contents of that image are stable and safe to deploy to production environments and be consumed by downstream containers in orchestrated environments.

A caveat of using this methodology is a lack of ability to easily roll back to a prior version. Since all releases are denoted as “Stable,” those that are replaced with the newest version are in a semi-archival state. While still usable, they may not be as accessible for easy image orchestration as other below-mentioned methods.

Multiple Tags

You can observe this concept applied to almost all popular open source container images on Docker Hub. Their images will have unique tags as well as Canonical Tags. Below is the screenshot of the NGINX tag descriptions on Docker Hub.

Nginx DockerHub Images

Each row in the list refers to a different image of NGINX, probably containing a different extension or application version. For example, the first row has the tags 1.19.6, mainline, 1, 1.19 and latest. All the tags point to the same image.

Images are also tagged with NGINX release versions as 1.19.6 and 1.18.0. Lastly, tags like alpine and perl indicate NGINX Alpine OS Builds and with NGINX Perl support, respectively. The strategy is more suited to public exposed images and adds little value for privately consumed images.

Usage Recommendation

Teams should use a container image tagging approach that’s both consistent and forward-looking to increase the image’s maintainability over time. The following guidelines ensures consistency and the ability to trace changes.

  • Using the predictable SemVer style is a good idea. The approach tightly couples the image to the underly service and can be managed using automation. Moreover, any downnstream users are also assured of receiving a tag which is compatible with their existing systems.
  • Do not use rolling tags when you deploy containers in production. This makes it harder to track deployed images and to roll them back effectively.
  • Use stable tags for picking base images.

Additionally, you can enable tag immutability in your image registry like Harbor. This would make sure that only unique tags are pushed to the repository. The immutability of tags ensures that images cannot be deleted or altered in any way, such as by re-pushes, re-taggings, or by replication from another registry. This is an age old practice that organisations have been doing with Java and NPM registries like JFrog and Sonatype.

Find out how Harbor can streamline container releases by trying it for free.

Published — September 9, 2021