2

I am trying to write a script for simple tagging docker images based on the contents of Dockerfile, basically something like "auto-versioning".

The current process is:

  1. Check the latest version in Docker repository (I am using AWS ECR)
  2. Get the digest for that image
  3. Build image from Dockerfile locally
  4. Compare digests from the remote image and local image

Now here is the problem. The locally built image doesn't have the RepoDigest that I want to compare against, because it wasn't in the repository yet.

Here's the error:

Template parsing error: template: :1:2: executing "" at <index .RepoDigests 0>: error calling index: index out of range: 0

The other approach I could think of is pulling the remote image, building the local one and comparing layers, if the layers are identical, no action, if they are different = new version and I can issue a new tag and push the image. I am not so sure if the layers are reliable for this manner.

Another possible approach would be building the image with some temporary tag e.g. pointer, pushing anyways and in case the tag is identical with the latest version, not issuing a new version and stopping there. That would mean there would always be pointer tag somewhere in the repository. (I am also thinking that this could be a definiton of the latest tag?)

This is the script that I am using for building the images:

#!/usr/bin/env bash

repository=myrepo
path=mypath.dkr.ecr.ohio-1.amazonaws.com/${repository}/

set -e
set -o pipefail

if [[ $# -gt 0 ]]; then
    if [[ -d "$1" ]]; then
        latest=$(aws ecr describe-images --repository-name ${repository}/$1 --output text --query 'sort_by(imageDetails,& imagePushedAt)[*].imageTags[*]' | tr '\t' '\n' | grep -e '^[0-9]$' | tail -1 )  || true
        if [[ -z "$latest" ]]; then
            latest=0
        fi
    else
        echo "$1 is not a directory"
        exit 1
    fi
else
   echo "Provide build directory"
   exit 1
fi

image="$path$1"
temporaryImage="$image:build"

echo "Building $image..."
docker build -t ${temporaryImage} $1

if [[ ${latest} -gt 0 ]]; then
    latestDigest=$(aws ecr describe-images --repository-name ${repository}/$1 --image-ids "imageTag=${latest}" | jq -r '.imageDetails[0].imageDigest')
    buildDigest=$(docker inspect --format='{{index .RepoDigests 0}}' ${temporaryImage})
    if [[ "$image@$latestDigest" == "$buildDigest" ]]; then
        echo "The desired version of the image is already present in the remote repository"
        exit 1
    fi
    version=$((latest+1))
else
    version=1
fi

versionedImage="$image:$version"
latestImage="$image:latest"
devImage="$image:dev"
devVersion="$image:$version-dev"

docker tag ${temporaryImage} ${versionedImage}
docker tag ${versionedImage} ${latestImage}
docker push ${versionedImage}
docker push ${latestImage}
echo "Image '$versionedImage' pushed successfully!"

docker build -t ${devImage} $1/dev/
docker tag ${devImage} ${devVersion}
docker push ${devImage}
docker push ${devVersion}
echo "Development image '$devImage' pushed successfully!"
Jan Richter
  • 1,976
  • 4
  • 29
  • 49
  • I don't know for the digest, but layers are reliable for this, Docker use them to check if image is up to date locally compared to the remote one and pull only different layers. So if all layers are the same, you are all good – Jonathan Muller Nov 06 '18 at 03:40
  • I suspect you'll have some trouble with this path: very small differences like timestamps or different builds of base images will result in a "different" layer and you'll wind up with more "builds" than you intend. I might pick some external identifier (source control commit ID, timestamp) and tag based on that. – David Maze Nov 06 '18 at 11:53
  • It looks like the case, yes. Every time I build an image from scratch it results in a new layer being present. In case I build the image after building a "previous version" (contents of the Dockerfile are identical) then the layers are identical as well. – Jan Richter Nov 06 '18 at 19:49

0 Answers0