Semantic Versioning (semver) of Docker Images

For my current project, I wanted to use Bitbucket Pipelines to deploy my Docker images to Amazon ECR (AWS Elastic Container Registry) every time I merge to develop or tag a commit as a release. This includes tagging my images correctly.

I aimed to loosely follow semantic versioning (semver) to tag these docker images and use retagging to make container orchestration easier:

Version 1.2.3 is also matched by tags 1 and 1.2. Once 1.2.4 becomes available, they will be updated to match it, and so on. This is also the naming scheme of many official docker images.

I didn’t find any readily available pipelines online, so here is my setup. Just remember to set the pipeline variables AWS_KEY, AWS_SECRET, ECR_REPO_URL and IMAGE_NAME:

# use a pipeline container image of your choice
image: node:14

pipelines:
  branches:
    develop:
        - step:
            name: upload image
            services:
              - docker
            caches:
              - docker
              - node
            script:
              - mkdir /aws
              - curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "/aws/awscli-bundle.zip"
              - unzip /aws/awscli-bundle.zip -d /aws/
              - /aws/awscli-bundle/install -b ~/bin/aws
              - export PATH=~/bin:$PATH
              - aws configure set aws_access_key_id "${AWS_KEY}"
              - aws configure set aws_secret_access_key "${AWS_SECRET}"
              - aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin $ECR_REPO_URL
              - docker build -t $BITBUCKET_COMMIT .
              - docker tag $BITBUCKET_COMMIT $ECR_REPO_URL/$IMAGE_NAME:develop #repeat this and next step for further tags
              - docker push $ECR_REPO_URL/$IMAGE_NAME:develop
  tags:
    v**:
        - step:
            name: upload image
            services:
              - docker
            caches:
              - docker
              - node
            script:
              - mkdir /aws
              - curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "/aws/awscli-bundle.zip"
              - unzip /aws/awscli-bundle.zip -d /aws/
              - /aws/awscli-bundle/install -b ~/bin/aws
              - export PATH=~/bin:$PATH
              - aws configure set aws_access_key_id "${AWS_KEY}"
              - aws configure set aws_secret_access_key "${AWS_SECRET}"
              - aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin $ECR_REPO_URL
              - docker build -t $BITBUCKET_COMMIT .
              - docker tag $BITBUCKET_COMMIT $ECR_REPO_URL/$IMAGE_NAME:latest
              - export MAJOR_DOCKER_TAG=`echo $BITBUCKET_TAG | perl -0777 -pe 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+))?(?:\+([0-9A-Za-z-]+))?/\1/'`
              - docker tag $BITBUCKET_COMMIT $ECR_REPO_URL/$IMAGE_NAME:$MAJOR_DOCKER_TAG
              - export MINOR_DOCKER_TAG=`echo $BITBUCKET_TAG | perl -0777 -pe 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+))?(?:\+([0-9A-Za-z-]+))?/\1\.\2/'`
              - docker tag $BITBUCKET_COMMIT $ECR_REPO_URL/$IMAGE_NAME:$MINOR_DOCKER_TAG
              - export PATCH_DOCKER_TAG=`echo $BITBUCKET_TAG | perl -0777 -pe 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+))?(?:\+([0-9A-Za-z-]+))?/\1\.\2\.\3/'`
              - docker tag $BITBUCKET_COMMIT $ECR_REPO_URL/$IMAGE_NAME:$PATCH_DOCKER_TAG
              - docker push $ECR_REPO_URL/$IMAGE_NAME
definitions:
  services:
    docker:
      memory: 2048

It is far from perfect and you might need to tweak it for your needs. Especially if you follow a different git tag naming scheme than v<major version>.<minor version>.<patch version>.

But it should be a nice starting point and should be easy to adapt to your needs, such as other CI tools (Gitlab CI, GitHub Actions) or container registries (Docker Hub, Azure).

Do you need help with implementing this or have any other comments? Feel free to reach out!

Leave a Reply

Your email address will not be published. Required fields are marked *