I have been using Google Cloud Build for a budget project for roughly a year now. Cloud Build stores built images in a storage bucket which you are of course billed for. Within the first weeks of using it I realized that I needed some automated way to cleanup unused and old images that were built there.

At the time I had a quick search around on the web for something already implemented that I could copy, but I came up blank, and decided putting my problem off would be the best solution. I filed issue number 6 for my project and left it for future me.

Now it’s time to finally close that issue, and I hope others might also find the small bash script useful.

The script

The script uses the gcloud container images list command to first retrieve all images within the stated repository.

It then uses gcloud container images list-tags to get all digests for the images, ordered by timestamp created.

Assuming the latest 3 images might be useful for rollbacks etc the script keeps those around, deleting all other images with gcloud container images delete.

#!/usr/bin/env bash

RED='\033[0;31m'
YELL='\033[1;33m'
NC='\033[0m' # No Color

IMAGES_TO_KEEP="3"
IMAGE_REPO="gcr.io/myproject"

# Get all images at the given image repo
echo -e "${YELL}Getting all images${NC}"
IMAGELIST=$(gcloud container images list --repository=${IMAGE_REPO} --format='get(name)')
echo "$IMAGELIST"

while IFS= read -r IMAGENAME; do
  IMAGENAME=$(echo $IMAGENAME|tr -d '\r')
  echo -e "${YELL}Checking ${IMAGENAME} for cleanup requirements${NC}"

  # Get all the digests for the tag ordered by timestamp (oldest first)
  DIGESTLIST=$(gcloud container images list-tags ${IMAGENAME} --sort-by timestamp --format='get(digest)')
  DIGESTLISTCOUNT=$(echo "${DIGESTLIST}" | wc -l)

  if [ ${IMAGES_TO_KEEP} -ge "${DIGESTLISTCOUNT}" ]; then
    echo -e "${YELL}Found ${DIGESTLISTCOUNT} digests, nothing to delete${NC}"
    continue
  fi

  # Filter the ordered list to remove the most recent 3
  DIGESTLISTTOREMOVE=$(echo "${DIGESTLIST}" | head -n -${IMAGES_TO_KEEP})
  DIGESTLISTTOREMOVECOUNT=$(echo "${DIGESTLISTTOREMOVE}" | wc -l)

  echo -e "${YELL}Found ${DIGESTLISTCOUNT} digests, ${DIGESTLISTTOREMOVECOUNT} to delete${NC}"

  # Do deletion or say nothing to do
  if [ "${DIGESTLISTTOREMOVECOUNT}" -gt "0" ]; then
    echo -e "${YELL}Removing ${DIGESTLISTTOREMOVECOUNT} digests${NC}"
    while IFS= read -r LINE; do
      LINE=$(echo $LINE|tr -d '\r')
        gcloud container images delete ${IMAGENAME}@${LINE} --force-delete-tags --quiet
    done <<< "${DIGESTLISTTOREMOVE}"
  else
    echo -e "${YELL}No digests to remove${NC}"
  fi
done <<< "${IMAGELIST}"

It’s a pretty basic bash script, but hopefully this can serve as a nice copy and paste starting point for people with the same issue as me.